mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of ssh://github.com/ArangoDB/ArangoDB into devel
This commit is contained in:
commit
300066f376
|
@ -32,12 +32,13 @@
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
|
#include "Basics/directories.h"
|
||||||
#include "Basics/StringUtils.h"
|
#include "Basics/StringUtils.h"
|
||||||
#include "Basics/Utf8Helper.h"
|
#include "Basics/Utf8Helper.h"
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#include "Basics/win-utils.h"
|
#include "Basics/win-utils.h"
|
||||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv()
|
#define FIX_ICU_ENV TRI_FixIcuDataEnv(BIN_DIRECTORY)
|
||||||
#else
|
#else
|
||||||
#define FIX_ICU_ENV
|
#define FIX_ICU_ENV
|
||||||
#endif
|
#endif
|
||||||
|
@ -74,7 +75,7 @@ static string hexedump (const string &s) {
|
||||||
struct StringUtilsSetup {
|
struct StringUtilsSetup {
|
||||||
StringUtilsSetup () {
|
StringUtilsSetup () {
|
||||||
FIX_ICU_ENV;
|
FIX_ICU_ENV;
|
||||||
if (!arangodb::basics::Utf8Helper::DefaultUtf8Helper.setCollatorLanguage("")) {
|
if (!arangodb::basics::Utf8Helper::DefaultUtf8Helper.setCollatorLanguage("", SBIN_DIRECTORY)) {
|
||||||
std::string msg =
|
std::string msg =
|
||||||
"cannot initialize ICU; please make sure ICU*dat is available; "
|
"cannot initialize ICU; please make sure ICU*dat is available; "
|
||||||
"the variable ICU_DATA='";
|
"the variable ICU_DATA='";
|
||||||
|
|
|
@ -31,11 +31,12 @@
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include "Basics/hashes.h"
|
#include "Basics/hashes.h"
|
||||||
|
#include "Basics/directories.h"
|
||||||
#include "Basics/Utf8Helper.h"
|
#include "Basics/Utf8Helper.h"
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#include "Basics/win-utils.h"
|
#include "Basics/win-utils.h"
|
||||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv()
|
#define FIX_ICU_ENV TRI_FixIcuDataEnv(SBIN_DIRECTORY)
|
||||||
#else
|
#else
|
||||||
#define FIX_ICU_ENV
|
#define FIX_ICU_ENV
|
||||||
#endif
|
#endif
|
||||||
|
@ -51,7 +52,7 @@
|
||||||
struct CHashesSetup {
|
struct CHashesSetup {
|
||||||
CHashesSetup () {
|
CHashesSetup () {
|
||||||
FIX_ICU_ENV;
|
FIX_ICU_ENV;
|
||||||
if (!arangodb::basics::Utf8Helper::DefaultUtf8Helper.setCollatorLanguage("")) {
|
if (!arangodb::basics::Utf8Helper::DefaultUtf8Helper.setCollatorLanguage("", SBIN_DIRECTORY)) {
|
||||||
std::string msg =
|
std::string msg =
|
||||||
"cannot initialize ICU; please make sure ICU*dat is available; "
|
"cannot initialize ICU; please make sure ICU*dat is available; "
|
||||||
"the variable ICU_DATA='";
|
"the variable ICU_DATA='";
|
||||||
|
|
|
@ -31,12 +31,13 @@
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include "Basics/json.h"
|
#include "Basics/json.h"
|
||||||
|
#include "Basics/directories.h"
|
||||||
#include "Basics/StringBuffer.h"
|
#include "Basics/StringBuffer.h"
|
||||||
#include "Basics/Utf8Helper.h"
|
#include "Basics/Utf8Helper.h"
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#include "Basics/win-utils.h"
|
#include "Basics/win-utils.h"
|
||||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv()
|
#define FIX_ICU_ENV TRI_FixIcuDataEnv(SBIN_DIRECTORY)
|
||||||
#else
|
#else
|
||||||
#define FIX_ICU_ENV
|
#define FIX_ICU_ENV
|
||||||
#endif
|
#endif
|
||||||
|
@ -58,7 +59,7 @@
|
||||||
struct CJsonSetup {
|
struct CJsonSetup {
|
||||||
CJsonSetup () {
|
CJsonSetup () {
|
||||||
FIX_ICU_ENV;
|
FIX_ICU_ENV;
|
||||||
if (!arangodb::basics::Utf8Helper::DefaultUtf8Helper.setCollatorLanguage("")) {
|
if (!arangodb::basics::Utf8Helper::DefaultUtf8Helper.setCollatorLanguage("", SBIN_DIRECTORY)) {
|
||||||
std::string msg =
|
std::string msg =
|
||||||
"cannot initialize ICU; please make sure ICU*dat is available; "
|
"cannot initialize ICU; please make sure ICU*dat is available; "
|
||||||
"the variable ICU_DATA='";
|
"the variable ICU_DATA='";
|
||||||
|
|
|
@ -32,10 +32,11 @@
|
||||||
|
|
||||||
#include "Basics/tri-strings.h"
|
#include "Basics/tri-strings.h"
|
||||||
#include "Basics/Utf8Helper.h"
|
#include "Basics/Utf8Helper.h"
|
||||||
|
#include "Basics/directories.h"
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#include "Basics/win-utils.h"
|
#include "Basics/win-utils.h"
|
||||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv()
|
#define FIX_ICU_ENV TRI_FixIcuDataEnv(SBIN_DIRECTORY)
|
||||||
#else
|
#else
|
||||||
#define FIX_ICU_ENV
|
#define FIX_ICU_ENV
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,7 +56,7 @@
|
||||||
struct CNormalizeStringTestSetup {
|
struct CNormalizeStringTestSetup {
|
||||||
CNormalizeStringTestSetup () {
|
CNormalizeStringTestSetup () {
|
||||||
FIX_ICU_ENV;
|
FIX_ICU_ENV;
|
||||||
if (!arangodb::basics::Utf8Helper::DefaultUtf8Helper.setCollatorLanguage("")) {
|
if (!arangodb::basics::Utf8Helper::DefaultUtf8Helper.setCollatorLanguage("", SBIN_DIRECTORY)) {
|
||||||
std::string msg =
|
std::string msg =
|
||||||
"cannot initialize ICU; please make sure ICU*dat is available; "
|
"cannot initialize ICU; please make sure ICU*dat is available; "
|
||||||
"the variable ICU_DATA='";
|
"the variable ICU_DATA='";
|
||||||
|
|
|
@ -33,10 +33,11 @@
|
||||||
|
|
||||||
#include "Basics/tri-strings.h"
|
#include "Basics/tri-strings.h"
|
||||||
#include "Basics/Utf8Helper.h"
|
#include "Basics/Utf8Helper.h"
|
||||||
|
#include "Basics/directories.h"
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#include "Basics/win-utils.h"
|
#include "Basics/win-utils.h"
|
||||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv()
|
#define FIX_ICU_ENV TRI_FixIcuDataEnv(SBIN_DIRECTORY)
|
||||||
#else
|
#else
|
||||||
#define FIX_ICU_ENV
|
#define FIX_ICU_ENV
|
||||||
#endif
|
#endif
|
||||||
|
@ -62,7 +63,7 @@
|
||||||
struct CStringUtf8Setup {
|
struct CStringUtf8Setup {
|
||||||
CStringUtf8Setup () {
|
CStringUtf8Setup () {
|
||||||
FIX_ICU_ENV;
|
FIX_ICU_ENV;
|
||||||
if (!arangodb::basics::Utf8Helper::DefaultUtf8Helper.setCollatorLanguage("")) {
|
if (!arangodb::basics::Utf8Helper::DefaultUtf8Helper.setCollatorLanguage("", SBIN_DIRECTORY)) {
|
||||||
std::string msg =
|
std::string msg =
|
||||||
"cannot initialize ICU; please make sure ICU*dat is available; "
|
"cannot initialize ICU; please make sure ICU*dat is available; "
|
||||||
"the variable ICU_DATA='";
|
"the variable ICU_DATA='";
|
||||||
|
|
|
@ -64,6 +64,82 @@ describe ArangoDB do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## create and using cursors, continuation
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
context "handling a cursor with continuation:" do
|
||||||
|
before do
|
||||||
|
@cn = "users"
|
||||||
|
ArangoDB.drop_collection(@cn)
|
||||||
|
@cid = ArangoDB.create_collection(@cn, false)
|
||||||
|
|
||||||
|
(0...2001).each{|i|
|
||||||
|
ArangoDB.post("/_api/document?collection=#{@cid}", :body => "{ \"_key\" : \"test#{i}\" }")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
ArangoDB.drop_collection(@cn)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates a cursor" do
|
||||||
|
cmd = api
|
||||||
|
body = "{ \"query\" : \"FOR u IN #{@cn} RETURN u\", \"count\" : true }"
|
||||||
|
doc = ArangoDB.log_post("#{prefix}-create-batchsize", cmd, :body => body)
|
||||||
|
|
||||||
|
doc.code.should eq(201)
|
||||||
|
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||||
|
doc.parsed_response['error'].should eq(false)
|
||||||
|
doc.parsed_response['code'].should eq(201)
|
||||||
|
doc.parsed_response['id'].should be_kind_of(String)
|
||||||
|
doc.parsed_response['id'].should match(@reId)
|
||||||
|
doc.parsed_response['hasMore'].should eq(true)
|
||||||
|
doc.parsed_response['count'].should eq(2001)
|
||||||
|
doc.parsed_response['result'].length.should eq(1000)
|
||||||
|
doc.parsed_response['cached'].should eq(false)
|
||||||
|
|
||||||
|
id = doc.parsed_response['id']
|
||||||
|
|
||||||
|
cmd = api + "/#{id}"
|
||||||
|
doc = ArangoDB.log_put("#{prefix}-create-batchsize", cmd)
|
||||||
|
|
||||||
|
doc.code.should eq(200)
|
||||||
|
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||||
|
doc.parsed_response['error'].should eq(false)
|
||||||
|
doc.parsed_response['code'].should eq(200)
|
||||||
|
doc.parsed_response['id'].should be_kind_of(String)
|
||||||
|
doc.parsed_response['id'].should match(@reId)
|
||||||
|
doc.parsed_response['id'].should eq(id)
|
||||||
|
doc.parsed_response['hasMore'].should eq(true)
|
||||||
|
doc.parsed_response['count'].should eq(2001)
|
||||||
|
doc.parsed_response['result'].length.should eq(1000)
|
||||||
|
doc.parsed_response['cached'].should eq(false)
|
||||||
|
|
||||||
|
cmd = api + "/#{id}"
|
||||||
|
doc = ArangoDB.log_put("#{prefix}-create-batchsize", cmd)
|
||||||
|
|
||||||
|
doc.code.should eq(200)
|
||||||
|
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||||
|
doc.parsed_response['error'].should eq(false)
|
||||||
|
doc.parsed_response['code'].should eq(200)
|
||||||
|
doc.parsed_response['id'].should be_nil
|
||||||
|
doc.parsed_response['hasMore'].should eq(false)
|
||||||
|
doc.parsed_response['count'].should eq(2001)
|
||||||
|
doc.parsed_response['result'].length.should eq(1)
|
||||||
|
doc.parsed_response['cached'].should eq(false)
|
||||||
|
|
||||||
|
cmd = api + "/#{id}"
|
||||||
|
doc = ArangoDB.log_put("#{prefix}-create-batchsize", cmd)
|
||||||
|
|
||||||
|
doc.code.should eq(404)
|
||||||
|
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||||
|
doc.parsed_response['error'].should eq(true)
|
||||||
|
doc.parsed_response['errorNum'].should eq(1600)
|
||||||
|
doc.parsed_response['code'].should eq(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## create and using cursors
|
## create and using cursors
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
|
@ -461,7 +461,8 @@ void RestCursorHandler::modifyCursor() {
|
||||||
builder.close();
|
builder.close();
|
||||||
|
|
||||||
_response->setContentType(rest::ContentType::JSON);
|
_response->setContentType(rest::ContentType::JSON);
|
||||||
generateResult(rest::ResponseCode::OK, builder.slice());
|
generateResult(rest::ResponseCode::OK, builder.slice(),
|
||||||
|
static_cast<VelocyPackCursor*>(cursor)->result()->context);
|
||||||
|
|
||||||
cursors->release(cursor);
|
cursors->release(cursor);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
|
@ -38,7 +38,7 @@ class RestUploadHandler : public RestVocbaseBaseHandler {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
char const* name() const override final { return "RestUploadHandler"; }
|
char const* name() const override final { return "RestUploadHandler"; }
|
||||||
RestHandler::status execute();
|
RestHandler::status execute() override;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief parses a multi-part request body and determines the boundaries of
|
/// @brief parses a multi-part request body and determines the boundaries of
|
||||||
|
|
|
@ -103,7 +103,7 @@ static int runServer(int argc, char** argv) {
|
||||||
std::string name = context.binaryName();
|
std::string name = context.binaryName();
|
||||||
|
|
||||||
auto options = std::make_shared<options::ProgramOptions>(
|
auto options = std::make_shared<options::ProgramOptions>(
|
||||||
argv[0], "Usage: " + name + " [<options>]", "For more information use:");
|
argv[0], "Usage: " + name + " [<options>]", "For more information use:", SBIN_DIRECTORY);
|
||||||
|
|
||||||
application_features::ApplicationServer server(options, SBIN_DIRECTORY);
|
application_features::ApplicationServer server(options, SBIN_DIRECTORY);
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ void VelocyPackCursor::dump(VPackBuilder& builder) {
|
||||||
|
|
||||||
VPackOptions const* oldOptions = builder.options;
|
VPackOptions const* oldOptions = builder.options;
|
||||||
|
|
||||||
builder.options = _result.context->getVPackOptions();
|
builder.options = _result.context->getVPackOptionsForDump();
|
||||||
|
|
||||||
builder.add("result", VPackValue(VPackValueType::Array));
|
builder.add("result", VPackValue(VPackValueType::Array));
|
||||||
for (size_t i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
|
|
@ -1332,6 +1332,18 @@ static void JS_SendChunk(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||||
TRI_V8_TRY_CATCH_END
|
TRI_V8_TRY_CATCH_END
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void JS_IsEnterprise(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||||
|
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
#ifndef USE_ENTERPRISE
|
||||||
|
TRI_V8_RETURN(v8::False(isolate));
|
||||||
|
#else
|
||||||
|
TRI_V8_RETURN(v8::True(isolate));
|
||||||
|
#endif
|
||||||
|
TRI_V8_TRY_CATCH_END
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief stores the V8 actions function inside the global variable
|
/// @brief stores the V8 actions function inside the global variable
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1364,6 +1376,11 @@ void TRI_InitV8Actions(v8::Isolate* isolate, v8::Handle<v8::Context> context) {
|
||||||
JS_RequestParts, true);
|
JS_RequestParts, true);
|
||||||
TRI_AddGlobalFunctionVocbase(
|
TRI_AddGlobalFunctionVocbase(
|
||||||
isolate, context, TRI_V8_ASCII_STRING("SYS_SEND_CHUNK"), JS_SendChunk);
|
isolate, context, TRI_V8_ASCII_STRING("SYS_SEND_CHUNK"), JS_SendChunk);
|
||||||
|
TRI_AddGlobalFunctionVocbase(
|
||||||
|
isolate, context,
|
||||||
|
TRI_V8_ASCII_STRING("SYS_IS_ENTERPRISE"),
|
||||||
|
JS_IsEnterprise);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -47,7 +47,7 @@ int main(int argc, char* argv[]) {
|
||||||
context.installHup();
|
context.installHup();
|
||||||
|
|
||||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||||
argv[0], "Usage: arangobench [<options>]", "For more information use:"));
|
argv[0], "Usage: arangobench [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||||
|
|
||||||
ApplicationServer server(options, BIN_DIRECTORY);
|
ApplicationServer server(options, BIN_DIRECTORY);
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ int main(int argc, char* argv[]) {
|
||||||
context.installHup();
|
context.installHup();
|
||||||
|
|
||||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||||
argv[0], "Usage: arangodump [<options>]", "For more information use:"));
|
argv[0], "Usage: arangodump [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||||
|
|
||||||
ApplicationServer server(options, BIN_DIRECTORY);
|
ApplicationServer server(options, BIN_DIRECTORY);
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ int main(int argc, char* argv[]) {
|
||||||
context.installHup();
|
context.installHup();
|
||||||
|
|
||||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||||
argv[0], "Usage: arangoimp [<options>]", "For more information use:"));
|
argv[0], "Usage: arangoimp [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||||
|
|
||||||
ApplicationServer server(options, BIN_DIRECTORY);
|
ApplicationServer server(options, BIN_DIRECTORY);
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ int main(int argc, char* argv[]) {
|
||||||
context.installHup();
|
context.installHup();
|
||||||
|
|
||||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||||
argv[0], "Usage: arangorestore [<options>]", "For more information use:"));
|
argv[0], "Usage: arangorestore [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||||
|
|
||||||
ApplicationServer server(options, BIN_DIRECTORY);
|
ApplicationServer server(options, BIN_DIRECTORY);
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ int main(int argc, char* argv[]) {
|
||||||
std::string name = context.binaryName();
|
std::string name = context.binaryName();
|
||||||
|
|
||||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||||
argv[0], "Usage: " + name + " [<options>]", "For more information use:"));
|
argv[0], "Usage: " + name + " [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||||
|
|
||||||
ApplicationServer server(options, BIN_DIRECTORY);
|
ApplicationServer server(options, BIN_DIRECTORY);
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ int main(int argc, char* argv[]) {
|
||||||
context.installHup();
|
context.installHup();
|
||||||
|
|
||||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||||
argv[0], "Usage: arangovpack [<options>]", "For more information use:"));
|
argv[0], "Usage: arangovpack [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||||
|
|
||||||
ApplicationServer server(options, BIN_DIRECTORY);
|
ApplicationServer server(options, BIN_DIRECTORY);
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ endif()
|
||||||
# Global macros ----------------------------------------------------------------
|
# Global macros ----------------------------------------------------------------
|
||||||
macro (generate_root_config name)
|
macro (generate_root_config name)
|
||||||
FILE(READ ${PROJECT_SOURCE_DIR}/etc/arangodb3/${name}.conf.in FileContent)
|
FILE(READ ${PROJECT_SOURCE_DIR}/etc/arangodb3/${name}.conf.in FileContent)
|
||||||
STRING(REPLACE "@PKGDATADIR@" "@ROOTDIR@/share/arangodb3"
|
STRING(REPLACE "@PKGDATADIR@" "@ROOTDIR@$/{CMAKE_INSTALL_DATAROOTDIR_ARANGO}"
|
||||||
FileContent "${FileContent}")
|
FileContent "${FileContent}")
|
||||||
STRING(REPLACE "@LOCALSTATEDIR@" "@ROOTDIR@/var"
|
STRING(REPLACE "@LOCALSTATEDIR@" "@ROOTDIR@/var"
|
||||||
FileContent "${FileContent}")
|
FileContent "${FileContent}")
|
||||||
|
|
|
@ -34,6 +34,12 @@ const cluster = require('@arangodb/cluster');
|
||||||
const Graph = require('@arangodb/general-graph');
|
const Graph = require('@arangodb/general-graph');
|
||||||
const createRouter = require('@arangodb/foxx/router');
|
const createRouter = require('@arangodb/foxx/router');
|
||||||
const actions = require('@arangodb/actions');
|
const actions = require('@arangodb/actions');
|
||||||
|
const isEnterprise = require('internal').isEnterprise();
|
||||||
|
|
||||||
|
let SmartGraph = {};
|
||||||
|
if (isEnterprise) {
|
||||||
|
SmartGraph = require('@arangodb/smart-graph');
|
||||||
|
}
|
||||||
|
|
||||||
const NOT_MODIFIED = statuses('not modified');
|
const NOT_MODIFIED = statuses('not modified');
|
||||||
const ACCEPTED = statuses('accepted');
|
const ACCEPTED = statuses('accepted');
|
||||||
|
@ -43,6 +49,24 @@ const OK = statuses('ok');
|
||||||
const router = createRouter();
|
const router = createRouter();
|
||||||
module.context.use(router);
|
module.context.use(router);
|
||||||
|
|
||||||
|
const loadGraph = (name) => {
|
||||||
|
try {
|
||||||
|
if (isEnterprise) {
|
||||||
|
return SmartGraph._graph(name);
|
||||||
|
} else {
|
||||||
|
return Graph._graph(name);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
||||||
|
throw Object.assign(
|
||||||
|
new httperr.NotFound(e.errorMessage),
|
||||||
|
{errorNum: e.errorNum, cause: e}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
router.use((req, res, next) => {
|
router.use((req, res, next) => {
|
||||||
try {
|
try {
|
||||||
next();
|
next();
|
||||||
|
@ -113,7 +137,8 @@ function setResponse (res, name, body, code) {
|
||||||
res.json({
|
res.json({
|
||||||
error: false,
|
error: false,
|
||||||
[name]: body,
|
[name]: body,
|
||||||
code});
|
code
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchVertexRevision (req, rev) {
|
function matchVertexRevision (req, rev) {
|
||||||
|
@ -197,29 +222,43 @@ router.post('/', function (req, res) {
|
||||||
const waitForSync = Boolean(req.queryParams.waitForSync);
|
const waitForSync = Boolean(req.queryParams.waitForSync);
|
||||||
let g;
|
let g;
|
||||||
try {
|
try {
|
||||||
g = Graph._create(
|
if (isEnterprise && req.body.isSmart === true) {
|
||||||
req.body.name,
|
const smartGraphAttribute = req.body.options.smartGraphAttribute;
|
||||||
req.body.edgeDefinitions,
|
const numberOfShards = req.body.options.numberOfShards;
|
||||||
req.body.orphanCollections,
|
g = SmartGraph._create(
|
||||||
{waitForSync}
|
req.body.name,
|
||||||
);
|
req.body.edgeDefinitions,
|
||||||
} catch (e) {
|
req.body.orphanCollections,
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_DUPLICATE.code) {
|
{waitForSync, numberOfShards, smartGraphAttribute}
|
||||||
throw Object.assign(
|
);
|
||||||
new httperr.Conflict(e.errorMessage),
|
} else {
|
||||||
{errorNum: e.errorNum, cause: e}
|
g = Graph._create(
|
||||||
|
req.body.name,
|
||||||
|
req.body.edgeDefinitions,
|
||||||
|
req.body.orphanCollections,
|
||||||
|
{waitForSync}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (e.isArangoError && [
|
} catch (e) {
|
||||||
errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code,
|
if (e.isArangoError) {
|
||||||
errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.code,
|
switch (e.errorNum) {
|
||||||
errors.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.code,
|
case errors.ERROR_BAD_PARAMETER.code:
|
||||||
errors.ERROR_GRAPH_COLLECTION_USED_IN_ORPHANS.code
|
case errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code:
|
||||||
].indexOf(e.errorNum) !== -1) {
|
case errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.code:
|
||||||
throw Object.assign(
|
case errors.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.code:
|
||||||
new httperr.BadRequest(e.errorMessage),
|
case errors.ERROR_GRAPH_COLLECTION_USED_IN_ORPHANS.code:
|
||||||
{errorNum: e.errorNum, cause: e}
|
throw Object.assign(
|
||||||
);
|
new httperr.BadRequest(e.errorMessage),
|
||||||
|
{errorNum: e.errorNum, cause: e}
|
||||||
|
);
|
||||||
|
|
||||||
|
case errors.ERROR_GRAPH_DUPLICATE.code:
|
||||||
|
throw Object.assign(
|
||||||
|
new httperr.Conflict(e.errorMessage),
|
||||||
|
{errorNum: e.errorNum, cause: e}
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
@ -228,8 +267,13 @@ router.post('/', function (req, res) {
|
||||||
.queryParam('waitForSync', waitForSyncFlag)
|
.queryParam('waitForSync', waitForSyncFlag)
|
||||||
.body(joi.object({
|
.body(joi.object({
|
||||||
name: joi.string().required(),
|
name: joi.string().required(),
|
||||||
edgeDefinitions: joi.any().optional(),
|
edgeDefinitions: joi.array().optional(),
|
||||||
orphanCollections: joi.any().optional()
|
orphanCollections: joi.array().optional(),
|
||||||
|
isSmart: joi.boolean().optional(),
|
||||||
|
options: joi.object({
|
||||||
|
smartGraphAttribute: joi.string().required(),
|
||||||
|
numberOfShards: joi.number().integer().greater(0).required()
|
||||||
|
}).optional()
|
||||||
}).required(), 'The required information for a graph')
|
}).required(), 'The required information for a graph')
|
||||||
.error('bad request', 'Graph creation error.')
|
.error('bad request', 'Graph creation error.')
|
||||||
.error('conflict', 'Graph creation error.')
|
.error('conflict', 'Graph creation error.')
|
||||||
|
@ -238,18 +282,7 @@ router.post('/', function (req, res) {
|
||||||
|
|
||||||
router.get('/:graph', function (req, res) {
|
router.get('/:graph', function (req, res) {
|
||||||
const name = req.pathParams.graph;
|
const name = req.pathParams.graph;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
setResponse(res, 'graph', graphForClient(g), OK);
|
setResponse(res, 'graph', graphForClient(g), OK);
|
||||||
})
|
})
|
||||||
.pathParam('graph', graphName)
|
.pathParam('graph', graphName)
|
||||||
|
@ -292,18 +325,7 @@ router.delete('/:graph', function (req, res) {
|
||||||
router.get('/:graph/vertex', function (req, res) {
|
router.get('/:graph/vertex', function (req, res) {
|
||||||
const name = req.pathParams.graph;
|
const name = req.pathParams.graph;
|
||||||
const excludeOrphans = req.queryParams.excludeOrphans;
|
const excludeOrphans = req.queryParams.excludeOrphans;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
const mapFunc = (
|
const mapFunc = (
|
||||||
req.pathParams.collectionObjects
|
req.pathParams.collectionObjects
|
||||||
? (c) => collectionRepresentation(c, false, false, false)
|
? (c) => collectionRepresentation(c, false, false, false)
|
||||||
|
@ -318,36 +340,25 @@ router.get('/:graph/vertex', function (req, res) {
|
||||||
|
|
||||||
router.post('/:graph/vertex', function (req, res) {
|
router.post('/:graph/vertex', function (req, res) {
|
||||||
const name = req.pathParams.graph;
|
const name = req.pathParams.graph;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
g._addVertexCollection(req.body.collection);
|
g._addVertexCollection(req.body.collection);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code) {
|
if (e.isArangoError) {
|
||||||
throw Object.assign(
|
switch (e.errorNum) {
|
||||||
new httperr.NotFound(e.errorMessage),
|
case errors.ERROR_BAD_PARAMETER.code:
|
||||||
{errorNum: e.errorNum, cause: e}
|
case errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.code:
|
||||||
);
|
case errors.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.code:
|
||||||
}
|
case errors.ERROR_GRAPH_COLLECTION_USED_IN_ORPHANS.code:
|
||||||
if (e.isArangoError && [
|
throw Object.assign(
|
||||||
errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.code,
|
new httperr.BadRequest(e.errorMessage),
|
||||||
errors.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.code,
|
{errorNum: e.errorNum, cause: e});
|
||||||
errors.ERROR_GRAPH_COLLECTION_USED_IN_ORPHANS.code
|
|
||||||
].indexOf(e.errorNum) !== -1) {
|
case errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code:
|
||||||
throw Object.assign(
|
throw Object.assign(
|
||||||
new httperr.BadRequest(e.errorMessage),
|
new httperr.NotFound(e.errorMessage),
|
||||||
{errorNum: e.errorNum, cause: e}
|
{errorNum: e.errorNum, cause: e});
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
@ -366,18 +377,7 @@ router.delete('/:graph/vertex/:collection', function (req, res) {
|
||||||
const dropCollection = Boolean(req.queryParams.dropCollection);
|
const dropCollection = Boolean(req.queryParams.dropCollection);
|
||||||
const name = req.pathParams.graph;
|
const name = req.pathParams.graph;
|
||||||
const defName = req.pathParams.collection;
|
const defName = req.pathParams.collection;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
g._removeVertexCollection(defName, dropCollection);
|
g._removeVertexCollection(defName, dropCollection);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -407,18 +407,7 @@ router.delete('/:graph/vertex/:collection', function (req, res) {
|
||||||
|
|
||||||
router.get('/:graph/edge', function (req, res) {
|
router.get('/:graph/edge', function (req, res) {
|
||||||
const name = req.pathParams.graph;
|
const name = req.pathParams.graph;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
setResponse(res, 'collections', _.map(g._edgeCollections(), (c) => c.name()).sort(), OK);
|
setResponse(res, 'collections', _.map(g._edgeCollections(), (c) => c.name()).sort(), OK);
|
||||||
})
|
})
|
||||||
.pathParam('graph', graphName)
|
.pathParam('graph', graphName)
|
||||||
|
@ -428,30 +417,20 @@ router.get('/:graph/edge', function (req, res) {
|
||||||
|
|
||||||
router.post('/:graph/edge', function (req, res) {
|
router.post('/:graph/edge', function (req, res) {
|
||||||
const name = req.pathParams.graph;
|
const name = req.pathParams.graph;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
g._extendEdgeDefinitions(req.body);
|
g._extendEdgeDefinitions(req.body);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.isArangoError && [
|
if (e.isArangoError) {
|
||||||
errors.ERROR_GRAPH_COLLECTION_MULTI_USE.code,
|
switch (e.errorNum) {
|
||||||
errors.ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS.code,
|
case errors.ERROR_GRAPH_COLLECTION_MULTI_USE.code:
|
||||||
errors.ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION.code
|
case errors.ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS.code:
|
||||||
].indexOf(e.errorNum) !== -1) {
|
case errors.ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION.code:
|
||||||
throw Object.assign(
|
throw Object.assign(
|
||||||
new httperr.BadRequest(e.errorMessage),
|
new httperr.BadRequest(e.errorMessage),
|
||||||
{errorNum: e.errorNum, cause: e}
|
{errorNum: e.errorNum, cause: e}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
@ -471,18 +450,7 @@ router.post('/:graph/edge', function (req, res) {
|
||||||
router.put('/:graph/edge/:definition', function (req, res) {
|
router.put('/:graph/edge/:definition', function (req, res) {
|
||||||
const name = req.pathParams.graph;
|
const name = req.pathParams.graph;
|
||||||
const defName = req.pathParams.definition;
|
const defName = req.pathParams.definition;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
if (defName !== req.body.collection) {
|
if (defName !== req.body.collection) {
|
||||||
throw Object.assign(
|
throw Object.assign(
|
||||||
new httperr.NotFound(errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.message),
|
new httperr.NotFound(errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.message),
|
||||||
|
@ -492,14 +460,15 @@ router.put('/:graph/edge/:definition', function (req, res) {
|
||||||
try {
|
try {
|
||||||
g._editEdgeDefinitions(req.body);
|
g._editEdgeDefinitions(req.body);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.isArangoError && [
|
if (e.isArangoError) {
|
||||||
errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.code,
|
switch (e.errorNum) {
|
||||||
errors.ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION.code
|
case errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.code:
|
||||||
].indexOf(e.errorNum) !== -1) {
|
case errors.ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION.code:
|
||||||
throw Object.assign(
|
throw Object.assign(
|
||||||
new httperr.BadRequest(e.errorMessage),
|
new httperr.BadRequest(e.errorMessage),
|
||||||
{errorNum: e.errorNum, cause: e}
|
{errorNum: e.errorNum, cause: e}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
@ -522,15 +491,12 @@ router.delete('/:graph/edge/:definition', function (req, res) {
|
||||||
const dropCollection = Boolean(req.queryParams.dropCollection);
|
const dropCollection = Boolean(req.queryParams.dropCollection);
|
||||||
const name = req.pathParams.graph;
|
const name = req.pathParams.graph;
|
||||||
const defName = req.pathParams.definition;
|
const defName = req.pathParams.definition;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
try {
|
||||||
g = Graph._graph(name);
|
|
||||||
g._deleteEdgeDefinition(defName, dropCollection);
|
g._deleteEdgeDefinition(defName, dropCollection);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.isArangoError && [
|
if (e.isArangoError &&
|
||||||
errors.ERROR_GRAPH_NOT_FOUND.code,
|
errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.code === e.errorNum) {
|
||||||
errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.code
|
|
||||||
].indexOf(e.errorNum) !== -1) {
|
|
||||||
throw Object.assign(
|
throw Object.assign(
|
||||||
new httperr.NotFound(e.errorMessage),
|
new httperr.NotFound(e.errorMessage),
|
||||||
{errorNum: e.errorNum, cause: e}
|
{errorNum: e.errorNum, cause: e}
|
||||||
|
@ -557,18 +523,7 @@ router.post('/:graph/vertex/:collection', function (req, res) {
|
||||||
const waitForSync = Boolean(req.queryParams.waitForSync);
|
const waitForSync = Boolean(req.queryParams.waitForSync);
|
||||||
const name = req.pathParams.graph;
|
const name = req.pathParams.graph;
|
||||||
const collection = req.pathParams.collection;
|
const collection = req.pathParams.collection;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
checkCollection(g, collection);
|
checkCollection(g, collection);
|
||||||
let meta;
|
let meta;
|
||||||
try {
|
try {
|
||||||
|
@ -598,18 +553,7 @@ router.get('/:graph/vertex/:collection/:key', function (req, res) {
|
||||||
const collection = req.pathParams.collection;
|
const collection = req.pathParams.collection;
|
||||||
const key = req.pathParams.key;
|
const key = req.pathParams.key;
|
||||||
const id = `${collection}/${key}`;
|
const id = `${collection}/${key}`;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
checkCollection(g, collection);
|
checkCollection(g, collection);
|
||||||
let doc;
|
let doc;
|
||||||
try {
|
try {
|
||||||
|
@ -639,18 +583,7 @@ router.put('/:graph/vertex/:collection/:key', function (req, res) {
|
||||||
const collection = req.pathParams.collection;
|
const collection = req.pathParams.collection;
|
||||||
const key = req.pathParams.key;
|
const key = req.pathParams.key;
|
||||||
const id = `${collection}/${key}`;
|
const id = `${collection}/${key}`;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
checkCollection(g, collection);
|
checkCollection(g, collection);
|
||||||
let doc;
|
let doc;
|
||||||
try {
|
try {
|
||||||
|
@ -688,18 +621,7 @@ router.patch('/:graph/vertex/:collection/:key', function (req, res) {
|
||||||
const collection = req.pathParams.collection;
|
const collection = req.pathParams.collection;
|
||||||
const key = req.pathParams.key;
|
const key = req.pathParams.key;
|
||||||
const id = `${collection}/${key}`;
|
const id = `${collection}/${key}`;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
checkCollection(g, collection);
|
checkCollection(g, collection);
|
||||||
let doc;
|
let doc;
|
||||||
try {
|
try {
|
||||||
|
@ -737,18 +659,7 @@ router.delete('/:graph/vertex/:collection/:key', function (req, res) {
|
||||||
const collection = req.pathParams.collection;
|
const collection = req.pathParams.collection;
|
||||||
const key = req.pathParams.key;
|
const key = req.pathParams.key;
|
||||||
const id = `${collection}/${key}`;
|
const id = `${collection}/${key}`;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
checkCollection(g, collection);
|
checkCollection(g, collection);
|
||||||
let doc;
|
let doc;
|
||||||
try {
|
try {
|
||||||
|
@ -799,23 +710,12 @@ router.post('/:graph/edge/:collection', function (req, res) {
|
||||||
{errorNum: errors.ERROR_GRAPH_INVALID_EDGE.code}
|
{errorNum: errors.ERROR_GRAPH_INVALID_EDGE.code}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
checkCollection(g, collection);
|
checkCollection(g, collection);
|
||||||
let meta;
|
let meta;
|
||||||
try {
|
try {
|
||||||
meta = g[collection].save(req.body);
|
meta = g[collection].save(req.body);
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
if (e.errorNum !== errors.ERROR_GRAPH_INVALID_EDGE.code) {
|
if (e.errorNum !== errors.ERROR_GRAPH_INVALID_EDGE.code) {
|
||||||
throw Object.assign(
|
throw Object.assign(
|
||||||
new httperr.Gone(e.errorMessage),
|
new httperr.Gone(e.errorMessage),
|
||||||
|
@ -839,18 +739,7 @@ router.get('/:graph/edge/:collection/:key', function (req, res) {
|
||||||
const collection = req.pathParams.collection;
|
const collection = req.pathParams.collection;
|
||||||
const key = req.pathParams.key;
|
const key = req.pathParams.key;
|
||||||
const id = `${collection}/${key}`;
|
const id = `${collection}/${key}`;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
checkCollection(g, collection);
|
checkCollection(g, collection);
|
||||||
let doc;
|
let doc;
|
||||||
try {
|
try {
|
||||||
|
@ -880,18 +769,7 @@ router.put('/:graph/edge/:collection/:key', function (req, res) {
|
||||||
const collection = req.pathParams.collection;
|
const collection = req.pathParams.collection;
|
||||||
const key = req.pathParams.key;
|
const key = req.pathParams.key;
|
||||||
const id = `${collection}/${key}`;
|
const id = `${collection}/${key}`;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
checkCollection(g, collection);
|
checkCollection(g, collection);
|
||||||
let doc;
|
let doc;
|
||||||
try {
|
try {
|
||||||
|
@ -929,18 +807,7 @@ router.patch('/:graph/edge/:collection/:key', function (req, res) {
|
||||||
const collection = req.pathParams.collection;
|
const collection = req.pathParams.collection;
|
||||||
const key = req.pathParams.key;
|
const key = req.pathParams.key;
|
||||||
const id = `${collection}/${key}`;
|
const id = `${collection}/${key}`;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
checkCollection(g, collection);
|
checkCollection(g, collection);
|
||||||
let doc;
|
let doc;
|
||||||
try {
|
try {
|
||||||
|
@ -978,18 +845,7 @@ router.delete('/:graph/edge/:collection/:key', function (req, res) {
|
||||||
const collection = req.pathParams.collection;
|
const collection = req.pathParams.collection;
|
||||||
const key = req.pathParams.key;
|
const key = req.pathParams.key;
|
||||||
const id = `${collection}/${key}`;
|
const id = `${collection}/${key}`;
|
||||||
let g;
|
const g = loadGraph(name);
|
||||||
try {
|
|
||||||
g = Graph._graph(name);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_NOT_FOUND.code) {
|
|
||||||
throw Object.assign(
|
|
||||||
new httperr.NotFound(e.errorMessage),
|
|
||||||
{errorNum: e.errorNum, cause: e}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
checkCollection(g, collection);
|
checkCollection(g, collection);
|
||||||
let doc;
|
let doc;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -2124,11 +2124,11 @@ exports._renameCollection = function (oldName, newName) {
|
||||||
// //////////////////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports._list = function () {
|
exports._list = function () {
|
||||||
return db._query(`FOR x IN _graphs FILTER !x.isSmart RETURN x._key`).toArray();
|
return db._query(`FOR x IN _graphs RETURN x._key`).toArray();
|
||||||
};
|
};
|
||||||
|
|
||||||
exports._listObjects = function () {
|
exports._listObjects = function () {
|
||||||
return db._query(`FOR x IN _graphs FILTER !x.isSmart RETURN x`).toArray();
|
return db._query(`FOR x IN _graphs RETURN x`).toArray();
|
||||||
};
|
};
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -355,4 +355,14 @@
|
||||||
exports.DEFAULT_REPLICATION_FACTOR_SYSTEM = global.SYS_DEFAULT_REPLICATION_FACTOR_SYSTEM;
|
exports.DEFAULT_REPLICATION_FACTOR_SYSTEM = global.SYS_DEFAULT_REPLICATION_FACTOR_SYSTEM;
|
||||||
delete global.SYS_DEFAULT_REPLICATION_FACTOR_SYSTEM;
|
delete global.SYS_DEFAULT_REPLICATION_FACTOR_SYSTEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////////////////
|
||||||
|
// / @brief returns if we are in enterprise version or not
|
||||||
|
// //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
if (global.SYS_IS_ENTERPRISE) {
|
||||||
|
exports.isEnterprise = global.SYS_IS_ENTERPRISE;
|
||||||
|
delete global.SYS_IS_ENTERPRISE;
|
||||||
|
}
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -216,6 +216,7 @@ class ApplicationServer {
|
||||||
_progressReports.emplace_back(reporter);
|
_progressReports.emplace_back(reporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* getBinaryPath() { return _binaryPath;}
|
||||||
private:
|
private:
|
||||||
// look up a feature and return a pointer to it. may be nullptr
|
// look up a feature and return a pointer to it. may be nullptr
|
||||||
static ApplicationFeature* lookupFeature(std::string const&);
|
static ApplicationFeature* lookupFeature(std::string const&);
|
||||||
|
|
|
@ -33,7 +33,8 @@ using namespace arangodb::options;
|
||||||
|
|
||||||
LanguageFeature::LanguageFeature(
|
LanguageFeature::LanguageFeature(
|
||||||
application_features::ApplicationServer* server)
|
application_features::ApplicationServer* server)
|
||||||
: ApplicationFeature(server, "Language") {
|
: ApplicationFeature(server, "Language"),
|
||||||
|
_binaryPath(server->getBinaryPath()){
|
||||||
setOptional(false);
|
setOptional(false);
|
||||||
requiresElevatedPrivileges(false);
|
requiresElevatedPrivileges(false);
|
||||||
startsAfter("Logger");
|
startsAfter("Logger");
|
||||||
|
@ -46,7 +47,7 @@ void LanguageFeature::collectOptions(
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageFeature::prepare() {
|
void LanguageFeature::prepare() {
|
||||||
if (!Utf8Helper::DefaultUtf8Helper.setCollatorLanguage(_language)) {
|
if (!Utf8Helper::DefaultUtf8Helper.setCollatorLanguage(_language, _binaryPath)) {
|
||||||
std::string msg =
|
std::string msg =
|
||||||
"cannot initialize ICU; please make sure ICU*dat is available; "
|
"cannot initialize ICU; please make sure ICU*dat is available; "
|
||||||
"the variable ICU_DATA='";
|
"the variable ICU_DATA='";
|
||||||
|
|
|
@ -37,6 +37,7 @@ class LanguageFeature final : public application_features::ApplicationFeature {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _language;
|
std::string _language;
|
||||||
|
const char* _binaryPath;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "Utf8Helper.h"
|
#include "Utf8Helper.h"
|
||||||
#include "Logger/Logger.h"
|
#include "Logger/Logger.h"
|
||||||
#include "Basics/tri-strings.h"
|
#include "Basics/tri-strings.h"
|
||||||
|
#include "Basics/directories.h"
|
||||||
#include "unicode/normalizer2.h"
|
#include "unicode/normalizer2.h"
|
||||||
#include "unicode/brkiter.h"
|
#include "unicode/brkiter.h"
|
||||||
#include "unicode/ucasemap.h"
|
#include "unicode/ucasemap.h"
|
||||||
|
@ -38,13 +39,14 @@
|
||||||
|
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
|
|
||||||
Utf8Helper Utf8Helper::DefaultUtf8Helper;
|
Utf8Helper Utf8Helper::DefaultUtf8Helper(SBIN_DIRECTORY);
|
||||||
|
|
||||||
Utf8Helper::Utf8Helper(std::string const& lang) : _coll(nullptr) {
|
Utf8Helper::Utf8Helper(std::string const& lang, char const* binaryPath)
|
||||||
setCollatorLanguage(lang);
|
: _coll(nullptr) {
|
||||||
|
setCollatorLanguage(lang, binaryPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utf8Helper::Utf8Helper() : Utf8Helper("") {}
|
Utf8Helper::Utf8Helper(char const* binaryPath) : Utf8Helper("", binaryPath) {}
|
||||||
|
|
||||||
Utf8Helper::~Utf8Helper() {
|
Utf8Helper::~Utf8Helper() {
|
||||||
if (_coll) {
|
if (_coll) {
|
||||||
|
@ -127,9 +129,9 @@ int Utf8Helper::compareUtf16(uint16_t const* left, size_t leftLength,
|
||||||
(const UChar*)right, (int32_t)rightLength);
|
(const UChar*)right, (int32_t)rightLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Utf8Helper::setCollatorLanguage(std::string const& lang) {
|
bool Utf8Helper::setCollatorLanguage(std::string const& lang, char const* binaryPath) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
TRI_FixIcuDataEnv();
|
TRI_FixIcuDataEnv(binaryPath);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
|
|
|
@ -52,9 +52,9 @@ class Utf8Helper {
|
||||||
/// This parameter can instead be an ICU style C locale (e.g. "en_US")
|
/// This parameter can instead be an ICU style C locale (e.g. "en_US")
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
explicit Utf8Helper(std::string const& lang);
|
Utf8Helper(std::string const& lang, char const* binaryPath);
|
||||||
|
|
||||||
Utf8Helper();
|
explicit Utf8Helper(char const* binaryPath);
|
||||||
|
|
||||||
~Utf8Helper();
|
~Utf8Helper();
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ class Utf8Helper {
|
||||||
/// This parameter can instead be an ICU style C locale (e.g. "en_US")
|
/// This parameter can instead be an ICU style C locale (e.g. "en_US")
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool setCollatorLanguage(std::string const& lang);
|
bool setCollatorLanguage(std::string const& lang, char const* binaryPath);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief get collator language
|
/// @brief get collator language
|
||||||
|
|
|
@ -2326,7 +2326,7 @@ void TRI_SetUserTempPath(std::string const& path) { TempPath = path; }
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
|
|
||||||
std::string TRI_LocateInstallDirectory(const char *binaryPath) {
|
std::string TRI_LocateInstallDirectory(const char *binaryPath) {
|
||||||
std::string thisPath = TRI_LocateBinaryPath(null);
|
std::string thisPath = TRI_LocateBinaryPath(nullptr);
|
||||||
return TRI_GetInstallRoot(thisPath, binaryPath) +
|
return TRI_GetInstallRoot(thisPath, binaryPath) +
|
||||||
std::string(1, TRI_DIR_SEPARATOR_CHAR);
|
std::string(1, TRI_DIR_SEPARATOR_CHAR);
|
||||||
}
|
}
|
||||||
|
|
|
@ -336,7 +336,7 @@ bool TRI_CopySymlink(std::string const& srcItem, std::string const& dstItem,
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
std::string TRI_LocateInstallDirectory();
|
std::string TRI_LocateInstallDirectory(const char* binaryPath);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -312,12 +312,12 @@ int TRI_OPEN_WIN32(char const* filename, int openFlags) {
|
||||||
/// @brief fixes the ICU_DATA environment path
|
/// @brief fixes the ICU_DATA environment path
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_FixIcuDataEnv() {
|
void TRI_FixIcuDataEnv(const char* binaryPath) {
|
||||||
if (getenv("ICU_DATA") != nullptr) {
|
if (getenv("ICU_DATA") != nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string p = TRI_LocateInstallDirectory();
|
std::string p = TRI_LocateInstallDirectory(binaryPath);
|
||||||
|
|
||||||
if (!p.empty()) {
|
if (!p.empty()) {
|
||||||
std::string e = "ICU_DATA=" + p + ICU_DESTINATION_DIRECTORY;
|
std::string e = "ICU_DATA=" + p + ICU_DESTINATION_DIRECTORY;
|
||||||
|
|
|
@ -93,7 +93,7 @@ void TRI_usleep(unsigned long);
|
||||||
/// @brief fixes the ICU_DATA environment path
|
/// @brief fixes the ICU_DATA environment path
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_FixIcuDataEnv();
|
void TRI_FixIcuDataEnv(const char* binaryPath);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief converts a Windows error to a *nix system error
|
/// @brief converts a Windows error to a *nix system error
|
||||||
|
|
|
@ -102,6 +102,7 @@ class ProgramOptions {
|
||||||
|
|
||||||
ProgramOptions(char const* progname, std::string const& usage,
|
ProgramOptions(char const* progname, std::string const& usage,
|
||||||
std::string const& more,
|
std::string const& more,
|
||||||
|
const char *binaryPath,
|
||||||
TerminalWidthFuncType const& terminalWidth = TRI_ColumnsWidth,
|
TerminalWidthFuncType const& terminalWidth = TRI_ColumnsWidth,
|
||||||
SimilarityFuncType const& similarity = TRI_Levenshtein)
|
SimilarityFuncType const& similarity = TRI_Levenshtein)
|
||||||
: _progname(progname),
|
: _progname(progname),
|
||||||
|
@ -111,7 +112,8 @@ class ProgramOptions {
|
||||||
_similarity(similarity),
|
_similarity(similarity),
|
||||||
_processingResult(),
|
_processingResult(),
|
||||||
_sealed(false),
|
_sealed(false),
|
||||||
_overrideOptions(false) {
|
_overrideOptions(false),
|
||||||
|
_binaryPath(binaryPath){
|
||||||
// find progname wildcard in string
|
// find progname wildcard in string
|
||||||
size_t const pos = _usage.find(ARANGODB_PROGRAM_OPTIONS_PROGNAME);
|
size_t const pos = _usage.find(ARANGODB_PROGRAM_OPTIONS_PROGNAME);
|
||||||
|
|
||||||
|
@ -126,7 +128,7 @@ class ProgramOptions {
|
||||||
|
|
||||||
// sets a value translator
|
// sets a value translator
|
||||||
void setTranslator(
|
void setTranslator(
|
||||||
std::function<std::string(std::string const&)> translator) {
|
std::function<std::string(std::string const&, char const*)> translator) {
|
||||||
_translator = translator;
|
_translator = translator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,7 +359,7 @@ class ProgramOptions {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string result = option.parameter->set(_translator(value));
|
std::string result = option.parameter->set(_translator(value, _binaryPath));
|
||||||
|
|
||||||
if (!result.empty()) {
|
if (!result.empty()) {
|
||||||
// parameter validation failed
|
// parameter validation failed
|
||||||
|
@ -621,7 +623,9 @@ class ProgramOptions {
|
||||||
// allow or disallow overriding already set options
|
// allow or disallow overriding already set options
|
||||||
bool _overrideOptions;
|
bool _overrideOptions;
|
||||||
// translate input values
|
// translate input values
|
||||||
std::function<std::string(std::string const&)> _translator;
|
std::function<std::string(std::string const&, char const*)> _translator;
|
||||||
|
// directory of this binary
|
||||||
|
char const* _binaryPath;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "Translator.h"
|
#include "Translator.h"
|
||||||
#include "Basics/tri-strings.h"
|
#include "Basics/tri-strings.h"
|
||||||
#include "Basics/files.h"
|
#include "Basics/files.h"
|
||||||
std::string arangodb::options::EnvironmentTranslator(std::string const& value) {
|
std::string arangodb::options::EnvironmentTranslator(std::string const& value, const char *binaryPath) {
|
||||||
if (value.empty()) {
|
if (value.empty()) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ std::string arangodb::options::EnvironmentTranslator(std::string const& value) {
|
||||||
if (v == nullptr) {
|
if (v == nullptr) {
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
if (TRI_EqualString(k.c_str(), "ROOTDIR")) {
|
if (TRI_EqualString(k.c_str(), "ROOTDIR")) {
|
||||||
vv = TRI_LocateInstallDirectory();
|
vv = TRI_LocateInstallDirectory(binaryPath);
|
||||||
|
|
||||||
if (! vv.empty()) {
|
if (! vv.empty()) {
|
||||||
char c = *(vv.rbegin());
|
char c = *(vv.rbegin());
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
namespace options {
|
namespace options {
|
||||||
std::string EnvironmentTranslator(std::string const& value);
|
std::string EnvironmentTranslator(std::string const& value, const char* binaryPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue