mirror of https://gitee.com/bigwinds/arangodb
Gharial rewrite in C++ (#5631)
* Built a C++ skeleton REST handler for gharial, with fallback to the JS handler * Moved aql::Graph to graph::Graph * Added complete edge definitions to Graph Also: - some cleanup - used forward-declarations in headers - use Graph in graph rest handler * Handle graph lookup failures according to the test suite * Added GET vertex * Bugfixes in ResultT - Added missing #include - Fixed move semantics * Move central code of readVertex to GraphOperations * ResultT fixes and complements * Implemented a graph cache * Added and used graph cache to the rest handler * Added GET edge * Added DELETE edge * Extracted some code * Added PATCH and PUT for both edge and vertex * Moved update/replace transaction code to GraphOperations * Added stub routes for POST and a TODO note * Added a test checking that deleting a vertex removes all incident edges as well * Added a test checking that deleting a vertex does not remove edges in non-graph collections * fixed compiler warnings and errors * Began work on DELETE vertex For this, added a V8Context to allow for AQL queries to use subtransactions * Continued work on DELETE vertex (still WIP) * prep for graph post routes * fixed removeVertex operation (aql) * added post vertex and post edge gharial routes * wasSynchronoues flag changed * gharial post c++ handler, naming conventions * added gharial tests * temporary disabled cache (because not completed), added graph property read functions * added c++ gharial list vertex collections * added c++ gharial graph config * added c++ gharial list graphs * added graph manager class * first implementation of create graph in c++, WIP * changed error messages * added etag to create graph api, still multiple edge definition check missing * finished POST /_api/gharial/<graph> * WIP - DELETE /_api/gharial/<graphName> * added DELETE /_api/gharial/<graphName> validation, still missing correct response * gharial delete * fixed delete gharial lock * finished DELETE /_api/gharial/<graphName> * added routes for graph based vertices and edge definitions * improved delete route * added add new edge definition to existing graph * patch edge definition in a graph, still <WIP> * finished edit edge definition route * code changes due to devel code changes * added remove edge definition route * added vertex delete function * added todo note regarding one drop collection issue * add oprhan collection to graph route implemented * Added a test * Updated a comment * Several minor changes * Minor changes during review * Changes during review * Changes during review * Bugfix: orphans may be null or omitted * Bugfix: resolve externals * minor code changes * seperated graph class to independent component classes * seperated graph class to independent component classes * removed log output * fixed create collection behaviour in a cluster environment * fixed enterprise graphs behaviour in c++ gharial api * removed log output * formatting * improved error handling, fixed a linux compile bug * more result refactoring * more result type cleanup * fixed wrongly defined test * result handling * error handling * more refactoring * Bugfix: avoid race condition in cluster when creating collections * updated graph documentation * added graph related static strings * static strings, new method to create options for gharial created collections * Some minor cleanup * more use of static strings * minor code changes, review * added missing parseint * removed gharial foxx, added js common module, added v8 general graph module * correct use of virtual method * more v8, js general graph, broken state * more v8 graph functions * fixed editEdgeDefinition, added drop function * fixed drop behaviour * added _list, _exists * added c++ rename graph collections, added v8 + graph module function * Added a regression test * added graph._deleteEdgeDefinition, v8, server * more v8g * added _removeVertexCollection * added _extendEditDefinitions * todo, need to add a helper sort method for a local defined relation * fixed test * fixed lots of tests, added more client functions, _addVertexCollection on client module is still broken * added more client graph functions, all tests green * more client functions * add del edge def route * Fix use after move * Minor changes in client general-graph.js module * Make a copy before sorting (don't touch the argument) * Minor changes and some additional asserts in graph tests * Consistently set parameter defaults * Renamed static strings * Remove superfluous function * Made comment more verbose * Minor changes in general-graph-common.js * Added missing template arguments * Fixed community build * Cleanup in editEdgeDefinition * Regression test & bugfix: comparison of edge definitions didn' order from and to * Fixed errors introduced by merge * Minor changes in v8-general-graph.cpp * Fixed test failure due to wrong error code in CE * added missing id field * Added permission checks for graph._create * Removed assertion that is no longer valid * Moved removeGraph from GraphOperations to GraphManager * Allow C++ implementation of graph._drop to handle smart graphs * Flush js client db cache after creating/dropping collections via the general graph module * Added _deleteEdgeDefinition to the general graph client module * WIP: Added permission checks for drop graph * Fixed permission checks for drop graph * Added permission checks for other graph operations * Bugfix: assert edge definitions are returned in order * Some cleanup * Removed unused method * Minor improvements in GraphManager * Fixed a type in general-graph common module * Most useful fix of all times ever: Do not auto cast from bool to int and alternate error/noerror by this * Added the initial keyword to StaticStrings * Added a new error code, used whenever a user tries to inject a documentcollection as a relation into the graph, which is invalid * Some GraphManager/Ops/Graph cleanup. Less Slice parsing, more usage of GraphObjects * Test edgeDefinitions in graphs with a defined ordering * GraphClass Layout cleanup * Do not test error messages, use codes instead * Recreated backwards compatibility of Graph Creation Permission errors * Changed error-code if edgedefinition is used twice * Added a StaticString for the GraphName * Renamed graphToVpack => graphForClient * Partly fixed graph-api test to work with better error messages. Still red: The edgeDefinitions are now sorted, the test is supposed to sort his own list, but appearently does not do so. Under investigation * Added a new error code that rejects injection of differently sharded smart collection into smartgraph. Should be more helpful to our users * graph createCollectionOptions now require an open object to be cross-called from enterprise. Made enterprise switch for creation of graph more elegant. * Updated graphs.cpp * Massive refactoring. Made Factories for graphs to make SmartGraph much more transparent. Also reduced amount of multiple implementations of the same stuff. Killed vocbase/graphs use GraphManager instead. Removed usage of GraphCache, was not completely implemented anyway and only partially used, which is bad at the moment. Option for later improvement never the less * Adapted JS code to now really use c++ variants. ALso included 3 Classes: Graph, SmartGraph and GraphModule. * Fixed undefined behaviour in Remove Vertex. Fixed smartgraph sharding if one collection already exists. * Removed DEBUG output * Removed DEBUG logs * Removed dead code * Fixed Graph EdgeDefinition test, they now have a different ordering. * Added a test when adding a vertexCollection that it is actually valid in the graph * Client Graph API now correctly sends `orphanCollections` and not `orphans` * Let GraphOperations modify the graph in-place. It should now properly handle edgeDefinitions. * Added initial cid StaticString * Included the vocbase in fromPersistence creation of Graphs. Only required to enhance 3.3 SmartGraphs on the fly. * Fixed internal error message * Fixed compiler isses originiated from merging * Removed unused imports * Regenerated generated file
This commit is contained in:
parent
4aa174399c
commit
de4f5587ae
|
@ -384,7 +384,7 @@ graph with different *from* and/or *to* collections an error is thrown.
|
|||
|
||||
Modify an relation definition
|
||||
|
||||
`graph_module._editEdgeDefinition(edgeDefinition)`
|
||||
`graph_module._editEdgeDefinitions(edgeDefinition)`
|
||||
|
||||
Edits one relation definition of a graph. The edge definition used as argument will
|
||||
replace the existing edge definition of the graph which has the same collection.
|
||||
|
|
|
@ -23,6 +23,10 @@ The *_key* attribute of the vertex.
|
|||
@RESTQUERYPARAM{waitForSync,boolean,optional}
|
||||
Define if the request should wait until synced to disk.
|
||||
|
||||
@RESTQUERYPARAM{returnOld,boolean,optional}
|
||||
Define if a presentation of the deleted document should
|
||||
be returned within the response object.
|
||||
|
||||
@RESTHEADERPARAMETERS
|
||||
|
||||
@RESTHEADERPARAM{if-match,string,optional}
|
||||
|
|
|
@ -26,6 +26,16 @@ Define if the request should wait until synced to disk.
|
|||
@RESTQUERYPARAM{keepNull,boolean,optional}
|
||||
Define if values set to null should be stored. By default the key is not removed from the document.
|
||||
|
||||
@RESTQUERYPARAM{returnOld,boolean,optional}
|
||||
Define if a presentation of the deleted document should
|
||||
be returned within the response object.
|
||||
|
||||
@RESTQUERYPARAM{returnNew,boolean,optional}
|
||||
Define if a presentation of the newly create
|
||||
|
||||
@RESTQUERYPARAM{keepNull,boolean,optional}
|
||||
Define if values set to null should be stored. By default the key is not removed from the document.
|
||||
|
||||
@RESTALLBODYPARAM{updateAttributes,object,required}
|
||||
The body has to be a JSON object containing the attributes to be updated.
|
||||
|
||||
|
|
|
@ -22,6 +22,16 @@ The *_key* attribute of the vertex.
|
|||
@RESTQUERYPARAM{waitForSync,boolean,optional}
|
||||
Define if the request should wait until synced to disk.
|
||||
|
||||
@RESTQUERYPARAM{keepNull,boolean,optional}
|
||||
Define if values set to null should be stored. By default the key is not removed from the document.
|
||||
|
||||
@RESTQUERYPARAM{returnOld,boolean,optional}
|
||||
Define if a presentation of the deleted document should
|
||||
be returned within the response object.
|
||||
|
||||
@RESTQUERYPARAM{returnNew,boolean,optional}
|
||||
Define if a presentation of the newly create
|
||||
|
||||
@RESTHEADERPARAMETERS
|
||||
|
||||
@RESTHEADERPARAM{if-match,string,optional}
|
||||
|
|
|
@ -23,6 +23,14 @@ The *_key* attribute of the vertex.
|
|||
@RESTQUERYPARAM{waitForSync,boolean,optional}
|
||||
Define if the request should wait until synced to disk.
|
||||
|
||||
@RESTQUERYPARAM{returnOld,boolean,optional}
|
||||
Define if a presentation of the deleted document should
|
||||
be returned within the response object.
|
||||
|
||||
@RESTQUERYPARAM{returnNew,boolean,optional}
|
||||
Define if a presentation of the newly created document
|
||||
should be returned within the response object.
|
||||
|
||||
@RESTHEADERPARAMETERS
|
||||
|
||||
@RESTHEADERPARAM{if-match,string,optional}
|
||||
|
|
|
@ -26,6 +26,13 @@ Define if the request should wait until synced to disk.
|
|||
@RESTQUERYPARAM{keepNull,boolean,optional}
|
||||
Define if values set to null should be stored. By default the key is not removed from the document.
|
||||
|
||||
@RESTQUERYPARAM{returnOld,boolean,optional}
|
||||
Define if a presentation of the deleted document should
|
||||
be returned within the response object.
|
||||
|
||||
@RESTQUERYPARAM{returnNew,boolean,optional}
|
||||
Define if a presentation of the newly create
|
||||
|
||||
@RESTHEADERPARAMETERS
|
||||
|
||||
@RESTHEADERPARAM{if-match,string,optional}
|
||||
|
|
|
@ -23,6 +23,16 @@ The *_key* attribute of the vertex.
|
|||
@RESTQUERYPARAM{waitForSync,boolean,optional}
|
||||
Define if the request should wait until synced to disk.
|
||||
|
||||
@RESTQUERYPARAM{keepNull,boolean,optional}
|
||||
Define if values set to null should be stored. By default the key is not removed from the document.
|
||||
|
||||
@RESTQUERYPARAM{returnOld,boolean,optional}
|
||||
Define if a presentation of the deleted document should
|
||||
be returned within the response object.
|
||||
|
||||
@RESTQUERYPARAM{returnNew,boolean,optional}
|
||||
Define if a presentation of the newly create
|
||||
|
||||
@RESTHEADERPARAMETERS
|
||||
|
||||
@RESTHEADERPARAM{if-match,string,optional}
|
||||
|
|
|
@ -159,7 +159,6 @@ describe ArangoDB do
|
|||
return doc
|
||||
end
|
||||
|
||||
|
||||
def create_edge (waitForSync, graph_name, collection, from, to, body, options = {})
|
||||
cmd = edge_endpoint(graph_name, collection)
|
||||
cmd = cmd + "?waitForSync=#{waitForSync}"
|
||||
|
@ -282,6 +281,7 @@ describe ArangoDB do
|
|||
second_def = { "collection" => bought_collection, "from" => [user_collection], "to" => [product_collection] }
|
||||
doc = additional_edge_definition(sync, graph_name, second_def )
|
||||
edge_definition.push(second_def)
|
||||
edge_definition = edge_definition.sort_by { |d| [ -d["collection"] ] }
|
||||
|
||||
doc.code.should eq(202)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
|
@ -848,7 +848,10 @@ describe ArangoDB do
|
|||
it "can not replace a non existing edge" do
|
||||
key = "unknownKey"
|
||||
|
||||
doc = replace_edge( sync, graph_name, friend_collection, key, {"type2" => "divorced"})
|
||||
# Added _from and _to, because otherwise a 400 might conceal the
|
||||
# 404. Another test checking that missing _from or _to trigger
|
||||
# errors was added to api-gharial-spec.js.
|
||||
doc = replace_edge( sync, graph_name, friend_collection, key, {"type2" => "divorced", "_from" => "1", "_to" => "2"})
|
||||
doc.code.should eq(404)
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['errorMessage'].should include("document not found")
|
||||
|
@ -1169,11 +1172,18 @@ describe ArangoDB do
|
|||
doc.parsed_response['code'].should eq(404)
|
||||
end
|
||||
|
||||
def check400 (doc)
|
||||
doc.code.should eq(400)
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(400)
|
||||
puts doc.parsed_response['errorMessage']
|
||||
doc.parsed_response['errorMessage'].should include("edge attribute missing or invalid")
|
||||
end
|
||||
|
||||
def check404Edge (doc)
|
||||
check404(doc)
|
||||
doc.parsed_response['errorNum'].should eq(1930)
|
||||
doc.parsed_response['errorMessage'].should eq("edge collection not used in graph")
|
||||
|
||||
end
|
||||
|
||||
def check404Vertex (doc)
|
||||
|
@ -1181,10 +1191,23 @@ describe ArangoDB do
|
|||
doc.parsed_response['errorNum'].should eq(1926)
|
||||
end
|
||||
|
||||
def check400VertexUnused (doc)
|
||||
doc.parsed_response['errorNum'].should eq(1928)
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(400)
|
||||
puts doc.parsed_response['errorMessage']
|
||||
doc.parsed_response['errorMessage'].should include("not in orphan collection")
|
||||
end
|
||||
|
||||
def check404CRUD (doc)
|
||||
check404(doc)
|
||||
doc.parsed_response['errorNum'].should eq(1203)
|
||||
doc.parsed_response['errorMessage'].should eq("collection or view not found")
|
||||
doc.parsed_response['errorMessage'].should start_with("collection or view not found: ")
|
||||
end
|
||||
|
||||
def check400CRUD (doc)
|
||||
check400(doc)
|
||||
doc.parsed_response['errorNum'].should eq(1233)
|
||||
end
|
||||
|
||||
it "change edge definition" do
|
||||
|
@ -1197,7 +1220,8 @@ describe ArangoDB do
|
|||
end
|
||||
|
||||
it "delete vertex collection" do
|
||||
check404Vertex(delete_vertex_collection( sync, graph_name, unknown_name))
|
||||
# this checks if a not used vertex collection can be removed of a graph
|
||||
check400VertexUnused(delete_vertex_collection( sync, graph_name, unknown_name))
|
||||
end
|
||||
|
||||
it "create vertex" do
|
||||
|
@ -1208,6 +1232,8 @@ describe ArangoDB do
|
|||
check404CRUD(get_vertex(graph_name, unknown_name, unknown_name))
|
||||
end
|
||||
|
||||
# TODO add tests where the edge/vertex collection is not part of the graph, but
|
||||
# the given key exists!
|
||||
it "update vertex" do
|
||||
check404CRUD(update_vertex( sync, graph_name, unknown_name, unknown_name, {}))
|
||||
end
|
||||
|
@ -1221,7 +1247,7 @@ describe ArangoDB do
|
|||
end
|
||||
|
||||
it "create edge" do
|
||||
check404CRUD(create_edge( sync, graph_name, unknown_name, unknown_name, unknown_name, {}))
|
||||
check400CRUD(create_edge( sync, graph_name, unknown_name, unknown_name, unknown_name, {}))
|
||||
end
|
||||
|
||||
it "get edge" do
|
||||
|
@ -1277,7 +1303,10 @@ describe ArangoDB do
|
|||
end
|
||||
|
||||
it "replace edge" do
|
||||
check404(replace_edge( sync, graph_name, friend_collection, unknown_name, {}))
|
||||
# Added _from and _to, because otherwise a 400 might conceal the
|
||||
# 404. Another test checking that missing _from or _to trigger
|
||||
# errors was added to api-gharial-spec.js.
|
||||
check404(replace_edge( sync, graph_name, friend_collection, unknown_name, {"_from" => "1", "_to" => "2"}))
|
||||
end
|
||||
|
||||
it "delete edge" do
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/tri-strings.h"
|
||||
#include "Cluster/ClusterInfo.h"
|
||||
#include "Graph/Graph.h"
|
||||
#include "Transaction/Helpers.h"
|
||||
#include "Utils/CollectionNameResolver.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "Aql/Query.h"
|
||||
#include "Cluster/ServerState.h"
|
||||
#include "Graph/BaseOptions.h"
|
||||
#include "Graph/Graph.h"
|
||||
#include "Utils/CollectionNameResolver.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
|
||||
|
|
|
@ -32,12 +32,11 @@ namespace arangodb {
|
|||
|
||||
namespace graph {
|
||||
struct BaseOptions;
|
||||
class Graph;
|
||||
}
|
||||
|
||||
namespace aql {
|
||||
|
||||
class Graph;
|
||||
|
||||
// @brief This is a pure virtual super-class for all AQL graph operations
|
||||
// It does the generally required:
|
||||
// * graph info parsing
|
||||
|
@ -145,7 +144,7 @@ class GraphNode : public ExecutionNode {
|
|||
Variable const* _edgeOutVariable;
|
||||
|
||||
/// @brief our graph...
|
||||
Graph const* _graphObj;
|
||||
graph::Graph const* _graphObj;
|
||||
|
||||
/// @brief Temporary pseudo variable for the currently traversed object.
|
||||
Variable const* _tmpObjVariable;
|
||||
|
|
|
@ -21,20 +21,17 @@
|
|||
/// @author Michael Hackstein
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <velocypack/Iterator.h>
|
||||
|
||||
#include "Graphs.h"
|
||||
#include "Aql/AstNode.h"
|
||||
#include "Basics/StaticStrings.h"
|
||||
#include "Basics/VelocyPackHelper.h"
|
||||
|
||||
#include <velocypack/Iterator.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
#include "Graph/Graph.h"
|
||||
|
||||
using namespace arangodb::basics;
|
||||
using namespace arangodb::aql;
|
||||
|
||||
char const* Graph::_attrEdgeDefs = "edgeDefinitions";
|
||||
char const* Graph::_attrOrphans = "orphanCollections";
|
||||
|
||||
EdgeConditionBuilder::EdgeConditionBuilder(AstNode* modCondition)
|
||||
: _fromCondition(nullptr),
|
||||
_toCondition(nullptr),
|
||||
|
@ -161,83 +158,3 @@ void EdgeConditionBuilderContainer::setVertexId(std::string const& id) {
|
|||
_compareNode->setStringValue(id.c_str(), id.length());
|
||||
}
|
||||
|
||||
void Graph::insertVertexCollections(VPackSlice& arr) {
|
||||
TRI_ASSERT(arr.isArray());
|
||||
for (auto const& c : VPackArrayIterator(arr)) {
|
||||
TRI_ASSERT(c.isString());
|
||||
addVertexCollection(c.copyString());
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> const& Graph::vertexCollections() const {
|
||||
return _vertexColls;
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> const& Graph::edgeCollections() const {
|
||||
return _edgeColls;
|
||||
}
|
||||
|
||||
void Graph::addEdgeCollection(std::string const& name) {
|
||||
_edgeColls.insert(name);
|
||||
}
|
||||
|
||||
void Graph::addVertexCollection(std::string const& name) {
|
||||
_vertexColls.insert(name);
|
||||
}
|
||||
|
||||
void Graph::toVelocyPack(VPackBuilder& builder) const {
|
||||
VPackObjectBuilder guard(&builder);
|
||||
|
||||
if (!_vertexColls.empty()) {
|
||||
builder.add(VPackValue("vertexCollectionNames"));
|
||||
VPackArrayBuilder guard2(&builder);
|
||||
for (auto const& cn : _vertexColls) {
|
||||
builder.add(VPackValue(cn));
|
||||
}
|
||||
}
|
||||
|
||||
if (!_edgeColls.empty()) {
|
||||
builder.add(VPackValue("edgeCollectionNames"));
|
||||
VPackArrayBuilder guard2(&builder);
|
||||
for (auto const& cn : _edgeColls) {
|
||||
builder.add(VPackValue(cn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Graph::Graph(VPackSlice const& slice) : _vertexColls(), _edgeColls() {
|
||||
if (slice.hasKey(_attrEdgeDefs)) {
|
||||
auto edgeDefs = slice.get(_attrEdgeDefs);
|
||||
|
||||
for (auto const& def : VPackArrayIterator(edgeDefs)) {
|
||||
TRI_ASSERT(def.isObject());
|
||||
try {
|
||||
std::string eCol = arangodb::basics::VelocyPackHelper::getStringValue(
|
||||
def, "collection", "");
|
||||
addEdgeCollection(eCol);
|
||||
} catch (...) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_GRAPH_INVALID_GRAPH, "didn't find 'collection' in the graph definition");
|
||||
}
|
||||
// TODO what if graph is not in a valid format any more
|
||||
try {
|
||||
VPackSlice tmp = def.get("from");
|
||||
insertVertexCollections(tmp);
|
||||
} catch (...) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_GRAPH_INVALID_GRAPH, "didn't find from-collection in the graph definition");
|
||||
}
|
||||
try {
|
||||
VPackSlice tmp = def.get("to");
|
||||
insertVertexCollections(tmp);
|
||||
} catch (...) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_GRAPH_INVALID_GRAPH, "didn't find to-collection in the graph definition");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (slice.hasKey(_attrOrphans)) {
|
||||
auto orphans = slice.get(_attrOrphans);
|
||||
insertVertexCollections(orphans);
|
||||
}
|
||||
}
|
||||
|
||||
void Graph::enhanceEngineInfo(VPackBuilder&) const {
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#ifndef ARANGOD_AQL_GRAPHS_H
|
||||
#define ARANGOD_AQL_GRAPHS_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Aql/VariableGenerator.h"
|
||||
#include "Basics/Common.h"
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
|
@ -141,51 +141,6 @@ class EdgeConditionBuilderContainer final : public EdgeConditionBuilder {
|
|||
VariableGenerator _varGen;
|
||||
};
|
||||
|
||||
class Graph {
|
||||
public:
|
||||
explicit Graph(arangodb::velocypack::Slice const&);
|
||||
|
||||
virtual ~Graph() {}
|
||||
|
||||
private:
|
||||
/// @brief the cids of all vertexCollections
|
||||
std::unordered_set<std::string> _vertexColls;
|
||||
|
||||
/// @brief the cids of all edgeCollections
|
||||
std::unordered_set<std::string> _edgeColls;
|
||||
|
||||
/// @brief Graph collection edge definition attribute name
|
||||
static char const* _attrEdgeDefs;
|
||||
|
||||
/// @brief Graph collection orphan list arribute name
|
||||
static char const* _attrOrphans;
|
||||
|
||||
public:
|
||||
/// @brief Graph collection name
|
||||
static std::string const _graphs;
|
||||
|
||||
/// @brief Add Collections to the object
|
||||
void insertVertexCollections(arangodb::velocypack::Slice& arr);
|
||||
|
||||
public:
|
||||
/// @brief get the cids of all vertexCollections
|
||||
std::unordered_set<std::string> const& vertexCollections() const;
|
||||
|
||||
/// @brief get the cids of all edgeCollections
|
||||
std::unordered_set<std::string> const& edgeCollections() const;
|
||||
|
||||
/// @brief Add an edge collection to this graphs definition
|
||||
void addEdgeCollection(std::string const&);
|
||||
|
||||
/// @brief Add a vertex collection to this graphs definition
|
||||
void addVertexCollection(std::string const&);
|
||||
|
||||
/// @brief return a VelocyPack representation of the graph
|
||||
void toVelocyPack(arangodb::velocypack::Builder&) const;
|
||||
|
||||
virtual void enhanceEngineInfo(arangodb::velocypack::Builder&) const;
|
||||
};
|
||||
|
||||
} // namespace aql
|
||||
} // namespace arangodb
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#include "Basics/fasthash.h"
|
||||
#include "Cluster/ServerState.h"
|
||||
#include "GeneralServer/AuthenticationFeature.h"
|
||||
#include "Graph/Graph.h"
|
||||
#include "Graph/GraphManager.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "RestServer/AqlFeature.h"
|
||||
#include "StorageEngine/TransactionState.h"
|
||||
|
@ -49,12 +51,9 @@
|
|||
#include "V8/v8-conv.h"
|
||||
#include "V8/v8-vpack.h"
|
||||
#include "V8Server/V8DealerFeature.h"
|
||||
#include "VocBase/Graphs.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
||||
#include <velocypack/Builder.h>
|
||||
#include <velocypack/Iterator.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
|
||||
#ifndef USE_PLAN_CACHE
|
||||
#undef USE_PLAN_CACHE
|
||||
|
@ -1444,24 +1443,24 @@ std::shared_ptr<transaction::Context> Query::createTransactionContext() {
|
|||
|
||||
/// @brief look up a graph either from our cache list or from the _graphs
|
||||
/// collection
|
||||
Graph const* Query::lookupGraphByName(std::string const& name) {
|
||||
graph::Graph const* Query::lookupGraphByName(std::string const& name) {
|
||||
auto it = _graphs.find(name);
|
||||
|
||||
if (it == _graphs.end()) {
|
||||
std::unique_ptr<arangodb::aql::Graph> g(
|
||||
arangodb::lookupGraphByName(createTransactionContext(), name));
|
||||
|
||||
if (g == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto result = _graphs.emplace(name, std::move(g));
|
||||
TRI_ASSERT(result.second);
|
||||
it = result.first;
|
||||
if (it != _graphs.end()) {
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
TRI_ASSERT((*it).second != nullptr);
|
||||
return (*it).second.get();
|
||||
graph::GraphManager graphManager{_vocbase, _contextOwnedByExterior};
|
||||
|
||||
auto g = graphManager.lookupGraphByName(name);
|
||||
|
||||
if (g.fail()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto graph = g.get().get();
|
||||
_graphs.emplace(name, std::move(g.get()));
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
/// @brief returns the next query id
|
||||
|
|
|
@ -58,6 +58,10 @@ namespace velocypack {
|
|||
class Builder;
|
||||
}
|
||||
|
||||
namespace graph {
|
||||
class Graph;
|
||||
}
|
||||
|
||||
namespace aql {
|
||||
|
||||
struct AstNode;
|
||||
|
@ -280,7 +284,7 @@ class Query {
|
|||
std::string getStateString() const;
|
||||
|
||||
/// @brief look up a graph in the _graphs collection
|
||||
Graph const* lookupGraphByName(std::string const& name);
|
||||
graph::Graph const* lookupGraphByName(std::string const& name);
|
||||
|
||||
/// @brief return the bind parameters as passed by the user
|
||||
std::shared_ptr<arangodb::velocypack::Builder> bindParameters() const {
|
||||
|
@ -355,7 +359,7 @@ class Query {
|
|||
V8Context* _context;
|
||||
|
||||
/// @brief graphs used in query, identified by name
|
||||
std::unordered_map<std::string, std::unique_ptr<Graph>> _graphs;
|
||||
std::unordered_map<std::string, std::unique_ptr<graph::Graph>> _graphs;
|
||||
|
||||
/// @brief the actual query string
|
||||
QueryString _queryString;
|
||||
|
|
|
@ -556,7 +556,7 @@ auth::Level auth::User::collectionAuthLevel(std::string const& dbname,
|
|||
return auth::Level::NONE; // invalid collection names
|
||||
}
|
||||
// we must have got a non-empty collection name when we get here
|
||||
TRI_ASSERT(cname[0] < '0' || cname[0] > '9');
|
||||
TRI_ASSERT(!isdigit(cname[0]));
|
||||
|
||||
bool isSystem = cname[0] == '_';
|
||||
if (isSystem) {
|
||||
|
|
|
@ -738,8 +738,9 @@ auth::Level auth::UserManager::collectionAuthLevel(std::string const& user,
|
|||
}
|
||||
|
||||
auth::Level level;
|
||||
if (coll[0] >= '0' && coll[0] <= '9') {
|
||||
std::string tmpColl = DatabaseFeature::DATABASE->translateCollectionName(dbname, coll);
|
||||
if (isdigit(coll[0])) {
|
||||
std::string tmpColl =
|
||||
DatabaseFeature::DATABASE->translateCollectionName(dbname, coll);
|
||||
level = it->second.collectionAuthLevel(dbname, tmpColl);
|
||||
} else {
|
||||
level = it->second.collectionAuthLevel(dbname, coll);
|
||||
|
|
|
@ -323,6 +323,9 @@ SET(ARANGOD_SOURCES
|
|||
Graph/ConstantWeightShortestPathFinder.cpp
|
||||
Graph/ClusterTraverserCache.cpp
|
||||
Graph/EdgeCollectionInfo.cpp
|
||||
Graph/Graph.cpp
|
||||
Graph/GraphManager.cpp
|
||||
Graph/GraphOperations.cpp
|
||||
Graph/NeighborsEnumerator.cpp
|
||||
Graph/PathEnumerator.cpp
|
||||
Graph/ShortestPathOptions.cpp
|
||||
|
@ -404,6 +407,7 @@ SET(ARANGOD_SOURCES
|
|||
RestHandler/RestEndpointHandler.cpp
|
||||
RestHandler/RestEngineHandler.cpp
|
||||
RestHandler/RestExplainHandler.cpp
|
||||
RestHandler/RestGraphHandler.cpp
|
||||
RestHandler/RestImportHandler.cpp
|
||||
RestHandler/RestIndexHandler.cpp
|
||||
RestHandler/RestJobHandler.cpp
|
||||
|
@ -507,6 +511,7 @@ SET(ARANGOD_SOURCES
|
|||
V8Server/v8-vocbase.cpp
|
||||
V8Server/v8-voccursor.cpp
|
||||
V8Server/v8-vocindex.cpp
|
||||
V8Server/v8-general-graph.cpp
|
||||
VocBase/Methods/AqlUserFunctions.cpp
|
||||
VocBase/Methods/Collections.cpp
|
||||
VocBase/Methods/Databases.cpp
|
||||
|
@ -516,7 +521,6 @@ SET(ARANGOD_SOURCES
|
|||
VocBase/Methods/Upgrade.cpp
|
||||
VocBase/Methods/UpgradeTasks.cpp
|
||||
VocBase/Methods/Version.cpp
|
||||
VocBase/Graphs.cpp
|
||||
VocBase/KeyGenerator.cpp
|
||||
VocBase/LogicalCollection.cpp
|
||||
VocBase/LogicalDataSource.cpp
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <boost/optional.hpp>
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/Result.h"
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
|
@ -57,7 +58,13 @@ namespace arangodb {
|
|||
template <typename T>
|
||||
class ResultT : public arangodb::Result {
|
||||
public:
|
||||
ResultT static success(T val) { return ResultT(val, TRI_ERROR_NO_ERROR); }
|
||||
ResultT static success(T const& val) {
|
||||
return ResultT(val, TRI_ERROR_NO_ERROR);
|
||||
}
|
||||
|
||||
ResultT static success(T&& val) {
|
||||
return ResultT(std::move(val), TRI_ERROR_NO_ERROR);
|
||||
}
|
||||
|
||||
ResultT static error(int errorNumber) {
|
||||
return ResultT(boost::none, errorNumber);
|
||||
|
@ -67,17 +74,23 @@ class ResultT : public arangodb::Result {
|
|||
return ResultT(boost::none, errorNumber, errorMessage);
|
||||
}
|
||||
|
||||
// This is not explicit on purpose
|
||||
// NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
// These are not explicit on purpose
|
||||
ResultT(Result const& other) : Result(other) {
|
||||
// .ok() is not allowed here, as _val should be expected to be initialized
|
||||
// iff .ok() is true.
|
||||
TRI_ASSERT(other.fail());
|
||||
}
|
||||
|
||||
// This is not explicit on purpose
|
||||
// NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
ResultT(T&& val) : ResultT(std::forward<T>(val), TRI_ERROR_NO_ERROR) {}
|
||||
ResultT(Result&& other) : Result(std::move(other)) {
|
||||
// .ok() is not allowed here, as _val should be expected to be initialized
|
||||
// iff .ok() is true.
|
||||
TRI_ASSERT(other.fail());
|
||||
}
|
||||
|
||||
// These are not explicit on purpose
|
||||
ResultT(T&& val) : ResultT(std::move(val), TRI_ERROR_NO_ERROR) {}
|
||||
|
||||
ResultT(T const& val) : ResultT(val, TRI_ERROR_NO_ERROR) {}
|
||||
|
||||
ResultT() = delete;
|
||||
|
||||
|
@ -91,6 +104,8 @@ class ResultT : public arangodb::Result {
|
|||
return *this;
|
||||
}
|
||||
|
||||
Result copy_result() const { return *this; }
|
||||
|
||||
// These would be very convenient, but also make it very easy to accidentally
|
||||
// use the value of an error-result. So don't add them.
|
||||
//
|
||||
|
@ -139,11 +154,20 @@ class ResultT : public arangodb::Result {
|
|||
boost::optional<T> _val;
|
||||
|
||||
ResultT(boost::optional<T>&& val_, int errorNumber)
|
||||
: Result(errorNumber), _val(val_) {}
|
||||
: Result(errorNumber), _val(std::move(val_)) {}
|
||||
|
||||
ResultT(boost::optional<T>&& val_, int errorNumber,
|
||||
std::string const& errorMessage)
|
||||
: Result(errorNumber, errorMessage), _val(val_) {}
|
||||
: Result(errorNumber, errorMessage),
|
||||
_val(val_) {}
|
||||
|
||||
ResultT(boost::optional<T>const& val_, int errorNumber)
|
||||
: Result(errorNumber), _val(std::move(val_)) {}
|
||||
|
||||
ResultT(boost::optional<T>const& val_, int errorNumber,
|
||||
std::string const& errorMessage)
|
||||
: Result(errorNumber, errorMessage),
|
||||
_val(val_) {}
|
||||
};
|
||||
|
||||
} // namespace arangodb
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "GeneralServer/AuthenticationFeature.h"
|
||||
#include "GeneralServer/GeneralServer.h"
|
||||
#include "GeneralServer/RestHandlerFactory.h"
|
||||
#include "Graph/Graph.h"
|
||||
#include "InternalRestHandler/InternalRestTraverserHandler.h"
|
||||
#include "ProgramOptions/Parameters.h"
|
||||
#include "ProgramOptions/ProgramOptions.h"
|
||||
|
@ -60,6 +61,7 @@
|
|||
#include "RestHandler/RestEndpointHandler.h"
|
||||
#include "RestHandler/RestEngineHandler.h"
|
||||
#include "RestHandler/RestExplainHandler.h"
|
||||
#include "RestHandler/RestGraphHandler.h"
|
||||
#include "RestHandler/RestHandlerCreator.h"
|
||||
#include "RestHandler/RestImportHandler.h"
|
||||
#include "RestHandler/RestIndexHandler.h"
|
||||
|
@ -68,9 +70,9 @@
|
|||
#include "RestHandler/RestPregelHandler.h"
|
||||
#include "RestHandler/RestQueryCacheHandler.h"
|
||||
#include "RestHandler/RestQueryHandler.h"
|
||||
#include "RestHandler/RestRepairHandler.h"
|
||||
#include "RestHandler/RestShutdownHandler.h"
|
||||
#include "RestHandler/RestSimpleHandler.h"
|
||||
#include "RestHandler/RestRepairHandler.h"
|
||||
#include "RestHandler/RestSimpleQueryHandler.h"
|
||||
#include "RestHandler/RestStatusHandler.h"
|
||||
#include "RestHandler/RestTasksHandler.h"
|
||||
|
@ -335,6 +337,10 @@ void GeneralServerFeature::defineHandlers() {
|
|||
RestVocbaseBaseHandler::EDGES_PATH,
|
||||
RestHandlerCreator<RestEdgesHandler>::createNoData);
|
||||
|
||||
_handlerFactory->addPrefixHandler(
|
||||
RestVocbaseBaseHandler::GHARIAL_PATH,
|
||||
RestHandlerCreator<RestGraphHandler>::createNoData);
|
||||
|
||||
_handlerFactory->addPrefixHandler(
|
||||
RestVocbaseBaseHandler::ENDPOINT_PATH,
|
||||
RestHandlerCreator<RestEndpointHandler>::createNoData);
|
||||
|
|
|
@ -84,7 +84,7 @@ class GeneralServerFeature final
|
|||
|
||||
return GENERAL_SERVER->_accessControlAllowOrigins;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static GeneralServerFeature* GENERAL_SERVER;
|
||||
|
||||
|
@ -98,7 +98,7 @@ class GeneralServerFeature final
|
|||
void start() override final;
|
||||
void stop() override final;
|
||||
void unprepare() override final;
|
||||
|
||||
|
||||
private:
|
||||
double _keepAliveTimeout = 300.0;
|
||||
bool _allowMethodOverride;
|
||||
|
@ -118,7 +118,9 @@ class GeneralServerFeature final
|
|||
private:
|
||||
std::unique_ptr<rest::RestHandlerFactory> _handlerFactory;
|
||||
std::unique_ptr<rest::AsyncJobManager> _jobManager;
|
||||
std::unique_ptr<std::pair<aql::QueryRegistry*, traverser::TraverserEngineRegistry*>> _combinedRegistries;
|
||||
std::unique_ptr<
|
||||
std::pair<aql::QueryRegistry*, traverser::TraverserEngineRegistry*>>
|
||||
_combinedRegistries;
|
||||
std::vector<rest::GeneralServer*> _servers;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace arangodb {
|
|||
class GeneralRequest;
|
||||
class RequestStatistics;
|
||||
|
||||
enum class RestStatus { DONE, WAITING, FAIL};
|
||||
enum class RestStatus { DONE, WAITING, FAIL };
|
||||
|
||||
namespace rest {
|
||||
class RestHandler : public std::enable_shared_from_this<RestHandler> {
|
||||
|
|
|
@ -0,0 +1,534 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Tobias Gödderz
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Graph.h"
|
||||
|
||||
#include <velocypack/Buffer.h>
|
||||
#include <velocypack/Collection.h>
|
||||
#include <velocypack/Iterator.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
#include <array>
|
||||
#include <boost/variant.hpp>
|
||||
#include <utility>
|
||||
|
||||
#include "Aql/AstNode.h"
|
||||
#include "Aql/Graphs.h"
|
||||
#include "Aql/Query.h"
|
||||
#include "Basics/ReadLocker.h"
|
||||
#include "Basics/StaticStrings.h"
|
||||
#include "Basics/VelocyPackHelper.h"
|
||||
#include "Basics/WriteLocker.h"
|
||||
#include "Cluster/ServerState.h"
|
||||
#include "RestServer/QueryRegistryFeature.h"
|
||||
#include "Transaction/Methods.h"
|
||||
#include "Transaction/StandaloneContext.h"
|
||||
#include "Utils/OperationOptions.h"
|
||||
#include "Utils/SingleCollectionTransaction.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/Methods/Collections.h"
|
||||
|
||||
using namespace arangodb;
|
||||
using namespace arangodb::graph;
|
||||
using UserTransaction = transaction::Methods;
|
||||
using VelocyPackHelper = basics::VelocyPackHelper;
|
||||
|
||||
#ifndef USE_ENTERPRISE
|
||||
// Factory methods
|
||||
std::unique_ptr<Graph> Graph::fromPersistence(VPackSlice document, TRI_vocbase_t& vocbase) {
|
||||
std::unique_ptr<Graph> result{new Graph{document}};
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Graph> Graph::fromUserInput(std::string&& name, VPackSlice document, VPackSlice options) {
|
||||
std::unique_ptr<Graph> result{new Graph{std::move(name), document, options}};
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::unique_ptr<Graph> Graph::fromUserInput(std::string const& name, VPackSlice document, VPackSlice options) {
|
||||
return Graph::fromUserInput(std::string{name}, document, options);
|
||||
|
||||
}
|
||||
|
||||
// From persistence
|
||||
Graph::Graph(velocypack::Slice const& slice)
|
||||
: _graphName(VelocyPackHelper::getStringValue(slice, StaticStrings::KeyString, "")),
|
||||
_vertexColls(),
|
||||
_edgeColls(),
|
||||
_numberOfShards(basics::VelocyPackHelper::readNumericValue<uint64_t>(
|
||||
slice, StaticStrings::NumberOfShards, 1)),
|
||||
_replicationFactor(basics::VelocyPackHelper::readNumericValue<uint64_t>(
|
||||
slice, StaticStrings::ReplicationFactor, 1)),
|
||||
_rev(basics::VelocyPackHelper::getStringValue(
|
||||
slice, StaticStrings::RevString, "")) {
|
||||
// If this happens we have a document without an _key Attribute.
|
||||
TRI_ASSERT(!_graphName.empty());
|
||||
if (_graphName.empty()) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "Persisted graph is invalid. It does not have a _key set. Please contact support.");
|
||||
}
|
||||
|
||||
// If this happens we have a document without an _rev Attribute.
|
||||
TRI_ASSERT(!_rev.empty());
|
||||
if (_rev.empty()) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "Persisted graph is invalid. It does not have a _rev set. Please contact support.");
|
||||
}
|
||||
|
||||
if (slice.hasKey(StaticStrings::GraphEdgeDefinitions)) {
|
||||
parseEdgeDefinitions(slice.get(StaticStrings::GraphEdgeDefinitions));
|
||||
}
|
||||
if (slice.hasKey(StaticStrings::GraphOrphans)) {
|
||||
insertOrphanCollections(slice.get(StaticStrings::GraphOrphans));
|
||||
}
|
||||
}
|
||||
|
||||
// From user input
|
||||
Graph::Graph(std::string&& graphName, VPackSlice const& info, VPackSlice const& options)
|
||||
: _graphName(graphName),
|
||||
_vertexColls(),
|
||||
_edgeColls(),
|
||||
_numberOfShards(1),
|
||||
_replicationFactor(1),
|
||||
_rev("") {
|
||||
if (_graphName.empty()) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
TRI_ASSERT(_rev.empty());
|
||||
|
||||
if (info.hasKey(StaticStrings::GraphEdgeDefinitions)) {
|
||||
parseEdgeDefinitions(info.get(StaticStrings::GraphEdgeDefinitions));
|
||||
}
|
||||
if (info.hasKey(StaticStrings::GraphOrphans)) {
|
||||
insertOrphanCollections(info.get(StaticStrings::GraphOrphans));
|
||||
}
|
||||
if (options.isObject()) {
|
||||
_numberOfShards = VelocyPackHelper::readNumericValue<uint64_t>(
|
||||
options, StaticStrings::NumberOfShards, 1);
|
||||
_replicationFactor = VelocyPackHelper::readNumericValue<uint64_t>(
|
||||
options, StaticStrings::ReplicationFactor, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Graph::parseEdgeDefinitions(VPackSlice edgeDefs) {
|
||||
TRI_ASSERT(edgeDefs.isArray());
|
||||
if (!edgeDefs.isArray()) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_GRAPH_INVALID_GRAPH,
|
||||
"'edgeDefinitions' are not an array in the graph definition");
|
||||
}
|
||||
|
||||
for (auto const& def : VPackArrayIterator(edgeDefs)) {
|
||||
auto edgeDefRes = addEdgeDefinition(def);
|
||||
if (edgeDefRes.fail()) {
|
||||
THROW_ARANGO_EXCEPTION(edgeDefRes.copy_result());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Graph::insertOrphanCollections(VPackSlice const arr) {
|
||||
TRI_ASSERT(arr.isArray());
|
||||
for (auto const& c : VPackArrayIterator(arr)) {
|
||||
TRI_ASSERT(c.isString());
|
||||
addOrphanCollection(c.copyString());
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> const& Graph::vertexCollections() const {
|
||||
return _vertexColls;
|
||||
}
|
||||
|
||||
std::set<std::string> const& Graph::orphanCollections() const {
|
||||
return _orphanColls;
|
||||
}
|
||||
|
||||
std::set<std::string> const& Graph::edgeCollections() const {
|
||||
return _edgeColls;
|
||||
}
|
||||
|
||||
std::map<std::string, EdgeDefinition> const& Graph::edgeDefinitions()
|
||||
const {
|
||||
return _edgeDefs;
|
||||
}
|
||||
|
||||
uint64_t Graph::numberOfShards() const { return _numberOfShards; }
|
||||
|
||||
uint64_t Graph::replicationFactor() const { return _replicationFactor; }
|
||||
|
||||
std::string const Graph::id() const {
|
||||
return std::string(StaticStrings::GraphCollection + "/" + _graphName);
|
||||
}
|
||||
|
||||
std::string const& Graph::rev() const { return _rev; }
|
||||
|
||||
void Graph::addVertexCollection(std::string const& name) {
|
||||
if (_orphanColls.find(name) != _orphanColls.end()) {
|
||||
// Promote Orphans to vertices
|
||||
_orphanColls.erase(name);
|
||||
}
|
||||
_vertexColls.emplace(name);
|
||||
}
|
||||
|
||||
Result Graph::addOrphanCollection(std::string&& name) {
|
||||
if (_vertexColls.find(name) != _vertexColls.end()) {
|
||||
return TRI_ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF;
|
||||
}
|
||||
TRI_ASSERT(_orphanColls.find(name) == _orphanColls.end());
|
||||
_vertexColls.emplace(name);
|
||||
_orphanColls.emplace(std::move(name));
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
void Graph::setSmartState(bool state) { _isSmart = state; }
|
||||
|
||||
void Graph::setNumberOfShards(uint64_t numberOfShards) {
|
||||
_numberOfShards = numberOfShards;
|
||||
}
|
||||
|
||||
void Graph::setReplicationFactor(uint64_t replicationFactor) {
|
||||
_replicationFactor = replicationFactor;
|
||||
}
|
||||
|
||||
void Graph::setRev(std::string&& rev) { _rev = std::move(rev); }
|
||||
|
||||
void Graph::toVelocyPack(VPackBuilder& builder) const {
|
||||
VPackObjectBuilder guard(&builder);
|
||||
|
||||
if (!_vertexColls.empty()) {
|
||||
builder.add(VPackValue("vertexCollectionNames"));
|
||||
VPackArrayBuilder guard2(&builder);
|
||||
for (auto const& cn : _vertexColls) {
|
||||
builder.add(VPackValue(cn));
|
||||
}
|
||||
}
|
||||
|
||||
if (!_edgeColls.empty()) {
|
||||
builder.add(VPackValue("edgeCollectionNames"));
|
||||
VPackArrayBuilder guard2(&builder);
|
||||
for (auto const& cn : _edgeColls) {
|
||||
builder.add(VPackValue(cn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Graph::toPersistence(VPackBuilder& builder) const {
|
||||
TRI_ASSERT(builder.isOpenObject());
|
||||
|
||||
// The name
|
||||
builder.add(StaticStrings::KeyString, VPackValue(_graphName));
|
||||
|
||||
// Cluster Information
|
||||
builder.add(StaticStrings::NumberOfShards, VPackValue(_numberOfShards));
|
||||
builder.add(StaticStrings::ReplicationFactor, VPackValue(_replicationFactor));
|
||||
builder.add(StaticStrings::GraphIsSmart, VPackValue(isSmart()));
|
||||
|
||||
// EdgeDefinitions
|
||||
builder.add(VPackValue(StaticStrings::GraphEdgeDefinitions));
|
||||
builder.openArray();
|
||||
for (auto const& it : edgeDefinitions()) {
|
||||
it.second.addToBuilder(builder);
|
||||
}
|
||||
builder.close(); // EdgeDefinitions
|
||||
|
||||
// Orphan Collections
|
||||
builder.add(VPackValue(StaticStrings::GraphOrphans));
|
||||
builder.openArray();
|
||||
for (auto const& on : _orphanColls) {
|
||||
builder.add(VPackValue(on));
|
||||
}
|
||||
builder.close(); // Orphans
|
||||
}
|
||||
|
||||
void Graph::enhanceEngineInfo(VPackBuilder&) const {}
|
||||
|
||||
// validates the type:
|
||||
// edgeDefinition : { collection : string, from : [string], to : [string] }
|
||||
Result EdgeDefinition::validateEdgeDefinition(
|
||||
VPackSlice const& edgeDefinition) {
|
||||
if (!edgeDefinition.isObject()) {
|
||||
return Result(TRI_ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION);
|
||||
}
|
||||
|
||||
for (auto const& key : std::array<std::string, 3>{
|
||||
{"collection", StaticStrings::GraphFrom, StaticStrings::GraphTo}}) {
|
||||
if (!edgeDefinition.hasKey(key)) {
|
||||
return Result(TRI_ERROR_GRAPH_INTERNAL_DATA_CORRUPT,
|
||||
"Attribute '" + key + "' missing in edge definition!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!edgeDefinition.get("collection").isString()) {
|
||||
return Result(TRI_ERROR_GRAPH_INTERNAL_DATA_CORRUPT,
|
||||
"edge definition is not a string!");
|
||||
}
|
||||
|
||||
for (auto const& key : std::array<std::string, 2>{
|
||||
{StaticStrings::GraphFrom, StaticStrings::GraphTo}}) {
|
||||
if (!edgeDefinition.get(key).isArray()) {
|
||||
return Result(TRI_ERROR_GRAPH_INTERNAL_DATA_CORRUPT,
|
||||
"Edge definition '" + key + "' is not an array!");
|
||||
}
|
||||
|
||||
for (auto const& it : VPackArrayIterator(edgeDefinition.get(key))) {
|
||||
if (!it.isString()) {
|
||||
return Result(TRI_ERROR_GRAPH_INTERNAL_DATA_CORRUPT,
|
||||
std::string("Edge definition '") + key +
|
||||
"' does not only contain strings!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result();
|
||||
}
|
||||
|
||||
// TODO: maybe create a class instance here + func as class func
|
||||
// sort an edgeDefinition:
|
||||
// edgeDefinition : { collection : string, from : [string], to : [string] }
|
||||
std::shared_ptr<velocypack::Buffer<uint8_t>> EdgeDefinition::sortEdgeDefinition(
|
||||
VPackSlice const& edgeDefinition) {
|
||||
arangodb::basics::VelocyPackHelper::VPackLess<true> sorter;
|
||||
VPackBuilder from = VPackCollection::sort(edgeDefinition.get(StaticStrings::GraphFrom), sorter);
|
||||
VPackBuilder to = VPackCollection::sort(edgeDefinition.get(StaticStrings::GraphTo), sorter);
|
||||
VPackBuilder sortedBuilder;
|
||||
sortedBuilder.openObject();
|
||||
sortedBuilder.add("collection", edgeDefinition.get("collection"));
|
||||
sortedBuilder.add(StaticStrings::GraphFrom, from.slice());
|
||||
sortedBuilder.add(StaticStrings::GraphTo, to.slice());
|
||||
sortedBuilder.close();
|
||||
|
||||
return sortedBuilder.steal();
|
||||
}
|
||||
|
||||
ResultT<EdgeDefinition> EdgeDefinition::createFromVelocypack(
|
||||
VPackSlice edgeDefinition) {
|
||||
Result res = EdgeDefinition::validateEdgeDefinition(edgeDefinition);
|
||||
if (res.fail()) {
|
||||
return res;
|
||||
}
|
||||
std::string collection = edgeDefinition.get("collection").copyString();
|
||||
VPackSlice from = edgeDefinition.get(StaticStrings::GraphFrom);
|
||||
VPackSlice to = edgeDefinition.get(StaticStrings::GraphTo);
|
||||
|
||||
std::set<std::string> fromSet;
|
||||
std::set<std::string> toSet;
|
||||
|
||||
// duplicates in from and to shouldn't occur, but are safely ignored here
|
||||
for (auto const& it : VPackArrayIterator(from)) {
|
||||
fromSet.emplace(it.copyString());
|
||||
}
|
||||
for (auto const& it : VPackArrayIterator(to)) {
|
||||
toSet.emplace(it.copyString());
|
||||
}
|
||||
|
||||
return EdgeDefinition{collection, std::move(fromSet), std::move(toSet)};
|
||||
}
|
||||
|
||||
bool EdgeDefinition::operator==(EdgeDefinition const& other) const {
|
||||
return this->getName() == other.getName() &&
|
||||
this->getFrom() == other.getFrom() && this->getTo() == other.getTo();
|
||||
}
|
||||
|
||||
bool EdgeDefinition::operator!=(EdgeDefinition const& other) const {
|
||||
return this->getName() != other.getName() ||
|
||||
this->getFrom() != other.getFrom() || this->getTo() != other.getTo();
|
||||
}
|
||||
|
||||
void EdgeDefinition::addToBuilder(VPackBuilder& builder) const {
|
||||
builder.add(VPackValue(VPackValueType::Object));
|
||||
builder.add("collection", VPackValue(getName()));
|
||||
|
||||
builder.add("from", VPackValue(VPackValueType::Array));
|
||||
for (auto const& from : getFrom()) {
|
||||
builder.add(VPackValue(from));
|
||||
}
|
||||
builder.close(); // from
|
||||
|
||||
// to
|
||||
builder.add("to", VPackValue(VPackValueType::Array));
|
||||
for (auto const& to : getTo()) {
|
||||
builder.add(VPackValue(to));
|
||||
}
|
||||
builder.close(); // to
|
||||
|
||||
builder.close(); // obj
|
||||
}
|
||||
|
||||
bool EdgeDefinition::hasFrom(std::string const &vertexCollection) const {
|
||||
return getFrom().find(vertexCollection) != getFrom().end();
|
||||
}
|
||||
|
||||
bool EdgeDefinition::hasTo(std::string const &vertexCollection) const {
|
||||
return getTo().find(vertexCollection) != getTo().end();
|
||||
}
|
||||
|
||||
bool EdgeDefinition::hasVertexCollection(const std::string &vertexCollection) const {
|
||||
return hasFrom(vertexCollection) || hasTo(vertexCollection);
|
||||
}
|
||||
|
||||
// validates the type:
|
||||
// orphanDefinition : string <collectionName>
|
||||
Result Graph::validateOrphanCollection(VPackSlice const& orphanCollection) {
|
||||
if (!orphanCollection.isString()) {
|
||||
return Result(TRI_ERROR_GRAPH_CREATE_MALFORMED_ORPHAN_LIST,
|
||||
"orphan collection is not a string!");
|
||||
}
|
||||
return Result();
|
||||
}
|
||||
|
||||
ResultT<EdgeDefinition const*> Graph::addEdgeDefinition(VPackSlice const& edgeDefinitionSlice) {
|
||||
auto res = EdgeDefinition::createFromVelocypack(edgeDefinitionSlice);
|
||||
|
||||
if (res.fail()) {
|
||||
return res.copy_result();
|
||||
}
|
||||
TRI_ASSERT(res.ok());
|
||||
|
||||
EdgeDefinition const& edgeDefinition = res.get();
|
||||
|
||||
std::string const& collection = edgeDefinition.getName();
|
||||
if (hasEdgeCollection(collection)) {
|
||||
return {Result(
|
||||
TRI_ERROR_GRAPH_COLLECTION_MULTI_USE,
|
||||
collection + " " + std::string{TRI_errno_string(
|
||||
TRI_ERROR_GRAPH_COLLECTION_MULTI_USE)})};
|
||||
}
|
||||
|
||||
_edgeColls.emplace(collection);
|
||||
_edgeDefs.emplace(collection, edgeDefinition);
|
||||
TRI_ASSERT(hasEdgeCollection(collection));
|
||||
for (auto const& it : edgeDefinition.getFrom()) {
|
||||
addVertexCollection(it);
|
||||
}
|
||||
for (auto const& it : edgeDefinition.getTo()) {
|
||||
addVertexCollection(it);
|
||||
}
|
||||
|
||||
return &_edgeDefs.find(collection)->second;
|
||||
}
|
||||
|
||||
std::ostream& Graph::operator<<(std::ostream& ostream) {
|
||||
ostream << "Graph \"" << name() << "\" {\n";
|
||||
for (auto const& it : _edgeDefs) {
|
||||
EdgeDefinition const& def = it.second;
|
||||
ostream << " collection \"" << def.getName() << "\" {\n";
|
||||
ostream << " from [";
|
||||
bool first = true;
|
||||
for (auto const& from : def.getFrom()) {
|
||||
if (!first) {
|
||||
ostream << ", ";
|
||||
}
|
||||
first = false;
|
||||
ostream << from;
|
||||
}
|
||||
ostream << " to [";
|
||||
first = true;
|
||||
for (auto const& to : def.getTo()) {
|
||||
if (!first) {
|
||||
ostream << ", ";
|
||||
}
|
||||
first = false;
|
||||
ostream << to;
|
||||
}
|
||||
ostream << " }\n";
|
||||
}
|
||||
ostream << "}";
|
||||
|
||||
return ostream;
|
||||
}
|
||||
|
||||
bool Graph::hasEdgeCollection(std::string const& collectionName) const {
|
||||
TRI_ASSERT(
|
||||
(edgeDefinitions().find(collectionName) != edgeDefinitions().end()) ==
|
||||
(edgeCollections().find(collectionName) != edgeCollections().end()));
|
||||
return edgeCollections().find(collectionName) != edgeCollections().end();
|
||||
}
|
||||
|
||||
bool Graph::hasVertexCollection(std::string const& collectionName) const {
|
||||
return vertexCollections().find(collectionName) != vertexCollections().end();
|
||||
}
|
||||
|
||||
bool Graph::hasOrphanCollection(std::string const& collectionName) const {
|
||||
return orphanCollections().find(collectionName) != orphanCollections().end();
|
||||
}
|
||||
|
||||
void Graph::graphForClient(VPackBuilder& builder) const {
|
||||
TRI_ASSERT(builder.isOpenObject());
|
||||
builder.add(VPackValue("graph"));
|
||||
builder.openObject();
|
||||
|
||||
toPersistence(builder);
|
||||
TRI_ASSERT(builder.isOpenObject());
|
||||
builder.add(StaticStrings::RevString, VPackValue(rev()));
|
||||
builder.add(StaticStrings::IdString, VPackValue(id()));
|
||||
builder.add(StaticStrings::GraphName, VPackValue(_graphName));
|
||||
builder.close(); // graph object
|
||||
}
|
||||
|
||||
Result Graph::validateCollection(LogicalCollection& col) const {
|
||||
return {TRI_ERROR_NO_ERROR};
|
||||
}
|
||||
|
||||
void Graph::edgesToVpack(VPackBuilder& builder) const {
|
||||
builder.add(VPackValue(VPackValueType::Object));
|
||||
builder.add("collections", VPackValue(VPackValueType::Array));
|
||||
|
||||
for (auto const& edgeCollection : edgeCollections()) {
|
||||
builder.add(VPackValue(edgeCollection));
|
||||
}
|
||||
builder.close();
|
||||
|
||||
builder.close();
|
||||
}
|
||||
|
||||
void Graph::verticesToVpack(VPackBuilder& builder) const {
|
||||
builder.add(VPackValue(VPackValueType::Object));
|
||||
builder.add("collections", VPackValue(VPackValueType::Array));
|
||||
|
||||
for (auto const& vertexCollection : vertexCollections()) {
|
||||
builder.add(VPackValue(vertexCollection));
|
||||
}
|
||||
builder.close();
|
||||
|
||||
builder.close();
|
||||
}
|
||||
|
||||
bool Graph::isSmart() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Graph::createCollectionOptions(VPackBuilder& builder, bool waitForSync) const {
|
||||
TRI_ASSERT(builder.isOpenObject());
|
||||
|
||||
builder.add(StaticStrings::WaitForSyncString, VPackValue(waitForSync));
|
||||
builder.add(StaticStrings::NumberOfShards, VPackValue(numberOfShards()));
|
||||
builder.add(StaticStrings::ReplicationFactor, VPackValue(replicationFactor()));
|
||||
}
|
||||
|
||||
boost::optional<const EdgeDefinition&> Graph::getEdgeDefinition(
|
||||
std::string const& collectionName) const {
|
||||
auto it = edgeDefinitions().find(collectionName);
|
||||
if (it == edgeDefinitions().end()) {
|
||||
TRI_ASSERT(!hasEdgeCollection(collectionName));
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
TRI_ASSERT(hasEdgeCollection(collectionName));
|
||||
return {it->second};
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Tobias Gödderz
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_GRAPH_GRAPH_H
|
||||
#define ARANGOD_GRAPH_GRAPH_H
|
||||
|
||||
#include <velocypack/Buffer.h>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
|
||||
#include "Aql/Query.h"
|
||||
#include "Aql/VariableGenerator.h"
|
||||
#include "Basics/ReadWriteLock.h"
|
||||
#include "Cluster/ClusterInfo.h"
|
||||
#include "Cluster/ResultT.h"
|
||||
#include "Transaction/Methods.h"
|
||||
#include "Transaction/StandaloneContext.h"
|
||||
#include "Utils/OperationResult.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace graph {
|
||||
|
||||
class EdgeDefinition {
|
||||
public:
|
||||
EdgeDefinition(std::string edgeCollection_, std::set<std::string>&& from_,
|
||||
std::set<std::string>&& to_)
|
||||
: _edgeCollection(std::move(edgeCollection_)), _from(from_), _to(to_) {}
|
||||
|
||||
std::string const& getName() const { return _edgeCollection; }
|
||||
std::set<std::string> const& getFrom() const { return _from; }
|
||||
std::set<std::string> const& getTo() const { return _to; }
|
||||
|
||||
/// @brief Adds the edge definition as a new object {collection, from, to}
|
||||
/// to the builder.
|
||||
void addToBuilder(velocypack::Builder& builder) const;
|
||||
|
||||
bool hasFrom(std::string const& vertexCollection) const;
|
||||
bool hasTo(std::string const& vertexCollection) const;
|
||||
|
||||
bool hasVertexCollection(std::string const& vertexCollection) const;
|
||||
|
||||
/// @brief validate the structure of edgeDefinition, i.e.
|
||||
/// that it contains the correct attributes, and that they contain the correct
|
||||
/// types of values.
|
||||
static Result validateEdgeDefinition(const velocypack::Slice& edgeDefinition);
|
||||
static std::shared_ptr<velocypack::Buffer<uint8_t>> sortEdgeDefinition(
|
||||
const velocypack::Slice& edgeDefinition);
|
||||
|
||||
static ResultT<EdgeDefinition> createFromVelocypack(
|
||||
velocypack::Slice edgeDefinition);
|
||||
|
||||
bool operator==(EdgeDefinition const& other) const;
|
||||
bool operator!=(EdgeDefinition const& other) const;
|
||||
|
||||
private:
|
||||
std::string _edgeCollection;
|
||||
std::set<std::string> _from;
|
||||
std::set<std::string> _to;
|
||||
};
|
||||
|
||||
class Graph {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create graph from persistence.
|
||||
*
|
||||
* @param document The stored document
|
||||
*
|
||||
* @return A graph object corresponding to this document
|
||||
*/
|
||||
static std::unique_ptr<Graph> fromPersistence(
|
||||
velocypack::Slice document, TRI_vocbase_t& vocbase);
|
||||
|
||||
/**
|
||||
* @brief Create graph from user input.
|
||||
* NOTE: This is purely in memory and will NOT persist anything.
|
||||
*
|
||||
* @param name The name of the Graph
|
||||
* @param collectionInformation Collection information about relations and orphans
|
||||
* @param options The collection creation options.
|
||||
*
|
||||
* @return A graph object corresponding to the user input
|
||||
*/
|
||||
static std::unique_ptr<Graph> fromUserInput(
|
||||
std::string&& name, velocypack::Slice collectionInformation,
|
||||
velocypack::Slice options);
|
||||
|
||||
// Wrapper for Move constructor
|
||||
static std::unique_ptr<Graph> fromUserInput(
|
||||
std::string const& name, velocypack::Slice collectionInformation,
|
||||
velocypack::Slice options);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief Create graph from persistence.
|
||||
*
|
||||
* @param info The stored document
|
||||
*/
|
||||
explicit Graph(velocypack::Slice const& info);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create graph from user input.
|
||||
*
|
||||
* @param graphName The name of the graph
|
||||
* @param info Collection information, including relations and orphans
|
||||
* @param options The options to be used for collections
|
||||
*/
|
||||
Graph(std::string&& graphName, velocypack::Slice const& info, velocypack::Slice const& options);
|
||||
|
||||
public:
|
||||
virtual ~Graph() = default;
|
||||
|
||||
static Result validateOrphanCollection(
|
||||
const velocypack::Slice& orphanDefinition);
|
||||
|
||||
virtual void createCollectionOptions(VPackBuilder& builder,
|
||||
bool waitForSync) const;
|
||||
|
||||
public:
|
||||
/// @brief get the cids of all vertexCollections
|
||||
std::unordered_set<std::string> const& vertexCollections() const;
|
||||
|
||||
/// @brief get the cids of all orphanCollections
|
||||
std::set<std::string> const& orphanCollections() const;
|
||||
|
||||
/// @brief get the cids of all edgeCollections
|
||||
std::set<std::string> const& edgeCollections() const;
|
||||
|
||||
/// @brief get the cids of all edgeCollections
|
||||
std::map<std::string, EdgeDefinition> const& edgeDefinitions() const;
|
||||
|
||||
bool hasEdgeCollection(std::string const& collectionName) const;
|
||||
bool hasVertexCollection(std::string const& collectionName) const;
|
||||
bool hasOrphanCollection(std::string const& collectionName) const;
|
||||
|
||||
boost::optional<EdgeDefinition const&> getEdgeDefinition(
|
||||
std::string const& collectionName) const;
|
||||
|
||||
virtual bool isSmart() const;
|
||||
|
||||
uint64_t numberOfShards() const;
|
||||
uint64_t replicationFactor() const;
|
||||
std::string const id() const;
|
||||
std::string const& rev() const;
|
||||
|
||||
std::string const& name() const { return _graphName; }
|
||||
|
||||
/// @brief return a VelocyPack representation of the graph
|
||||
void toVelocyPack(velocypack::Builder&) const;
|
||||
|
||||
/**
|
||||
* @brief Create the GraphDocument to be stored in the database.
|
||||
*
|
||||
* @param builder The builder the result should be written in. Expects an open object.
|
||||
*/
|
||||
virtual void toPersistence(velocypack::Builder& builder) const;
|
||||
|
||||
/**
|
||||
* @brief Create the Graph Json Representation to be given to the client.
|
||||
* Uses toPersistence, but also includes _rev and _id values and encapsulates
|
||||
* the date into a graph attribute.
|
||||
*
|
||||
* @param builder The builder the result should be written in. Expects an open object.
|
||||
*/
|
||||
void graphForClient(VPackBuilder& builder) const;
|
||||
|
||||
/**
|
||||
* @brief Check if the collection is allowed to be used
|
||||
* within this graph
|
||||
*
|
||||
* @param col The collection
|
||||
*
|
||||
* @return TRUE if we are safe to use it.
|
||||
*/
|
||||
virtual Result validateCollection(LogicalCollection& col) const;
|
||||
|
||||
void edgesToVpack(VPackBuilder& builder) const;
|
||||
void verticesToVpack(VPackBuilder& builder) const;
|
||||
|
||||
virtual void enhanceEngineInfo(velocypack::Builder&) const;
|
||||
|
||||
/// @brief adds one edge definition. Returns an error if the edgeDefinition
|
||||
/// is already added to this graph.
|
||||
ResultT<EdgeDefinition const*> addEdgeDefinition(velocypack::Slice const& edgeDefinitionSlice);
|
||||
|
||||
/// @brief Add an orphan vertex collection to this graphs definition
|
||||
Result addOrphanCollection(std::string&&);
|
||||
|
||||
std::ostream& operator<<(std::ostream& ostream);
|
||||
|
||||
private:
|
||||
/// @brief Parse the edgeDefinition slice and inject it into this graph
|
||||
void parseEdgeDefinitions(velocypack::Slice edgeDefs);
|
||||
|
||||
/// @brief Add a vertex collection to this graphs definition
|
||||
void addVertexCollection(std::string const&);
|
||||
|
||||
/// @brief Add orphanCollections to the object
|
||||
void insertOrphanCollections(velocypack::Slice arr);
|
||||
|
||||
/// @brief Set numberOfShards to the graph definition
|
||||
void setNumberOfShards(uint64_t numberOfShards);
|
||||
|
||||
/// @brief Set replicationFactor to the graph definition
|
||||
void setReplicationFactor(uint64_t setReplicationFactor);
|
||||
|
||||
/// @brief Set isSmart to the graph definition
|
||||
void setSmartState(bool state);
|
||||
|
||||
/// @brief Set rev to the graph definition
|
||||
void setRev(std::string&& rev);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SECTION: Variables
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
protected:
|
||||
/// @brief name of this graph
|
||||
std::string const _graphName;
|
||||
|
||||
/// @brief the names of all vertexCollections
|
||||
/// This includes orphans.
|
||||
std::unordered_set<std::string> _vertexColls;
|
||||
|
||||
/// @brief the names of all orphanCollections
|
||||
std::set<std::string> _orphanColls;
|
||||
|
||||
/// @brief the names of all edgeCollections
|
||||
std::set<std::string> _edgeColls;
|
||||
|
||||
/// @brief edge definitions of this graph
|
||||
std::map<std::string, EdgeDefinition> _edgeDefs;
|
||||
|
||||
/// @brief state if smart graph enabled
|
||||
bool _isSmart;
|
||||
|
||||
/// @brief number of shards of this graph
|
||||
uint64_t _numberOfShards;
|
||||
|
||||
/// @brief replication factor of this graph
|
||||
uint64_t _replicationFactor;
|
||||
|
||||
/// @brief revision of this graph
|
||||
std::string _rev;
|
||||
};
|
||||
|
||||
// helper functions
|
||||
template<class T, class C>
|
||||
void setUnion(std::set<T> &set, C const &container) {
|
||||
for(auto const& it : container) {
|
||||
set.insert(it);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class C>
|
||||
void setMinus(std::set<T> &set, C const &container) {
|
||||
for(auto const& it : container) {
|
||||
set.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace graph
|
||||
} // namespace arangodb
|
||||
|
||||
#endif // ARANGOD_GRAPH_GRAPH_H
|
|
@ -0,0 +1,182 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Tobias Gödderz
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "GraphCache.h"
|
||||
|
||||
#include "Graph.h"
|
||||
|
||||
#include <velocypack/Buffer.h>
|
||||
#include <velocypack/Collection.h>
|
||||
#include <velocypack/Iterator.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
#include <array>
|
||||
#include <boost/variant.hpp>
|
||||
#include <utility>
|
||||
|
||||
#include "Aql/AstNode.h"
|
||||
#include "Aql/Graphs.h"
|
||||
#include "Aql/Query.h"
|
||||
#include "Basics/ReadLocker.h"
|
||||
#include "Basics/StaticStrings.h"
|
||||
#include "Basics/VelocyPackHelper.h"
|
||||
#include "Basics/WriteLocker.h"
|
||||
#include "Graph/GraphManager.h"
|
||||
#include "RestServer/QueryRegistryFeature.h"
|
||||
#include "Transaction/Methods.h"
|
||||
#include "Transaction/StandaloneContext.h"
|
||||
#include "Utils/OperationOptions.h"
|
||||
#include "Utils/SingleCollectionTransaction.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/Methods/Collections.h"
|
||||
|
||||
using namespace arangodb;
|
||||
using namespace arangodb::graph;
|
||||
|
||||
namespace getGraphFromCacheResult {
|
||||
struct Success {
|
||||
std::shared_ptr<Graph const> graph;
|
||||
|
||||
explicit Success(std::shared_ptr<Graph const> graph_)
|
||||
: graph(std::move(graph_)){};
|
||||
Success& operator=(Success const& other) = default;
|
||||
Success() = delete;
|
||||
};
|
||||
struct Outdated {};
|
||||
struct NotFound {};
|
||||
struct Exception {};
|
||||
}
|
||||
|
||||
using GetGraphFromCacheResult = boost::variant<
|
||||
getGraphFromCacheResult::Success, getGraphFromCacheResult::Outdated,
|
||||
getGraphFromCacheResult::NotFound, getGraphFromCacheResult::Exception>;
|
||||
|
||||
GetGraphFromCacheResult getGraphFromCache(GraphCache::CacheType const &_cache,
|
||||
std::string const &name,
|
||||
std::chrono::seconds maxAge) {
|
||||
using namespace getGraphFromCacheResult;
|
||||
|
||||
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
|
||||
|
||||
GraphCache::CacheType::const_iterator entryIt;
|
||||
bool entryFound;
|
||||
try {
|
||||
entryIt = _cache.find(name);
|
||||
entryFound = entryIt != _cache.end();
|
||||
} catch (...) {
|
||||
return Exception{};
|
||||
}
|
||||
|
||||
if (!entryFound) {
|
||||
return NotFound{};
|
||||
}
|
||||
|
||||
GraphCache::EntryType const& entry = entryIt->second;
|
||||
std::chrono::steady_clock::time_point const& insertedAt = entry.first;
|
||||
|
||||
if (now - insertedAt > maxAge) {
|
||||
return Outdated{};
|
||||
}
|
||||
|
||||
return Success{entry.second};
|
||||
}
|
||||
|
||||
const std::shared_ptr<const Graph> GraphCache::getGraph(
|
||||
std::shared_ptr<transaction::Context> ctx, std::string const& name,
|
||||
std::chrono::seconds maxAge) {
|
||||
using namespace getGraphFromCacheResult;
|
||||
|
||||
GetGraphFromCacheResult cacheResult = Exception{};
|
||||
|
||||
// try to lookup the graph in the cache first
|
||||
{
|
||||
READ_LOCKER(guard, _lock);
|
||||
cacheResult = getGraphFromCache(_cache, name, maxAge);
|
||||
}
|
||||
|
||||
// TODO The cache saves the graph names globally, not per database!
|
||||
// This must be addressed as soon as it is activated.
|
||||
/*
|
||||
if (typeid(Success) == cacheResult.type()) {
|
||||
LOG_TOPIC(TRACE, Logger::GRAPHS) << "GraphCache::getGraph('" << name
|
||||
<< "'): Found entry in cache";
|
||||
|
||||
return boost::get<Success>(cacheResult).graph;
|
||||
} else if (typeid(Outdated) == cacheResult.type()) {
|
||||
LOG_TOPIC(TRACE, Logger::GRAPHS) << "GraphCache::getGraph('" << name
|
||||
<< "'): Cached entry outdated";
|
||||
} else if (typeid(NotFound) == cacheResult.type()) {
|
||||
LOG_TOPIC(TRACE, Logger::GRAPHS) << "GraphCache::getGraph('" << name
|
||||
<< "'): No cache entry";
|
||||
} else if (typeid(Exception) == cacheResult.type()) {
|
||||
LOG_TOPIC(ERR, Logger::GRAPHS)
|
||||
<< "GraphCache::getGraph('" << name
|
||||
<< "'): An exception occured during cache lookup";
|
||||
} else {
|
||||
LOG_TOPIC(FATAL, Logger::GRAPHS) << "GraphCache::getGraph('" << name
|
||||
<< "'): Unhandled result type "
|
||||
<< cacheResult.type().name();
|
||||
|
||||
return nullptr;
|
||||
}*/
|
||||
|
||||
// if the graph wasn't found in the cache, lookup the graph and insert or
|
||||
// replace the entry. if the graph doesn't exist, erase a possible entry from
|
||||
// the cache.
|
||||
std::unique_ptr<Graph const> graph;
|
||||
try {
|
||||
WRITE_LOCKER(guard, _lock);
|
||||
|
||||
std::chrono::steady_clock::time_point now =
|
||||
std::chrono::steady_clock::now();
|
||||
|
||||
GraphManager gmngr{ctx->vocbase(), true};
|
||||
auto result = gmngr.lookupGraphByName(name);
|
||||
if (result.fail()) {
|
||||
if (result.is(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND) ||
|
||||
result.is(TRI_ERROR_GRAPH_NOT_FOUND)) {
|
||||
_cache.erase(name);
|
||||
}
|
||||
} else {
|
||||
graph.reset(result.get());
|
||||
}
|
||||
|
||||
if (graph == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CacheType::iterator it;
|
||||
bool insertSuccess;
|
||||
std::tie(it, insertSuccess) =
|
||||
_cache.emplace(name, std::make_pair(now, graph));
|
||||
|
||||
if (!insertSuccess) {
|
||||
it->second.first = now;
|
||||
it->second.second = graph;
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
};
|
||||
|
||||
// graph is never set to an invalid or outdated value. So even in case of an
|
||||
// exception, if graph was set, it may be returned.
|
||||
return graph;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Tobias Gödderz
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_GRAPH_GRAPHCACHE_H
|
||||
#define ARANGOD_GRAPH_GRAPHCACHE_H
|
||||
|
||||
#include <velocypack/Buffer.h>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
|
||||
#include "Aql/Query.h"
|
||||
#include "Aql/VariableGenerator.h"
|
||||
#include "Basics/ReadWriteLock.h"
|
||||
#include "Transaction/Methods.h"
|
||||
#include "Transaction/StandaloneContext.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace graph {
|
||||
class GraphCache {
|
||||
public:
|
||||
// save now() along with the graph
|
||||
using EntryType = std::pair<std::chrono::steady_clock::time_point,
|
||||
std::shared_ptr<const Graph>>;
|
||||
using CacheType = std::unordered_map<std::string, EntryType>;
|
||||
|
||||
// TODO The cache saves the graph names globally, not per database!
|
||||
// This must be addressed as soon as it is activated.
|
||||
const std::shared_ptr<const Graph> getGraph(
|
||||
std::shared_ptr<transaction::Context> ctx, std::string const& name,
|
||||
std::chrono::seconds maxAge = std::chrono::seconds(60));
|
||||
|
||||
private:
|
||||
basics::ReadWriteLock _lock;
|
||||
CacheType _cache;
|
||||
};
|
||||
} // namespace graph
|
||||
} // namespace arangodb
|
||||
|
||||
#endif // ARANGOD_GRAPH_GRAPHCACHE_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,204 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Heiko Kernbach
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_GRAPH_GRAPHMANAGER_H
|
||||
#define ARANGOD_GRAPH_GRAPHMANAGER_H
|
||||
|
||||
#include <velocypack/Buffer.h>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
|
||||
#include "Aql/Query.h"
|
||||
#include "Aql/VariableGenerator.h"
|
||||
#include "Basics/ReadWriteLock.h"
|
||||
#include "Cluster/ClusterInfo.h"
|
||||
#include "Cluster/ResultT.h"
|
||||
#include "Graph/Graph.h"
|
||||
#include "Transaction/Methods.h"
|
||||
#include "Transaction/StandaloneContext.h"
|
||||
#include "Utils/OperationResult.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace graph {
|
||||
|
||||
class GraphManager {
|
||||
|
||||
private:
|
||||
|
||||
TRI_vocbase_t& _vocbase;
|
||||
|
||||
bool _isInTransaction;
|
||||
|
||||
std::shared_ptr<transaction::Context> ctx() const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief find or create vertex collection by name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult findOrCreateVertexCollectionByName(const std::string& name,
|
||||
bool waitForSync, VPackSlice options);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief find or create collection by name and type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult createCollection(std::string const& name, TRI_col_type_e colType,
|
||||
bool waitForSync, VPackSlice options);
|
||||
|
||||
public:
|
||||
explicit GraphManager(TRI_vocbase_t& vocbase) : GraphManager(vocbase, false) {};
|
||||
|
||||
GraphManager(TRI_vocbase_t& vocbase, bool isInTransaction)
|
||||
: _vocbase(vocbase), _isInTransaction(isInTransaction) {
|
||||
}
|
||||
|
||||
OperationResult readGraphs(velocypack::Builder& builder,
|
||||
arangodb::aql::QueryPart queryPart) const;
|
||||
|
||||
OperationResult readGraphKeys(velocypack::Builder& builder,
|
||||
arangodb::aql::QueryPart queryPart) const;
|
||||
|
||||
OperationResult readGraphByQuery(velocypack::Builder& builder,
|
||||
arangodb::aql::QueryPart queryPart,
|
||||
std::string queryStr) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief find and return a collections if available
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static std::shared_ptr<LogicalCollection> getCollectionByName(
|
||||
const TRI_vocbase_t& vocbase, std::string const& name);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks wheter a graph exists or not
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool graphExists(std::string const& graphName) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief lookup a graph by name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
ResultT<std::unique_ptr<Graph>> lookupGraphByName(std::string const& name) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult createGraph(VPackSlice document, bool waitForSync) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief find or create collections by EdgeDefinitions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult findOrCreateCollectionsByEdgeDefinitions(
|
||||
std::map<std::string, EdgeDefinition> const& edgeDefinitions,
|
||||
bool waitForSync, VPackSlice options);
|
||||
|
||||
OperationResult findOrCreateCollectionsByEdgeDefinition(
|
||||
EdgeDefinition const& edgeDefinition, bool waitForSync,
|
||||
VPackSlice options);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a vertex collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult createVertexCollection(std::string const& name,
|
||||
bool waitForSync, VPackSlice options);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an edge collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult createEdgeCollection(std::string const& name,
|
||||
bool waitForSync, VPackSlice options);
|
||||
|
||||
/// @brief rename a collection used in an edge definition
|
||||
bool renameGraphCollection(std::string oldName, std::string newName);
|
||||
|
||||
/// @brief check if the edge definitions conflicts with one in an existing
|
||||
/// graph
|
||||
Result checkForEdgeDefinitionConflicts(
|
||||
std::map<std::string, arangodb::graph::EdgeDefinition> const&
|
||||
edgeDefinitions) const;
|
||||
|
||||
/// @brief check if the edge definition conflicts with one in an existing
|
||||
/// graph
|
||||
Result checkForEdgeDefinitionConflicts(
|
||||
arangodb::graph::EdgeDefinition const& edgeDefinition) const;
|
||||
|
||||
/// @brief Remove a graph and optional all connected collections
|
||||
OperationResult removeGraph(Graph const& graph, bool waitForSync,
|
||||
bool dropCollections);
|
||||
|
||||
OperationResult pushCollectionIfMayBeDropped(
|
||||
const std::string& colName, const std::string& graphName,
|
||||
std::unordered_set<std::string>& toBeRemoved);
|
||||
|
||||
bool collectionExists(std::string const& collection) const;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper function to make sure all collections required
|
||||
* for this graph are created or exist.
|
||||
* Will fail if the collections cannot be created, or
|
||||
* if they have a non-compatible sharding in SmartGraph-case.
|
||||
*
|
||||
* @param graph The graph information used to make sure all collections exist
|
||||
*
|
||||
* @return Either OK or an error.
|
||||
*/
|
||||
Result ensureCollections(Graph const* graph, bool waitForSync) const;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Store the given graph
|
||||
*
|
||||
* @param graph The graph to store
|
||||
* @param waitForSync Wait for Collection to sync
|
||||
* @param isUpdate If it is an update on existing graph or a new one.
|
||||
*
|
||||
* @return The result of the insrt transaction or Error.
|
||||
*/
|
||||
OperationResult storeGraph(Graph const& graph, bool waitForSync, bool isUpdate) const;
|
||||
|
||||
private:
|
||||
|
||||
#ifdef USE_ENTERPRISE
|
||||
Result ensureSmartCollectionSharding(Graph const* graph, bool waitForSync, std::unordered_set<std::string>& documentCollections) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Create a new in memory graph object from the given input.
|
||||
* This graph object does not create collections and does
|
||||
* not check them. It cannot be used to access any kind
|
||||
* of data. In order to get a "usable" Graph object use
|
||||
* lookup by name.
|
||||
*
|
||||
* @param input The slice containing the graph data.
|
||||
*
|
||||
* @return A temporary Graph object
|
||||
*/
|
||||
ResultT<std::unique_ptr<Graph>> buildGraphFromInput(std::string const& graphName, arangodb::velocypack::Slice input) const;
|
||||
|
||||
Result checkCreateGraphPermissions(Graph const* graph) const;
|
||||
|
||||
Result checkDropGraphPermissions(
|
||||
Graph const& graph,
|
||||
std::unordered_set<std::string> const& followersToBeRemoved,
|
||||
std::unordered_set<std::string> const& leadersToBeRemoved);
|
||||
};
|
||||
} // namespace graph
|
||||
} // namespace arangodb
|
||||
|
||||
#endif // ARANGOD_GRAPH_GRAPHMANAGER_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,211 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Tobias Gödderz & Heiko Kernbach
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_GRAPH_GRAPHOPERATIONS_H
|
||||
#define ARANGOD_GRAPH_GRAPHOPERATIONS_H
|
||||
|
||||
#include <velocypack/Buffer.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
|
||||
#include "Aql/Query.h"
|
||||
#include "Aql/VariableGenerator.h"
|
||||
#include "Auth/Common.h"
|
||||
#include "Basics/ReadWriteLock.h"
|
||||
#include "Cluster/ClusterInfo.h"
|
||||
#include "Cluster/ResultT.h"
|
||||
#include "Graph/Graph.h"
|
||||
#include "Transaction/Methods.h"
|
||||
#include "Transaction/StandaloneContext.h"
|
||||
#include "Utils/OperationResult.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace graph {
|
||||
|
||||
// TODO rename to GraphMethods
|
||||
|
||||
class GraphOperations {
|
||||
private:
|
||||
Graph& _graph;
|
||||
TRI_vocbase_t& _vocbase;
|
||||
|
||||
Graph const& graph() const { return _graph; };
|
||||
std::shared_ptr<transaction::Context> ctx() const;
|
||||
|
||||
public:
|
||||
GraphOperations() = delete;
|
||||
GraphOperations(Graph& graph_,
|
||||
TRI_vocbase_t& vocbase)
|
||||
: _graph(graph_), _vocbase(vocbase) {}
|
||||
|
||||
// TODO I added the complex result type for the get* methods to exactly
|
||||
// reproduce (in the RestGraphHandler) the behaviour of the similar methods
|
||||
// in the RestDocumentHandler. A simpler type, e.g. ResultT<OperationResult>,
|
||||
// would be preferable.
|
||||
|
||||
/// @brief Get a single vertex document from collection, optionally check rev
|
||||
/// The return value is as follows:
|
||||
/// If trx.begin fails, the outer ResultT will contain this error Result.
|
||||
/// Otherwise, the results of both (trx.document(), trx.finish()) are
|
||||
/// returned as a pair.
|
||||
/// This is because in case of a precondition error during trx.document(),
|
||||
/// the OperationResult may still be needed.
|
||||
OperationResult getVertex(std::string const& collectionName,
|
||||
std::string const& key,
|
||||
boost::optional<TRI_voc_rid_t> rev);
|
||||
|
||||
/// @brief Get a single edge document from definitionName.
|
||||
/// Similar to getVertex().
|
||||
OperationResult getEdge(const std::string& definitionName,
|
||||
const std::string& key,
|
||||
boost::optional<TRI_voc_rid_t> rev);
|
||||
|
||||
/// @brief Remove a single edge document from definitionName.
|
||||
OperationResult removeEdge(const std::string& definitionName,
|
||||
const std::string& key,
|
||||
boost::optional<TRI_voc_rid_t> rev,
|
||||
bool waitForSync, bool returnOld);
|
||||
|
||||
/// @brief Remove a vertex and all incident edges in the graph
|
||||
OperationResult removeVertex(const std::string& collectionName,
|
||||
const std::string& key,
|
||||
boost::optional<TRI_voc_rid_t> rev,
|
||||
bool waitForSync, bool returnOld);
|
||||
|
||||
OperationResult updateEdge(const std::string& definitionName,
|
||||
const std::string& key, VPackSlice document,
|
||||
boost::optional<TRI_voc_rid_t> rev,
|
||||
bool waitForSync, bool returnOld, bool returnNew,
|
||||
bool keepNull);
|
||||
|
||||
OperationResult replaceEdge(const std::string& definitionName,
|
||||
const std::string& key, VPackSlice document,
|
||||
boost::optional<TRI_voc_rid_t> rev,
|
||||
bool waitForSync, bool returnOld, bool returnNew,
|
||||
bool keepNull);
|
||||
|
||||
OperationResult createEdge(const std::string& definitionName,
|
||||
VPackSlice document, bool waitForSync,
|
||||
bool returnNew);
|
||||
|
||||
OperationResult updateVertex(const std::string& collectionName,
|
||||
const std::string& key, VPackSlice document,
|
||||
boost::optional<TRI_voc_rid_t> rev,
|
||||
bool waitForSync, bool returnOld, bool returnNew,
|
||||
bool keepNull);
|
||||
|
||||
OperationResult replaceVertex(const std::string& collectionName,
|
||||
const std::string& key, VPackSlice document,
|
||||
boost::optional<TRI_voc_rid_t> rev,
|
||||
bool waitForSync, bool returnOld,
|
||||
bool returnNew, bool keepNull);
|
||||
|
||||
OperationResult createVertex(const std::string& collectionName,
|
||||
VPackSlice document, bool waitForSync,
|
||||
bool returnNew);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add an orphan to collection to an existing graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult addOrphanCollection(VPackSlice document, bool waitForSync,
|
||||
bool createCollection);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remove an orphan collection from an existing graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult eraseOrphanCollection(bool waitForSync,
|
||||
std::string collectionName,
|
||||
bool dropCollection);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a new edge definition in an existing graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult addEdgeDefinition(VPackSlice edgeDefinition,
|
||||
bool waitForSync);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remove an edge definition from an existing graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult eraseEdgeDefinition(bool waitForSync,
|
||||
std::string edgeDefinitionName,
|
||||
bool dropCollection);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create edge definition in an existing graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult editEdgeDefinition(VPackSlice edgeDefinitionSlice,
|
||||
bool waitForSync,
|
||||
const std::string& edgeDefinitionName);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief change the edge definition for a specified graph
|
||||
/// if the graph doesn't already contain a definition for the same edge
|
||||
/// collection, this does nothing and returns success.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
OperationResult changeEdgeDefinitionForGraph(
|
||||
const Graph& graph, const EdgeDefinition& edgeDefinition,
|
||||
bool waitForSync, transaction::Methods& trx);
|
||||
|
||||
private:
|
||||
using VPackBufferPtr = std::shared_ptr<velocypack::Buffer<uint8_t>>;
|
||||
|
||||
OperationResult getDocument(std::string const& collectionName,
|
||||
const std::string& key,
|
||||
boost::optional<TRI_voc_rid_t> rev);
|
||||
|
||||
/// @brief creates a vpack { _key: key } or { _key: key, _rev: rev }
|
||||
/// (depending on whether rev is set)
|
||||
VPackBufferPtr _getSearchSlice(const std::string& key,
|
||||
boost::optional<TRI_voc_rid_t>& rev) const;
|
||||
|
||||
OperationResult modifyDocument(const std::string& collectionName,
|
||||
const std::string& key, VPackSlice document,
|
||||
bool isPatch,
|
||||
boost::optional<TRI_voc_rid_t> rev,
|
||||
bool waitForSync, bool returnOld,
|
||||
bool returnNew, bool keepNull);
|
||||
|
||||
OperationResult createDocument(transaction::Methods* trx,
|
||||
const std::string& collectionName,
|
||||
VPackSlice document, bool waitForSync,
|
||||
bool returnNew);
|
||||
|
||||
OperationResult checkEdgeCollectionAvailability(
|
||||
std::string edgeCollectionName);
|
||||
OperationResult checkVertexCollectionAvailability(
|
||||
std::string vertexCollectionName);
|
||||
|
||||
bool hasROPermissionsFor(std::string const& collection) const;
|
||||
bool hasRWPermissionsFor(std::string const& collection) const;
|
||||
bool hasPermissionsFor(std::string const& collection,
|
||||
auth::Level level) const;
|
||||
|
||||
Result checkEdgeDefinitionPermissions(
|
||||
EdgeDefinition const& edgeDefinition) const;
|
||||
|
||||
bool collectionExists(std::string const& collection) const;
|
||||
};
|
||||
} // namespace graph
|
||||
} // namespace arangodb
|
||||
|
||||
#endif // ARANGOD_GRAPH_GRAPHOPERATIONS_H
|
|
@ -24,7 +24,6 @@
|
|||
#include "RestControlPregelHandler.h"
|
||||
|
||||
#include "ApplicationFeatures/ApplicationServer.h"
|
||||
#include "Aql/Graphs.h"
|
||||
#include "Basics/VelocyPackHelper.h"
|
||||
#include "Cluster/ServerState.h"
|
||||
#include "Pregel/Conductor.h"
|
||||
|
@ -33,7 +32,8 @@
|
|||
#include "Transaction/StandaloneContext.h"
|
||||
#include "V8/v8-vpack.h"
|
||||
#include "V8Server/V8DealerFeature.h"
|
||||
#include "VocBase/Graphs.h"
|
||||
#include "Graph/Graph.h"
|
||||
#include "Graph/GraphManager.h"
|
||||
#include "VocBase/Methods/Tasks.h"
|
||||
|
||||
#include <velocypack/Builder.h>
|
||||
|
@ -133,12 +133,13 @@ void RestControlPregelHandler::startExecution() {
|
|||
return;
|
||||
}
|
||||
|
||||
auto ctx = transaction::StandaloneContext::Create(_vocbase);
|
||||
auto graph = lookupGraphByName(ctx, gs);
|
||||
if (nullptr == graph) {
|
||||
generateError(TRI_ERROR_GRAPH_NOT_FOUND);
|
||||
graph::GraphManager gmngr{_vocbase};
|
||||
auto graphRes = gmngr.lookupGraphByName(gs);
|
||||
if (graphRes.fail()) {
|
||||
generateError(graphRes.copy_result());
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<graph::Graph> graph = std::move(graphRes.get());
|
||||
|
||||
auto gv = graph->vertexCollections();
|
||||
for (auto& v : gv) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,278 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Tobias Gödderz
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_REST_HANDLER_REST_GRAPH_HANDLER_H
|
||||
#define ARANGOD_REST_HANDLER_REST_GRAPH_HANDLER_H
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "Actions/RestActionHandler.h"
|
||||
#include "Graph/GraphManager.h"
|
||||
#include "RestHandler/RestBaseHandler.h"
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
namespace graph {
|
||||
class Graph;
|
||||
}
|
||||
|
||||
class RestGraphHandler : public arangodb::RestVocbaseBaseHandler {
|
||||
private:
|
||||
enum class GraphProperty {
|
||||
VERTICES, EDGES
|
||||
};
|
||||
|
||||
enum class EdgeDefinitionAction {
|
||||
CREATE, EDIT, REMOVE
|
||||
};
|
||||
|
||||
enum class VertexDefinitionAction {
|
||||
CREATE, REMOVE
|
||||
};
|
||||
|
||||
public:
|
||||
RestGraphHandler(GeneralRequest* request, GeneralResponse* response);
|
||||
|
||||
~RestGraphHandler() override = default;
|
||||
|
||||
char const* name() const final { return "RestGraphHandler"; }
|
||||
|
||||
RestStatus execute() override;
|
||||
|
||||
RequestLane lane() const override;
|
||||
|
||||
private:
|
||||
arangodb::Result executeGharial();
|
||||
|
||||
// /_api/gharial
|
||||
arangodb::Result graphsAction();
|
||||
|
||||
// /_api/gharial/{graph-name}
|
||||
arangodb::Result graphAction(
|
||||
graph::Graph& graph);
|
||||
|
||||
// /_api/gharial/{graph-name}/vertex
|
||||
arangodb::Result vertexSetsAction(
|
||||
graph::Graph& graph);
|
||||
|
||||
// /_api/gharial/{graph-name}/edge
|
||||
arangodb::Result edgeSetsAction(
|
||||
graph::Graph& graph);
|
||||
|
||||
// /_api/gharial/{graph-name}/vertex/{collection-name}
|
||||
arangodb::Result vertexSetAction(
|
||||
graph::Graph& graph,
|
||||
const std::string& vertexCollectionName);
|
||||
|
||||
// /_api/gharial/{graph-name}/edge/{definition-name}
|
||||
arangodb::Result edgeSetAction(
|
||||
graph::Graph& graph,
|
||||
const std::string& edgeDefinitionName);
|
||||
|
||||
// /_api/gharial/{graph-name}/vertex/{collection-name}/{vertex-key}
|
||||
arangodb::Result vertexAction(
|
||||
graph::Graph& graph,
|
||||
const std::string& vertexCollectionName, const std::string& vertexKey);
|
||||
|
||||
// /_api/gharial/{graph-name}/edge/{definition-name}/{edge-key}
|
||||
arangodb::Result edgeAction(
|
||||
graph::Graph& graph,
|
||||
const std::string& edgeDefinitionName, const std::string& edgeKey);
|
||||
|
||||
// GET /_api/gharial/{graph-name}/vertex/{collection-name}/{vertex-key}
|
||||
void vertexActionRead(graph::Graph& graph,
|
||||
const std::string &collectionName,
|
||||
const std::string &key);
|
||||
|
||||
// DELETE /_api/gharial/{graph-name}/vertex/{collection-name}/{vertex-key}
|
||||
arangodb::Result vertexActionRemove(graph::Graph& graph,
|
||||
const std::string& collectionName,
|
||||
const std::string& key);
|
||||
|
||||
// PATCH /_api/gharial/{graph-name}/vertex/{collection-name}/{vertex-key}
|
||||
arangodb::Result vertexActionUpdate(graph::Graph& graph,
|
||||
const std::string& collectionName,
|
||||
const std::string& key);
|
||||
|
||||
// PUT /_api/gharial/{graph-name}/vertex/{collection-name}/{vertex-key}
|
||||
arangodb::Result vertexActionReplace(graph::Graph& graph,
|
||||
const std::string& collectionName,
|
||||
const std::string& key);
|
||||
|
||||
// POST /_api/gharial/{graph-name}/vertex/{collection-name}/{vertex-key}
|
||||
arangodb::Result vertexActionCreate(graph::Graph& graph,
|
||||
const std::string& collectionName);
|
||||
|
||||
// GET /_api/gharial/{graph-name}/edge/{definition-name}/{edge-key}
|
||||
void edgeActionRead(graph::Graph& graph,
|
||||
const std::string &definitionName,
|
||||
const std::string &key);
|
||||
|
||||
// DELETE /_api/gharial/{graph-name}/edge/{definition-name}/{edge-key}
|
||||
arangodb::Result edgeActionRemove(graph::Graph& graph,
|
||||
const std::string& definitionName,
|
||||
const std::string& key);
|
||||
|
||||
// POST /_api/gharial/{graph-name}/edge/{definition-name}/{edge-key}
|
||||
arangodb::Result edgeActionCreate(graph::Graph& graph,
|
||||
const std::string& definitionName);
|
||||
|
||||
// PATCH /_api/gharial/{graph-name}/edge/{definition-name}/{edge-key}
|
||||
arangodb::Result edgeActionUpdate(graph::Graph& graph,
|
||||
const std::string& collectionName,
|
||||
const std::string& key);
|
||||
|
||||
// PUT /_api/gharial/{graph-name}/edge/{definition-name}/{edge-key}
|
||||
arangodb::Result edgeActionReplace(graph::Graph& graph,
|
||||
const std::string& collectionName,
|
||||
const std::string& key);
|
||||
|
||||
std::unique_ptr<graph::Graph> getGraph(const std::string& graphName);
|
||||
|
||||
void generateVertexRead(VPackSlice vertex, VPackOptions const& options);
|
||||
|
||||
void generateEdgeRead(VPackSlice edge, const VPackOptions& options);
|
||||
|
||||
void generateRemoved(bool removed, bool wasSynchronous, VPackSlice old,
|
||||
VPackOptions const& options);
|
||||
|
||||
void generateGraphRemoved(bool removed, bool wasSynchronous,
|
||||
VPackOptions const& options);
|
||||
|
||||
void generateCreatedGraphConfig(bool wasSynchronous, VPackSlice slice,
|
||||
VPackOptions const& options);
|
||||
|
||||
void generateCreatedEdgeDefinition(bool wasSynchronous, VPackSlice slice,
|
||||
VPackOptions const& options);
|
||||
|
||||
void generateGraphConfig(VPackSlice slice, VPackOptions const& options);
|
||||
|
||||
// TODO maybe cleanup the generate* zoo a little?
|
||||
void generateResultWithField(std::string const& key, VPackSlice value,
|
||||
VPackOptions const& options);
|
||||
|
||||
void generateResultMergedWithObject(VPackSlice obj,
|
||||
VPackOptions const& options);
|
||||
|
||||
void addEtagHeader(velocypack::Slice slice);
|
||||
|
||||
Result vertexModify(graph::Graph& graph,
|
||||
const std::string& collectionName, const std::string& key,
|
||||
bool isPatch);
|
||||
|
||||
Result vertexCreate(graph::Graph& graph,
|
||||
const std::string& collectionName);
|
||||
|
||||
void generateVertexModified(bool wasSynchronous, VPackSlice resultSlice,
|
||||
const velocypack::Options& options);
|
||||
|
||||
void generateVertexCreated(bool wasSynchronous, VPackSlice resultSlice,
|
||||
const velocypack::Options& options);
|
||||
|
||||
void generateModified(TRI_col_type_e colType, bool wasSynchronous,
|
||||
VPackSlice resultSlice,
|
||||
const velocypack::Options& options);
|
||||
|
||||
void generateCreated(TRI_col_type_e colType, bool wasSynchronous,
|
||||
VPackSlice resultSlice,
|
||||
const velocypack::Options& options);
|
||||
|
||||
Result edgeModify(graph::Graph& graph,
|
||||
const std::string& collectionName, const std::string& key,
|
||||
bool isPatch);
|
||||
|
||||
Result edgeCreate(graph::Graph& graph,
|
||||
const std::string& collectionName);
|
||||
|
||||
Result documentModify(graph::Graph& graph,
|
||||
const std::string& collectionName,
|
||||
const std::string& key, bool isPatch,
|
||||
TRI_col_type_e colType);
|
||||
|
||||
Result documentCreate(
|
||||
graph::Graph& graph, const std::string &collectionName,
|
||||
TRI_col_type_e colType
|
||||
);
|
||||
|
||||
Result graphActionReadGraphConfig(
|
||||
graph::Graph const& graph
|
||||
);
|
||||
|
||||
Result graphActionRemoveGraph(
|
||||
graph::Graph const& graph
|
||||
);
|
||||
|
||||
Result graphActionCreateGraph();
|
||||
Result graphActionReadGraphs();
|
||||
|
||||
Result graphActionReadConfig(
|
||||
graph::Graph const& graph,
|
||||
TRI_col_type_e colType, GraphProperty property
|
||||
);
|
||||
|
||||
void generateEdgeModified(
|
||||
bool wasSynchronous, VPackSlice resultSlice,
|
||||
velocypack::Options const& options
|
||||
);
|
||||
|
||||
void generateEdgeCreated(
|
||||
bool wasSynchronous, VPackSlice resultSlice,
|
||||
velocypack::Options const& options
|
||||
);
|
||||
|
||||
// edges
|
||||
// PATCH /_api/gharial/{graph-name}/edge/{definition-name}
|
||||
Result editEdgeDefinition(
|
||||
graph::Graph& graph,
|
||||
const std::string& edgeDefinitionName
|
||||
);
|
||||
|
||||
// DELETE /_api/gharial/{graph-name}/edge/{definition-name}
|
||||
Result removeEdgeDefinition(
|
||||
graph::Graph& graph,
|
||||
const std::string& edgeDefinitionName
|
||||
);
|
||||
|
||||
// POST /_api/gharial/{graph-name}/edge/
|
||||
Result createEdgeDefinition(
|
||||
graph::Graph& graph
|
||||
);
|
||||
|
||||
// edgeDefinitionName may be omitted when action == CREATE
|
||||
Result modifyEdgeDefinition(
|
||||
graph::Graph& graph,
|
||||
EdgeDefinitionAction action,
|
||||
std::string edgeDefinitionName = {}
|
||||
);
|
||||
|
||||
Result modifyVertexDefinition(
|
||||
graph::Graph& graph,
|
||||
VertexDefinitionAction action,
|
||||
std::string vertexDefinitionName
|
||||
);
|
||||
|
||||
private:
|
||||
graph::GraphManager _gmngr;
|
||||
};
|
||||
} // namespace arangodb
|
||||
|
||||
#endif // ARANGOD_REST_HANDLER_REST_GRAPH_HANDLER_H
|
|
@ -193,6 +193,7 @@ RestStatus RestRepairHandler::repairDistributeShardsLike() {
|
|||
if (ClusterInfo* clusterInfo = ClusterInfo::instance()) {
|
||||
clusterInfo->loadPlan();
|
||||
}
|
||||
|
||||
}
|
||||
return RestStatus::DONE;
|
||||
}
|
||||
|
|
|
@ -102,6 +102,12 @@ std::string const RestVocbaseBaseHandler::DOCUMENT_PATH = "/_api/document";
|
|||
|
||||
std::string const RestVocbaseBaseHandler::EDGES_PATH = "/_api/edges";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief gharial graph api path
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string const RestVocbaseBaseHandler::GHARIAL_PATH = "/_api/gharial";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief endpoint path
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -103,6 +103,12 @@ class RestVocbaseBaseHandler : public RestBaseHandler {
|
|||
|
||||
static std::string const EDGES_PATH;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief gharial graph api path
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static std::string const GHARIAL_PATH;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief endpoint path
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -0,0 +1,770 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Heiko Kernbach
|
||||
/// @author Copyright 2018, ArangoDB GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "v8-users.h"
|
||||
|
||||
#include "ApplicationFeatures/ApplicationServer.h"
|
||||
#include "Basics/VelocyPackHelper.h"
|
||||
#include "GeneralServer/AuthenticationFeature.h"
|
||||
#include "Graph/Graph.h"
|
||||
#include "Graph/GraphManager.h"
|
||||
#include "Graph/GraphOperations.h"
|
||||
#include "RestServer/DatabaseFeature.h"
|
||||
#include "Transaction/V8Context.h"
|
||||
#include "Utils/ExecContext.h"
|
||||
#include "V8/v8-conv.h"
|
||||
#include "V8/v8-globals.h"
|
||||
#include "V8/v8-utils.h"
|
||||
#include "V8/v8-vpack.h"
|
||||
#include "V8Server/v8-externals.h"
|
||||
#include "V8Server/v8-vocbase.h"
|
||||
#include "V8Server/v8-vocbaseprivate.h"
|
||||
#include "V8Server/v8-vocindex.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
|
||||
#include <velocypack/HexDump.h>
|
||||
#include <velocypack/Slice.h>
|
||||
|
||||
using namespace arangodb;
|
||||
using namespace arangodb::velocypack;
|
||||
using namespace arangodb::basics;
|
||||
using namespace arangodb::graph;
|
||||
using namespace arangodb::rest;
|
||||
|
||||
static void JS_DropGraph(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
if (args.Length() < 1) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE("_drop(graphName, dropCollections)");
|
||||
} else if (!args[0]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
std::string graphName = TRI_ObjectToString(args[0]);
|
||||
if (graphName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
bool dropCollections = false;
|
||||
if (args.Length() >= 2) {
|
||||
dropCollections = TRI_ObjectToBoolean(args[1]);
|
||||
}
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
auto ctx = transaction::V8Context::Create(vocbase, false);
|
||||
|
||||
GraphManager gmngr{vocbase};
|
||||
auto graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
OperationResult result = gmngr.removeGraph(*(graph.get()), true, dropCollections);
|
||||
|
||||
VPackBuilder obj;
|
||||
obj.add(VPackValue(VPackValueType::Object, true));
|
||||
obj.add("removed", VPackValue(result.ok()));
|
||||
obj.close();
|
||||
TRI_V8_RETURN(TRI_VPackToV8(isolate, obj.slice()));
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void JS_RenameGraphCollection(
|
||||
v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
if (args.Length() < 2) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE("_renameCollection(oldName, newName)");
|
||||
} else if (!args[0]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
} else if (!args[1]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
std::string oldName = TRI_ObjectToString(args[0]);
|
||||
std::string newName = TRI_ObjectToString(args[1]);
|
||||
if (oldName.empty() || newName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
GraphManager gmngr{vocbase};
|
||||
bool r = gmngr.renameGraphCollection(oldName, newName);
|
||||
|
||||
TRI_V8_RETURN(r);
|
||||
|
||||
TRI_V8_RETURN_UNDEFINED();
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void JS_GraphExists(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
if (args.Length() < 1) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE("_exists(graphName)");
|
||||
} else if (!args[0]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
std::string graphName = TRI_ObjectToString(args[0]);
|
||||
if (graphName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
// check if graph already exists
|
||||
GraphManager gmngr{vocbase};
|
||||
bool r = gmngr.graphExists(graphName);
|
||||
|
||||
TRI_V8_RETURN(r);
|
||||
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void JS_GetGraph(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
if (args.Length() < 1) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE("_graph(graphName)");
|
||||
} else if (!args[0]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
std::string graphName = TRI_ObjectToString(args[0]);
|
||||
if (graphName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
|
||||
GraphManager gmngr{vocbase};
|
||||
auto graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
VPackBuilder result;
|
||||
result.openObject();
|
||||
graph.get()->graphForClient(result);
|
||||
result.close();
|
||||
VPackSlice resSlice = result.slice().get("graph");
|
||||
|
||||
TRI_V8_RETURN(TRI_VPackToV8(isolate, resSlice));
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void JS_GetGraphs(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
|
||||
GraphManager gmngr{vocbase};
|
||||
VPackBuilder result;
|
||||
OperationResult r = gmngr.readGraphs(result, arangodb::aql::PART_DEPENDENT);
|
||||
|
||||
if (r.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(r.errorNumber(), r.errorMessage());
|
||||
}
|
||||
|
||||
if (!result.isEmpty()) {
|
||||
TRI_V8_RETURN(TRI_VPackToV8(isolate, result.slice().get("graphs")));
|
||||
}
|
||||
|
||||
TRI_V8_RETURN_UNDEFINED();
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void JS_GetGraphKeys(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
|
||||
GraphManager gmngr{vocbase};
|
||||
VPackBuilder result;
|
||||
OperationResult r =
|
||||
gmngr.readGraphKeys(result, arangodb::aql::PART_DEPENDENT);
|
||||
|
||||
if (r.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(r.errorNumber(), r.errorMessage());
|
||||
}
|
||||
|
||||
if (!result.isEmpty()) {
|
||||
TRI_V8_RETURN(TRI_VPackToV8(isolate, result.slice().get("graphs")));
|
||||
}
|
||||
|
||||
TRI_V8_RETURN_UNDEFINED();
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void JS_CreateGraph(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
// TODO Needs to return a wrapped Graph!
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
if (args.Length() < 1) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE(
|
||||
"_create(graphName, edgeDefinitions, orphanCollections, options)");
|
||||
} else if (!args[0]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
std::string graphName = TRI_ObjectToString(args[0]);
|
||||
if (graphName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
|
||||
VPackBuilder builder;
|
||||
builder.openObject();
|
||||
|
||||
builder.add("name", VPackValue(graphName));
|
||||
if (args.Length() >= 2 && !args[1]->IsNullOrUndefined()) {
|
||||
builder.add(VPackValue(StaticStrings::GraphEdgeDefinitions));
|
||||
TRI_V8ToVPack(isolate, builder, args[1], true, true);
|
||||
builder.close();
|
||||
}
|
||||
if (args.Length() >= 3 && !args[2]->IsNullOrUndefined()) {
|
||||
builder.add(VPackValue(StaticStrings::GraphOrphans));
|
||||
TRI_V8ToVPack(isolate, builder, args[2], true, true);
|
||||
builder.close();
|
||||
}
|
||||
if (args.Length() >= 4 && !args[3]->IsNullOrUndefined()) {
|
||||
builder.add(VPackValue("options"));
|
||||
TRI_V8ToVPack(isolate, builder, args[3], true, true);
|
||||
builder.close();
|
||||
}
|
||||
|
||||
builder.close();
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
|
||||
GraphManager gmngr{vocbase};
|
||||
OperationResult r = gmngr.createGraph(builder.slice(), false);
|
||||
|
||||
if (r.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(r.errorNumber(), r.errorMessage());
|
||||
}
|
||||
|
||||
auto graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
VPackBuilder result;
|
||||
result.openObject();
|
||||
graph.get()->graphForClient(result);
|
||||
result.close();
|
||||
|
||||
TRI_V8_RETURN(TRI_VPackToV8(isolate, result.slice()));
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void JS_AddEdgeDefinitions(
|
||||
v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
if (args.Length() < 2) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE("_extendEdgeDefinitions(edgeDefinition)");
|
||||
}
|
||||
if (!args[0]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
std::string graphName = TRI_ObjectToString(args[0]);
|
||||
if (graphName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
|
||||
VPackBuilder edgeDefinition;
|
||||
TRI_V8ToVPack(isolate, edgeDefinition, args[1], false);
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
GraphManager gmngr{vocbase};
|
||||
auto graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
GraphOperations gops{*graph.get(), vocbase};
|
||||
OperationResult r = gops.addEdgeDefinition(edgeDefinition.slice(), false);
|
||||
|
||||
if (r.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(r.errorNumber(), r.errorMessage());
|
||||
}
|
||||
|
||||
graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
VPackBuilder result;
|
||||
result.openObject();
|
||||
graph.get()->graphForClient(result);
|
||||
result.close();
|
||||
|
||||
TRI_V8_RETURN(TRI_VPackToV8(isolate, result.slice()));
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void JS_EditEdgeDefinitions(
|
||||
v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
if (args.Length() < 2) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE("_editEdgeDefinitions(edgeDefinition)");
|
||||
}
|
||||
if (!args[0]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
std::string graphName = TRI_ObjectToString(args[0]);
|
||||
if (graphName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
|
||||
VPackBuilder edgeDefinition;
|
||||
TRI_V8ToVPack(isolate, edgeDefinition, args[1], false);
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
GraphManager gmngr{vocbase};
|
||||
auto graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
GraphOperations gops{*(graph.get()), vocbase};
|
||||
OperationResult r = gops.editEdgeDefinition(
|
||||
edgeDefinition.slice(), false,
|
||||
edgeDefinition.slice().get("collection").copyString());
|
||||
|
||||
if (r.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(r.errorNumber(), r.errorMessage());
|
||||
}
|
||||
|
||||
graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
VPackBuilder result;
|
||||
result.openObject();
|
||||
graph.get()->graphForClient(result);
|
||||
result.close();
|
||||
|
||||
TRI_V8_RETURN(TRI_VPackToV8(isolate, result.slice()));
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void JS_RemoveVertexCollection(
|
||||
v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
if (args.Length() < 2) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE(
|
||||
"_removeVertexCollection(vertexName, dropCollection)");
|
||||
}
|
||||
if (!args[0]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
if (!args[1]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE(
|
||||
"_removeVertexCollection(vertexName, dropCollection)");
|
||||
}
|
||||
std::string graphName = TRI_ObjectToString(args[0]);
|
||||
std::string vertexName = TRI_ObjectToString(args[1]);
|
||||
if (graphName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
if (vertexName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE(
|
||||
"_removeVertexCollection(vertexName, dropCollection)");
|
||||
}
|
||||
bool dropCollection = false;
|
||||
if (args.Length() >= 3) {
|
||||
dropCollection = TRI_ObjectToBoolean(args[2]);
|
||||
}
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
GraphManager gmngr{vocbase};
|
||||
auto graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
VPackBuilder builder;
|
||||
builder.openObject();
|
||||
builder.add("collection", VPackValue(vertexName));
|
||||
builder.close();
|
||||
|
||||
GraphOperations gops{*(graph.get()), vocbase};
|
||||
OperationResult r = gops.eraseOrphanCollection(false, vertexName, dropCollection);
|
||||
|
||||
if (r.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(r.errorNumber(), r.errorMessage());
|
||||
}
|
||||
|
||||
graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
VPackBuilder result;
|
||||
result.openObject();
|
||||
graph.get()->graphForClient(result);
|
||||
result.close();
|
||||
|
||||
TRI_V8_RETURN(TRI_VPackToV8(isolate, result.slice()));
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void JS_AddVertexCollection(
|
||||
v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
if (args.Length() < 2) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE(
|
||||
"_addVertexCollection(vertexName, createCollection)");
|
||||
}
|
||||
if (!args[0]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
if (!args[1]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE(
|
||||
"_addVertexCollection(vertexName, createCollection)");
|
||||
}
|
||||
std::string graphName = TRI_ObjectToString(args[0]);
|
||||
std::string vertexName = TRI_ObjectToString(args[1]);
|
||||
if (graphName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
if (vertexName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE(
|
||||
"_addVertexCollection(vertexName, createCollection)");
|
||||
}
|
||||
bool createCollection = true;
|
||||
if (args.Length() >= 3) {
|
||||
createCollection = TRI_ObjectToBoolean(args[2]);
|
||||
}
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
auto ctx = transaction::V8Context::Create(vocbase, false);
|
||||
|
||||
GraphManager gmngr{vocbase};
|
||||
auto graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
GraphOperations gops{*(graph.get()), vocbase};
|
||||
|
||||
VPackBuilder builder;
|
||||
builder.openObject();
|
||||
builder.add("collection", VPackValue(vertexName));
|
||||
builder.close();
|
||||
|
||||
OperationResult r =
|
||||
gops.addOrphanCollection(builder.slice(), false, createCollection);
|
||||
|
||||
if (r.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(r.errorNumber(), r.errorMessage());
|
||||
}
|
||||
|
||||
graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
VPackBuilder result;
|
||||
result.openObject();
|
||||
graph.get()->graphForClient(result);
|
||||
result.close();
|
||||
|
||||
TRI_V8_RETURN(TRI_VPackToV8(isolate, result.slice()));
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void JS_DropEdgeDefinition(
|
||||
v8::FunctionCallbackInfo<v8::Value> const& args) {
|
||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
if (args.Length() < 2) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE(
|
||||
"_deleteEdgeDefinition(edgeCollection, dropCollection)");
|
||||
}
|
||||
if (!args[0]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
if (!args[1]->IsString()) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE(
|
||||
"_deleteEdgeDefinition(edgeCollection, dropCollection)");
|
||||
}
|
||||
std::string graphName = TRI_ObjectToString(args[0]);
|
||||
std::string edgeDefinitionName = TRI_ObjectToString(args[1]);
|
||||
if (graphName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_GRAPH_CREATE_MISSING_NAME);
|
||||
}
|
||||
if (edgeDefinitionName.empty()) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE(
|
||||
"_deleteEdgeDefinition(edgeCollection, dropCollection)");
|
||||
}
|
||||
|
||||
bool dropCollections = false;
|
||||
if (args.Length() >= 3) {
|
||||
dropCollections = TRI_ObjectToBoolean(args[2]);
|
||||
}
|
||||
|
||||
auto& vocbase = GetContextVocBase(isolate);
|
||||
|
||||
GraphManager gmngr{vocbase};
|
||||
auto graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
GraphOperations gops{*(graph.get()), vocbase};
|
||||
OperationResult r =
|
||||
gops.eraseEdgeDefinition(false, edgeDefinitionName, dropCollections);
|
||||
|
||||
if (r.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(r.errorNumber(), r.errorMessage());
|
||||
}
|
||||
|
||||
graph = gmngr.lookupGraphByName(graphName);
|
||||
if (graph.fail()) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(graph.errorNumber(), graph.errorMessage());
|
||||
}
|
||||
TRI_ASSERT(graph.get() != nullptr);
|
||||
|
||||
VPackBuilder result;
|
||||
result.openObject();
|
||||
graph.get()->graphForClient(result);
|
||||
result.close();
|
||||
|
||||
TRI_V8_RETURN(TRI_VPackToV8(isolate, result.slice()));
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
static void InitV8GeneralGraphClass(v8::Handle<v8::Context> context,
|
||||
TRI_vocbase_t* vocbase, TRI_v8_global_t* v8g,
|
||||
v8::Isolate* isolate) {
|
||||
/* FULL API
|
||||
* _edgeCollections
|
||||
* _vertexCollections(bool excludeOrphans)
|
||||
* _EDGES
|
||||
* _INEDGES
|
||||
* _OUTEDGES
|
||||
* _edges
|
||||
* _vertices
|
||||
* _fromVertex(edgeId)
|
||||
* _toVertex(edgeId)
|
||||
* _getEdgeCollectionByName
|
||||
* _getVertexCollectionByName
|
||||
* _neighbors
|
||||
* _commonNeighbors
|
||||
* _countCommonNeighbors
|
||||
* _commonProperties
|
||||
* _countCommonProperties
|
||||
* _paths
|
||||
* _shortestPath
|
||||
* _distanceTo
|
||||
* _absoluteEccentricity
|
||||
* _farness
|
||||
* _absoluteCloseness
|
||||
* _eccentricity
|
||||
* _closeness
|
||||
* _absoluteBetweenness
|
||||
* _betweenness
|
||||
* _radius
|
||||
* _diameter
|
||||
* _orphanCollections
|
||||
* _renameVertexCollection
|
||||
* _getConnectingEdges
|
||||
*/
|
||||
|
||||
v8::Handle<v8::ObjectTemplate> rt;
|
||||
v8::Handle<v8::FunctionTemplate> ft;
|
||||
|
||||
ft = v8::FunctionTemplate::New(isolate);
|
||||
ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoGraph"));
|
||||
|
||||
rt = ft->InstanceTemplate();
|
||||
rt->SetInternalFieldCount(2);
|
||||
|
||||
TRI_AddMethodVocbase(isolate, rt,
|
||||
TRI_V8_ASCII_STRING(isolate, "_addVertexCollection"),
|
||||
JS_AddVertexCollection);
|
||||
TRI_AddMethodVocbase(isolate, rt,
|
||||
TRI_V8_ASCII_STRING(isolate, "_deleteEdgeDefinition"),
|
||||
JS_DropEdgeDefinition);
|
||||
TRI_AddMethodVocbase(isolate, rt,
|
||||
TRI_V8_ASCII_STRING(isolate, "_editEdgeDefinitions"),
|
||||
JS_EditEdgeDefinitions);
|
||||
TRI_AddMethodVocbase(isolate, rt,
|
||||
TRI_V8_ASCII_STRING(isolate, "_extendEdgeDefinitions"),
|
||||
JS_AddEdgeDefinitions);
|
||||
TRI_AddMethodVocbase(isolate, rt,
|
||||
TRI_V8_ASCII_STRING(isolate, "_removeVertexCollection"),
|
||||
JS_RemoveVertexCollection);
|
||||
|
||||
|
||||
|
||||
v8g->GeneralGraphTempl.Reset(isolate, rt);
|
||||
ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoGraphCtor"));
|
||||
TRI_AddGlobalFunctionVocbase(
|
||||
isolate, TRI_V8_ASCII_STRING(isolate, "ArangoGraphCtor"),
|
||||
ft->GetFunction(), true);
|
||||
|
||||
// TODO WE DO NOT NEED THIS. Update _create to return a graph object properly
|
||||
// register the global object
|
||||
v8::Handle<v8::Object> aa = rt->NewInstance();
|
||||
if (!aa.IsEmpty()) {
|
||||
TRI_AddGlobalVariableVocbase(
|
||||
isolate, TRI_V8_ASCII_STRING(isolate, "ArangoGraph"), aa);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_ENTERPRISE
|
||||
static void InitV8SmartGraphClass(v8::Handle<v8::Context> context,
|
||||
TRI_vocbase_t* vocbase, TRI_v8_global_t* v8g,
|
||||
v8::Isolate* isolate) {
|
||||
v8::Handle<v8::ObjectTemplate> rt;
|
||||
v8::Handle<v8::FunctionTemplate> ft;
|
||||
|
||||
ft = v8::FunctionTemplate::New(isolate);
|
||||
ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoSmartGraph"));
|
||||
|
||||
rt = ft->InstanceTemplate();
|
||||
rt->SetInternalFieldCount(2);
|
||||
|
||||
TRI_AddMethodVocbase(isolate, rt,
|
||||
TRI_V8_ASCII_STRING(isolate, "_addVertexCollection"),
|
||||
JS_AddVertexCollection);
|
||||
|
||||
TRI_AddMethodVocbase(isolate, rt,
|
||||
TRI_V8_ASCII_STRING(isolate, "_deleteEdgeDefinition"),
|
||||
JS_DropEdgeDefinition);
|
||||
|
||||
TRI_AddMethodVocbase(isolate, rt,
|
||||
TRI_V8_ASCII_STRING(isolate, "_editEdgeDefinitions"),
|
||||
JS_EditEdgeDefinitions);
|
||||
|
||||
TRI_AddMethodVocbase(isolate, rt,
|
||||
TRI_V8_ASCII_STRING(isolate, "_extendEdgeDefinitions"),
|
||||
JS_AddEdgeDefinitions);
|
||||
|
||||
TRI_AddMethodVocbase(isolate, rt,
|
||||
TRI_V8_ASCII_STRING(isolate, "_removeVertexCollection"),
|
||||
JS_RemoveVertexCollection);
|
||||
|
||||
v8g->SmartGraphTempl.Reset(isolate, rt);
|
||||
ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoSmartGraphCtor"));
|
||||
TRI_AddGlobalFunctionVocbase(
|
||||
isolate, TRI_V8_ASCII_STRING(isolate, "ArangoSmartGraphCtor"),
|
||||
ft->GetFunction(), true);
|
||||
|
||||
// register the global object
|
||||
v8::Handle<v8::Object> aa = rt->NewInstance();
|
||||
if (!aa.IsEmpty()) {
|
||||
TRI_AddGlobalVariableVocbase(
|
||||
isolate, TRI_V8_ASCII_STRING(isolate, "ArangoSmartGraph"), aa);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void InitV8GeneralGraphModule(v8::Handle<v8::Context> context,
|
||||
TRI_vocbase_t* vocbase, TRI_v8_global_t* v8g,
|
||||
v8::Isolate* isolate) {
|
||||
/* These functions still have a JS only implementation
|
||||
* JS ONLY:
|
||||
* _edgeDefinitions
|
||||
* _extendEdgeDefinitions
|
||||
* _relation
|
||||
* _registerCompatibilityFunctions
|
||||
*/
|
||||
|
||||
/* TODO
|
||||
* _create // SG => Potentially returns SG
|
||||
* _graph // SG => Potentially returns SG
|
||||
*/
|
||||
v8::Handle<v8::ObjectTemplate> rt;
|
||||
v8::Handle<v8::FunctionTemplate> ft;
|
||||
ft = v8::FunctionTemplate::New(isolate);
|
||||
ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoGeneralGraphModule"));
|
||||
rt = ft->InstanceTemplate();
|
||||
rt->SetInternalFieldCount(0);
|
||||
|
||||
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "_create"),
|
||||
JS_CreateGraph);
|
||||
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "_drop"),
|
||||
JS_DropGraph);
|
||||
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "_exists"),
|
||||
JS_GraphExists);
|
||||
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "_graph"),
|
||||
JS_GetGraph);
|
||||
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "_list"),
|
||||
JS_GetGraphKeys);
|
||||
TRI_AddMethodVocbase(
|
||||
isolate, rt, TRI_V8_ASCII_STRING(isolate, "_listObjects"), JS_GetGraphs);
|
||||
TRI_AddMethodVocbase(isolate, rt,
|
||||
TRI_V8_ASCII_STRING(isolate, "_renameCollection"),
|
||||
JS_RenameGraphCollection);
|
||||
|
||||
v8g->GeneralGraphModuleTempl.Reset(isolate, rt);
|
||||
ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoGeneralGraphModuleCtor"));
|
||||
TRI_AddGlobalFunctionVocbase(
|
||||
isolate, TRI_V8_ASCII_STRING(isolate, "ArangoGeneralGraphModuleCtor"),
|
||||
ft->GetFunction(), true);
|
||||
|
||||
// register the global object
|
||||
v8::Handle<v8::Object> aa = rt->NewInstance();
|
||||
if (!aa.IsEmpty()) {
|
||||
TRI_AddGlobalVariableVocbase(
|
||||
isolate, TRI_V8_ASCII_STRING(isolate, "ArangoGeneralGraphModule"), aa);
|
||||
}
|
||||
}
|
||||
|
||||
void TRI_InitV8GeneralGraph(v8::Handle<v8::Context> context,
|
||||
TRI_vocbase_t* vocbase, TRI_v8_global_t* v8g,
|
||||
v8::Isolate* isolate) {
|
||||
InitV8GeneralGraphModule(context, vocbase, v8g, isolate);
|
||||
InitV8GeneralGraphClass(context, vocbase, v8g, isolate);
|
||||
#ifdef USE_ENTERPRISE
|
||||
InitV8SmartGraphClass(context, vocbase, v8g, isolate);
|
||||
#endif
|
||||
|
||||
}
|
|
@ -18,32 +18,19 @@
|
|||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Michael Hackstein
|
||||
/// @author Heiko Kernbach
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_VOCBASE_GRAPHS_H
|
||||
#define ARANGOD_VOCBASE_GRAPHS_H 1
|
||||
#ifndef ARANGOD_V8_SERVER_V8_GENERAL_GRAPH_H
|
||||
#define ARANGOD_V8_SERVER_V8_GENERAL_GRAPH_H 1
|
||||
|
||||
#include "VocBase/vocbase.h"
|
||||
#include <v8.h>
|
||||
|
||||
namespace arangodb {
|
||||
namespace aql {
|
||||
class Graph;
|
||||
}
|
||||
struct TRI_vocbase_t;
|
||||
struct TRI_v8_global_t;
|
||||
|
||||
namespace transaction {
|
||||
class Context;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get an instance of Graph by Name.
|
||||
/// returns nullptr if graph is not existing
|
||||
/// The caller has to take care for the memory.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::Graph* lookupGraphByName(std::shared_ptr<transaction::Context>, std::string const& name);
|
||||
|
||||
} // namespace arangodb
|
||||
void TRI_InitV8GeneralGraph(v8::Handle<v8::Context> context,
|
||||
TRI_vocbase_t* vocbase, TRI_v8_global_t* v8g,
|
||||
v8::Isolate* isolate);
|
||||
|
||||
#endif
|
||||
|
|
@ -79,6 +79,7 @@
|
|||
#include "V8Server/v8-views.h"
|
||||
#include "V8Server/v8-voccursor.h"
|
||||
#include "V8Server/v8-vocindex.h"
|
||||
#include "V8Server/v8-general-graph.h"
|
||||
#include "VocBase/KeyGenerator.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/Methods/Databases.h"
|
||||
|
@ -2068,6 +2069,7 @@ void TRI_InitV8VocBridge(
|
|||
TRI_InitV8Collections(context, &vocbase, v8g, isolate, ArangoNS);
|
||||
TRI_InitV8Views(context, &vocbase, v8g, isolate, ArangoNS);
|
||||
TRI_InitV8Users(context, &vocbase, v8g, isolate);
|
||||
TRI_InitV8GeneralGraph(context, &vocbase, v8g, isolate);
|
||||
|
||||
TRI_InitV8cursor(context, v8g);
|
||||
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Michael Hackstein
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Graphs.h"
|
||||
|
||||
#include "Aql/Graphs.h"
|
||||
#include "Basics/StaticStrings.h"
|
||||
#include "Cluster/ClusterMethods.h"
|
||||
#include "Utils/OperationOptions.h"
|
||||
#include "Utils/SingleCollectionTransaction.h"
|
||||
#include "Transaction/Context.h"
|
||||
#include <sstream>
|
||||
using namespace arangodb;
|
||||
|
||||
#ifndef USE_ENTERPRISE
|
||||
std::string const GRAPHS = "_graphs";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Load a graph from the _graphs collection; local and coordinator way
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::Graph* arangodb::lookupGraphByName(std::shared_ptr<transaction::Context> transactionContext,
|
||||
std::string const& name) {
|
||||
SingleCollectionTransaction trx(transactionContext, GRAPHS, AccessMode::Type::READ);
|
||||
|
||||
Result res = trx.begin();
|
||||
|
||||
if (!res.ok()) {
|
||||
std::stringstream ss;
|
||||
ss << "while looking up graph '" << name << "': " << res.errorMessage();
|
||||
res.reset(res.errorNumber(), ss.str());
|
||||
THROW_ARANGO_EXCEPTION(res);
|
||||
}
|
||||
VPackBuilder b;
|
||||
{
|
||||
VPackObjectBuilder guard(&b);
|
||||
b.add(StaticStrings::KeyString, VPackValue(name));
|
||||
}
|
||||
|
||||
// Default options are enough here
|
||||
OperationOptions options;
|
||||
|
||||
OperationResult result = trx.document(GRAPHS, b.slice(), options);
|
||||
|
||||
// Commit or abort.
|
||||
res = trx.finish(result.result);
|
||||
|
||||
if (result.fail()) {
|
||||
THROW_ARANGO_EXCEPTION_FORMAT(result.errorNumber(), "while looking up graph '%s'",
|
||||
name.c_str());
|
||||
}
|
||||
if (res.fail()) {
|
||||
std::stringstream ss;
|
||||
ss << "while looking up graph '" << name << "': " << res.errorMessage();
|
||||
res.reset(res.errorNumber(), ss.str());
|
||||
THROW_ARANGO_EXCEPTION(res);
|
||||
}
|
||||
|
||||
VPackSlice info = result.slice();
|
||||
if (info.isExternal()) {
|
||||
info = info.resolveExternal();
|
||||
}
|
||||
|
||||
return new arangodb::aql::Graph(info);
|
||||
}
|
||||
#endif
|
|
@ -445,7 +445,7 @@ static int RenameGraphCollections(TRI_vocbase_t* vocbase,
|
|||
}
|
||||
|
||||
StringBuffer buffer(true);
|
||||
buffer.appendText("require('@arangodb/general-graph')._renameCollection(");
|
||||
buffer.appendText("require('@arangodb/general-graph-common')._renameCollection(");
|
||||
buffer.appendJsonEncoded(oldName.c_str(), oldName.size());
|
||||
buffer.appendChar(',');
|
||||
buffer.appendJsonEncoded(newName.c_str(), newName.size());
|
||||
|
|
|
@ -655,7 +655,7 @@
|
|||
} else {
|
||||
newCollectionObject.isSmart = true;
|
||||
newCollectionObject.options = {
|
||||
numberOfShards: $('#new-numberOfShards').val(),
|
||||
numberOfShards: parseInt($('#new-numberOfShards').val()),
|
||||
smartGraphAttribute: $('#new-smartGraphAttribute').val(),
|
||||
replicationFactor: parseInt($('#new-replicationFactor').val())
|
||||
};
|
||||
|
@ -664,15 +664,15 @@
|
|||
if (frontendConfig.isCluster) {
|
||||
if ($('#general-numberOfShards').val().length > 0) {
|
||||
newCollectionObject.options = {
|
||||
numberOfShards: $('#general-numberOfShards').val()
|
||||
numberOfShards: parseInt($('#general-numberOfShards').val())
|
||||
};
|
||||
}
|
||||
if ($('#general-replicationFactor').val().length > 0) {
|
||||
if (newCollectionObject.options) {
|
||||
newCollectionObject.options.replicationFactor = $('#general-replicationFactor').val();
|
||||
newCollectionObject.options.replicationFactor = parseInt($('#general-replicationFactor').val());
|
||||
} else {
|
||||
newCollectionObject.options = {
|
||||
replicationFactor: $('#general-replicationFactor').val()
|
||||
replicationFactor: parseInt($('#general-replicationFactor').val())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"name": "gharial",
|
||||
"description": "ArangoDB Graph Module",
|
||||
"author": "ArangoDB GmbH",
|
||||
"version": "3.0.0",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
"engines": {
|
||||
"arangodb": "^3.0.0-0 || ^3.0.0"
|
||||
},
|
||||
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/arangodb/arangodb.git"
|
||||
},
|
||||
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Michael Hackstein",
|
||||
"email": "m.hackstein@arangodb.com"
|
||||
}
|
||||
],
|
||||
|
||||
"main": "gharial.js"
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
'use strict';
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief Replication management
|
||||
// /
|
||||
// / @file
|
||||
// /
|
||||
// / DISCLAIMER
|
||||
// /
|
||||
// / Copyright 2012 triagens GmbH, Cologne, Germany
|
||||
// /
|
||||
// / Licensed under the Apache License, Version 2.0 (the "License")
|
||||
// / you may not use this file except in compliance with the License.
|
||||
// / You may obtain a copy of the License at
|
||||
// /
|
||||
// / http://www.apache.org/licenses/LICENSE-2.0
|
||||
// /
|
||||
// / Unless required by applicable law or agreed to in writing, software
|
||||
// / distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// / WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// / See the License for the specific language governing permissions and
|
||||
// / limitations under the License.
|
||||
// /
|
||||
// / Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
// /
|
||||
// / @author Heiko Kernbach
|
||||
// / @author Copyright 2018, ArangoDB GmbH, Cologne, Germany
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const internal = require('internal');
|
||||
const arangosh = require('@arangodb/arangosh');
|
||||
const ggc = require('@arangodb/general-graph-common');
|
||||
const _ = require('lodash');
|
||||
|
||||
const db = internal.db;
|
||||
|
||||
const GRAPH_PREFIX = '_api/gharial/';
|
||||
|
||||
// remove me later
|
||||
exports._exists = ggc._exists;
|
||||
|
||||
// TODO There are several db._flushCache() calls here, whenever gharial might
|
||||
// have added or dropped collections. Maybe this should be called even when
|
||||
// the request has failed (in which case now it isn't, because an exception is
|
||||
// thrown first).
|
||||
|
||||
exports._listObjects = function () {
|
||||
const uri = GRAPH_PREFIX;
|
||||
const requestResult = arangosh.checkRequestResult(db._connection.GET(uri));
|
||||
return requestResult.graphs;
|
||||
};
|
||||
|
||||
exports._list = function () {
|
||||
const uri = GRAPH_PREFIX;
|
||||
const requestResult = arangosh.checkRequestResult(db._connection.GET(uri));
|
||||
const graphs = requestResult.graphs;
|
||||
|
||||
const result = [];
|
||||
_.each(graphs, function (graph) {
|
||||
result.push(graph._key);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
// inherited graph class
|
||||
const CommonGraph = ggc.__GraphClass;
|
||||
|
||||
CommonGraph.prototype.__updateDefinitions = function (edgeDefs, orphans) {
|
||||
this.__edgeDefinitions = edgeDefs;
|
||||
this.__orphanCollections = orphans;
|
||||
};
|
||||
|
||||
CommonGraph.prototype._extendEdgeDefinitions = function (edgeDefinition) {
|
||||
const data = edgeDefinition || {};
|
||||
const uri = GRAPH_PREFIX + encodeURIComponent(this.__name) + "/edge";
|
||||
const requestResult = arangosh.checkRequestResult(db._connection.POST(uri, JSON.stringify(data)));
|
||||
const graph = requestResult.graph;
|
||||
try {
|
||||
this.__updateDefinitions(graph.edgeDefinitions, graph.orphanCollections);
|
||||
} catch (ignore) {
|
||||
}
|
||||
};
|
||||
|
||||
CommonGraph.prototype._editEdgeDefinitions = function (edgeDefinition) {
|
||||
const data = edgeDefinition || {};
|
||||
const uri = GRAPH_PREFIX + encodeURIComponent(this.__name) + "/edge/" + edgeDefinition.collection;
|
||||
const requestResult = arangosh.checkRequestResult(db._connection.PUT(uri, JSON.stringify(data)));
|
||||
const graph = requestResult.graph;
|
||||
try {
|
||||
this.__updateDefinitions(graph.edgeDefinitions, graph.orphanCollections);
|
||||
} catch (ignore) {
|
||||
}
|
||||
};
|
||||
|
||||
CommonGraph.prototype._addVertexCollection = function (name, createCollection) {
|
||||
const data = {};
|
||||
if (name) {
|
||||
data.collection = name;
|
||||
}
|
||||
let uri = GRAPH_PREFIX + encodeURIComponent(this.__name) + "/vertex";
|
||||
if (createCollection !== false) {
|
||||
uri += "?createCollection=true";
|
||||
} else {
|
||||
uri += "?createCollection=false";
|
||||
}
|
||||
const requestResult = arangosh.checkRequestResult(db._connection.POST(uri, JSON.stringify(data)));
|
||||
const graph = requestResult.graph;
|
||||
|
||||
try {
|
||||
this.__updateDefinitions(graph.edgeDefinitions, graph.orphanCollections);
|
||||
} catch (ignore) {
|
||||
}
|
||||
|
||||
if (createCollection !== false) {
|
||||
db._flushCache();
|
||||
}
|
||||
};
|
||||
|
||||
CommonGraph.prototype._removeVertexCollection = function (name, dropCollection) {
|
||||
let uri = GRAPH_PREFIX + encodeURIComponent(this.__name) + "/vertex/" + encodeURIComponent(name);
|
||||
if (dropCollection === true) {
|
||||
uri += "?dropCollections=true";
|
||||
} else {
|
||||
uri += "?dropCollections=false";
|
||||
}
|
||||
const requestResult = arangosh.checkRequestResult(db._connection.DELETE(uri));
|
||||
const graph = requestResult.graph;
|
||||
|
||||
try {
|
||||
this.__updateDefinitions(graph.edgeDefinitions, graph.orphanCollections);
|
||||
} catch (ignore) {
|
||||
}
|
||||
|
||||
if (dropCollection === true) {
|
||||
db._flushCache();
|
||||
}
|
||||
};
|
||||
|
||||
CommonGraph.prototype._deleteEdgeDefinition = function (name, dropCollection = false) {
|
||||
let uri = GRAPH_PREFIX + encodeURIComponent(this.__name) + "/edge/" + encodeURIComponent(name);
|
||||
if (dropCollection === true) {
|
||||
uri += "?dropCollections=true";
|
||||
} else {
|
||||
uri += "?dropCollections=false";
|
||||
}
|
||||
|
||||
const requestResult = arangosh.checkRequestResult(db._connection.DELETE(uri));
|
||||
const graph = requestResult.graph;
|
||||
|
||||
try {
|
||||
this.__updateDefinitions(graph.edgeDefinitions, graph.orphanCollections);
|
||||
} catch (ignore) {
|
||||
}
|
||||
|
||||
if (dropCollection === true) {
|
||||
db._flushCache();
|
||||
}
|
||||
};
|
||||
|
||||
exports._graph = function (graphName) {
|
||||
const uri = GRAPH_PREFIX + encodeURIComponent(graphName);
|
||||
const requestResult = arangosh.checkRequestResult(db._connection.GET(uri));
|
||||
return new CommonGraph(requestResult.graph);
|
||||
};
|
||||
|
||||
exports._create = function (name, edgeDefinitions, orphans, options) {
|
||||
const data = {};
|
||||
if (name) {
|
||||
data.name = name;
|
||||
}
|
||||
if (edgeDefinitions) {
|
||||
data.edgeDefinitions = edgeDefinitions;
|
||||
}
|
||||
if (orphans) {
|
||||
data.orphanCollections = orphans;
|
||||
}
|
||||
if (options) {
|
||||
data.options = options;
|
||||
}
|
||||
|
||||
const uri = GRAPH_PREFIX;
|
||||
const requestResult = arangosh.checkRequestResult(db._connection.POST(uri, JSON.stringify(data)));
|
||||
db._flushCache();
|
||||
return new CommonGraph(requestResult.graph);
|
||||
};
|
||||
|
||||
exports._drop = function (graphName, dropCollections) {
|
||||
|
||||
let uri = GRAPH_PREFIX + encodeURIComponent(graphName);
|
||||
if (dropCollections) {
|
||||
uri += "?dropCollections=true";
|
||||
}
|
||||
const requestResult = arangosh.checkRequestResult(db._connection.DELETE(uri));
|
||||
if (dropCollections) {
|
||||
db._flushCache();
|
||||
}
|
||||
return requestResult.result;
|
||||
};
|
||||
|
||||
// js based helper functions
|
||||
exports.__GraphClass = CommonGraph;
|
||||
exports._edgeDefinitions = ggc._edgeDefinitions;
|
||||
exports._extendEdgeDefinitions = ggc._extendEdgeDefinitions;
|
||||
exports._relation = ggc._relation;
|
||||
exports._registerCompatibilityFunctions = ggc._registerCompatibilityFunctions;
|
|
@ -24,15 +24,17 @@
|
|||
// / @author Michael Hackstein
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const expect = require('chai').expect;
|
||||
const chai = require('chai');
|
||||
const expect = chai.expect;
|
||||
chai.Assertion.addProperty('does', function () { return this; });
|
||||
|
||||
const arangodb = require('@arangodb');
|
||||
const request = require('@arangodb/request');
|
||||
|
||||
const ERRORS = arangodb.errors;
|
||||
const db = arangodb.db;
|
||||
const wait = require('internal').wait;
|
||||
const extend = require('lodash').extend;
|
||||
const internal = require('internal');
|
||||
const wait = internal.wait;
|
||||
|
||||
describe('_api/gharial', () => {
|
||||
|
||||
|
@ -314,4 +316,296 @@ describe('_api/gharial', () => {
|
|||
expect(db._collection(vName)).to.not.be.null;
|
||||
});
|
||||
|
||||
it('should check if edges can only be created if their _from and _to vertices are existent - should NOT create - invalid from', () => {
|
||||
const examples = require('@arangodb/graph-examples/example-graph');
|
||||
const exampleGraphName = 'knows_graph';
|
||||
const vName = 'persons';
|
||||
const eName = 'knows';
|
||||
expect(db._collection(eName)).to.be.null; // edgec
|
||||
expect(db._collection(vName)).to.be.null; // vertexc
|
||||
const g = examples.loadGraph(exampleGraphName);
|
||||
expect(g).to.not.be.null;
|
||||
|
||||
const edgeDef = {
|
||||
_from: 'peter',
|
||||
_to: 'persons/charlie'
|
||||
};
|
||||
let req = request.post(url + '/' + exampleGraphName + '/edge/knows', {
|
||||
body: JSON.stringify(edgeDef)
|
||||
});
|
||||
expect(req.statusCode).to.equal(400);
|
||||
expect(req.json.errorNum).to.equal(ERRORS.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code);
|
||||
|
||||
expect(db._collection(eName)).to.not.be.null;
|
||||
expect(db._collection(vName)).to.not.be.null;
|
||||
});
|
||||
|
||||
it('should check if edges can only be created if their _from and _to vertices are existent - should NOT create - invalid to', () => {
|
||||
const examples = require('@arangodb/graph-examples/example-graph');
|
||||
const exampleGraphName = 'knows_graph';
|
||||
const vName = 'persons';
|
||||
const eName = 'knows';
|
||||
expect(db._collection(eName)).to.be.null; // edgec
|
||||
expect(db._collection(vName)).to.be.null; // vertexc
|
||||
const g = examples.loadGraph(exampleGraphName);
|
||||
expect(g).to.not.be.null;
|
||||
|
||||
const edgeDef = {
|
||||
_from: 'persons/peter',
|
||||
_to: 'charlie'
|
||||
};
|
||||
let req = request.post(url + '/' + exampleGraphName + '/edge/knows', {
|
||||
body: JSON.stringify(edgeDef)
|
||||
});
|
||||
expect(req.statusCode).to.equal(400);
|
||||
expect(req.json.errorNum).to.equal(ERRORS.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code);
|
||||
|
||||
expect(db._collection(eName)).to.not.be.null;
|
||||
expect(db._collection(vName)).to.not.be.null;
|
||||
});
|
||||
|
||||
it('should check if edges can only be created if their _from and _to vertices are existent - should NOT create - invalid from and to attributes', () => {
|
||||
const examples = require('@arangodb/graph-examples/example-graph');
|
||||
const exampleGraphName = 'knows_graph';
|
||||
const vName = 'persons';
|
||||
const eName = 'knows';
|
||||
expect(db._collection(eName)).to.be.null; // edgec
|
||||
expect(db._collection(vName)).to.be.null; // vertexc
|
||||
const g = examples.loadGraph(exampleGraphName);
|
||||
expect(g).to.not.be.null;
|
||||
|
||||
const edgeDef = {
|
||||
_from: 'peter',
|
||||
_to: 'charlie'
|
||||
};
|
||||
let req = request.post(url + '/' + exampleGraphName + '/edge/knows', {
|
||||
body: JSON.stringify(edgeDef)
|
||||
});
|
||||
expect(req.statusCode).to.equal(400);
|
||||
expect(req.json.errorNum).to.equal(ERRORS.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code);
|
||||
|
||||
expect(db._collection(eName)).to.not.be.null;
|
||||
expect(db._collection(vName)).to.not.be.null;
|
||||
});
|
||||
|
||||
it('should check if edges can only be created if their _from and _to vertices are existent - should NOT create - missing from and to attributes', () => {
|
||||
const examples = require('@arangodb/graph-examples/example-graph');
|
||||
const exampleGraphName = 'knows_graph';
|
||||
const vName = 'persons';
|
||||
const eName = 'knows';
|
||||
expect(db._collection(eName)).to.be.null; // edgec
|
||||
expect(db._collection(vName)).to.be.null; // vertexc
|
||||
const g = examples.loadGraph(exampleGraphName);
|
||||
expect(g).to.not.be.null;
|
||||
|
||||
const edgeDef = {
|
||||
};
|
||||
let req = request.post(url + '/' + exampleGraphName + '/edge/knows', {
|
||||
body: JSON.stringify(edgeDef)
|
||||
});
|
||||
expect(req.statusCode).to.equal(400);
|
||||
expect(req.json.errorNum).to.equal(ERRORS.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code);
|
||||
|
||||
expect(db._collection(eName)).to.not.be.null;
|
||||
expect(db._collection(vName)).to.not.be.null;
|
||||
});
|
||||
|
||||
it('should check if incident edges are deleted with a vertex', () => {
|
||||
const examples = require('@arangodb/graph-examples/example-graph');
|
||||
const exampleGraphName = 'knows_graph';
|
||||
const vName = 'persons';
|
||||
const eName = 'knows';
|
||||
// vertices
|
||||
const alice = 'alice';
|
||||
const bob = 'bob';
|
||||
const eve = 'eve';
|
||||
|
||||
expect(db._collection(eName)).to.be.null;
|
||||
expect(db._collection(vName)).to.be.null;
|
||||
// load graph
|
||||
const g = examples.loadGraph(exampleGraphName);
|
||||
expect(g).to.not.be.null;
|
||||
expect(db._collection(eName)).to.not.be.null;
|
||||
expect(db._collection(vName)).to.not.be.null;
|
||||
|
||||
// pre-check that the expected edges are there
|
||||
expect(db[eName].all().toArray().length).to.equal(5);
|
||||
|
||||
// delete vertex bob
|
||||
const res = request.delete(
|
||||
`${url}/${exampleGraphName}/vertex/${vName}/${bob}`
|
||||
);
|
||||
|
||||
// check response
|
||||
expect(res).to.be.an.instanceof(request.Response);
|
||||
expect(res.body).to.be.a('string');
|
||||
const body = JSON.parse(res.body);
|
||||
// 202 without waitForSync (default)
|
||||
expect(body).to.eql({
|
||||
error: false,
|
||||
code: 202,
|
||||
removed: true
|
||||
});
|
||||
|
||||
// check that all edges incident to bob were removed as well
|
||||
expect(db[eName].all().toArray().length).to.equal(1);
|
||||
|
||||
// check that the remaining edge is the expected one
|
||||
const eveKnowsAlice = db[eName].all().toArray()[0];
|
||||
expect(eveKnowsAlice).to.have.all.keys(
|
||||
['_key', '_id', '_rev', '_from', '_to', 'vertex']
|
||||
);
|
||||
expect(eveKnowsAlice).to.include({
|
||||
_from: `${vName}/${eve}`,
|
||||
_to: `${vName}/${alice}`,
|
||||
vertex: eve
|
||||
});
|
||||
});
|
||||
|
||||
it('should check that non-graph incident edges are not deleted with a' +
|
||||
' vertex', () => {
|
||||
const examples = require('@arangodb/graph-examples/example-graph');
|
||||
const exampleGraphName = 'knows_graph';
|
||||
const vName = 'persons';
|
||||
const eName = 'knows';
|
||||
// vertices
|
||||
const alice = 'alice';
|
||||
const bob = 'bob';
|
||||
const charlie = 'charlie';
|
||||
const dave = 'dave';
|
||||
const eve = 'eve';
|
||||
|
||||
expect(db._collection(eName)).to.be.null;
|
||||
expect(db._collection(vName)).to.be.null;
|
||||
// load graph
|
||||
const g = examples.loadGraph(exampleGraphName);
|
||||
expect(g).to.not.be.null;
|
||||
expect(db._collection(eName)).to.not.be.null;
|
||||
expect(db._collection(vName)).to.not.be.null;
|
||||
|
||||
const ngEdges = db._create(eColName);
|
||||
ngEdges.insert({
|
||||
_from: `${vName}/${bob}`,
|
||||
_to: `${vName}/${charlie}`,
|
||||
name: 'bob->charlie'
|
||||
});
|
||||
ngEdges.insert({
|
||||
_from: `${vName}/${dave}`,
|
||||
_to: `${vName}/${bob}`,
|
||||
name: 'dave->bob'
|
||||
});
|
||||
|
||||
// pre-check that the expected edges are there
|
||||
expect(db[eName].all().toArray().length).to.equal(5);
|
||||
|
||||
// delete vertex bob
|
||||
const res = request.delete(
|
||||
`${url}/${exampleGraphName}/vertex/${vName}/${bob}`
|
||||
);
|
||||
|
||||
// check response
|
||||
expect(res).to.be.an.instanceof(request.Response);
|
||||
expect(res.body).to.be.a('string');
|
||||
const body = JSON.parse(res.body);
|
||||
// 202 without waitForSync (default)
|
||||
expect(body).to.eql({
|
||||
error: false,
|
||||
code: 202,
|
||||
removed: true
|
||||
});
|
||||
|
||||
// check that the edges outside of g are still there
|
||||
let remainingEdges = ngEdges.all().toArray();
|
||||
expect(remainingEdges.length).to.equal(2);
|
||||
expect(remainingEdges.map(x => x.name))
|
||||
.to.have.members(['bob->charlie', 'dave->bob']);
|
||||
});
|
||||
|
||||
// TODO deleting a vertex via the graph api should probably delete all
|
||||
// edges that are in any graph's edge collection, not only the "current"
|
||||
// graph. Decide this and write a test.
|
||||
|
||||
it('should check that edges can be replaced', () => {
|
||||
const examples = require('@arangodb/graph-examples/example-graph');
|
||||
const exampleGraphName = 'knows_graph';
|
||||
const vName = 'persons';
|
||||
const eName = 'knows';
|
||||
expect(db._collection(eName)).to.be.null; // edgec
|
||||
expect(db._collection(vName)).to.be.null; // vertexc
|
||||
const g = examples.loadGraph(exampleGraphName);
|
||||
expect(g).to.not.be.null;
|
||||
expect(db._collection(eName)).to.not.be.null;
|
||||
expect(db._collection(vName)).to.not.be.null;
|
||||
|
||||
const e = db.knows.any();
|
||||
|
||||
const newEdge = Object.assign({}, e);
|
||||
newEdge.newAttribute = 'new value';
|
||||
|
||||
const res = request.put(
|
||||
`${url}/${exampleGraphName}/edge/${eName}/${e._key}`,
|
||||
{body: JSON.stringify(newEdge)}
|
||||
);
|
||||
|
||||
// 202 without waitForSync (default)
|
||||
expect(res.statusCode).to.equal(202);
|
||||
expect(res.json.code).to.equal(202);
|
||||
expect(res.json.error).to.equal(false);
|
||||
expect(res.json.edge._key).to.equal(e._key);
|
||||
|
||||
expect(db.knows.document(e._key))
|
||||
.to.be.an('object')
|
||||
.that.has.property('newAttribute')
|
||||
.which.equals('new value');
|
||||
});
|
||||
|
||||
it('should check that edges can NOT be replaced if their _from or _to' +
|
||||
' attribute is missing', () => {
|
||||
const examples = require('@arangodb/graph-examples/example-graph');
|
||||
const exampleGraphName = 'knows_graph';
|
||||
const vName = 'persons';
|
||||
const eName = 'knows';
|
||||
expect(db._collection(eName)).to.be.null; // edgec
|
||||
expect(db._collection(vName)).to.be.null; // vertexc
|
||||
const g = examples.loadGraph(exampleGraphName);
|
||||
expect(g).to.not.be.null;
|
||||
expect(db._collection(eName)).to.not.be.null;
|
||||
expect(db._collection(vName)).to.not.be.null;
|
||||
|
||||
const e = db.knows.any();
|
||||
|
||||
let newEdge;
|
||||
let newEdges = {};
|
||||
newEdge = newEdges['_from missing'] = Object.assign({new: "new"}, e);
|
||||
delete newEdge._from;
|
||||
newEdge = newEdges['_to missing'] = Object.assign({new: "new"}, e);
|
||||
delete newEdge._to;
|
||||
newEdge = newEdges['_from and _to missing'] = Object.assign({new: "new"}, e);
|
||||
delete newEdge._from;
|
||||
delete newEdge._to;
|
||||
|
||||
|
||||
for (let key in newEdges) {
|
||||
if (!newEdges.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
const description = key;
|
||||
const newEdge = newEdges[key];
|
||||
|
||||
const res = request.put(
|
||||
`${url}/${exampleGraphName}/edge/${eName}/${e._key}`,
|
||||
{body: JSON.stringify(newEdge)}
|
||||
);
|
||||
|
||||
expect(res.statusCode, description).to.equal(400);
|
||||
expect(res.json.errorNum, description)
|
||||
.to.equal(ERRORS.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code);
|
||||
}
|
||||
|
||||
expect(db.knows.document(e._key))
|
||||
.to.be.an('object')
|
||||
.that.does.not.have.property('new');
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -286,6 +286,10 @@
|
|||
"ERROR_GRAPH_COLLECTION_USED_IN_ORPHANS" : { "code" : 1938, "message" : "collection used in orphans" },
|
||||
"ERROR_GRAPH_EDGE_COL_DOES_NOT_EXIST" : { "code" : 1939, "message" : "edge collection does not exist or is not part of the graph" },
|
||||
"ERROR_GRAPH_EMPTY" : { "code" : 1940, "message" : "empty graph" },
|
||||
"ERROR_GRAPH_INTERNAL_DATA_CORRUPT" : { "code" : 1941, "message" : "internal graph data corrupt" },
|
||||
"ERROR_GRAPH_INTERNAL_EDGE_COLLECTION_ALREADY_SET" : { "code" : 1942, "message" : "edge collection already set" },
|
||||
"ERROR_GRAPH_CREATE_MALFORMED_ORPHAN_LIST" : { "code" : 1943, "message" : "malformed orphan list" },
|
||||
"ERROR_GRAPH_EDGE_DEFINITION_IS_DOCUMENT" : { "code" : 1944, "message" : "edge definition collection is a document collection" },
|
||||
"ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
|
||||
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
|
||||
"SIMPLE_CLIENT_UNKNOWN_ERROR" : { "code" : 2000, "message" : "unknown client error" },
|
||||
|
@ -316,6 +320,7 @@
|
|||
"ERROR_CANNOT_DROP_SMART_COLLECTION" : { "code" : 4002, "message" : "cannot drop this smart collection" },
|
||||
"ERROR_KEY_MUST_BE_PREFIXED_WITH_SMART_GRAPH_ATTRIBUTE" : { "code" : 4003, "message" : "in smart vertex collections _key must be prefixed with the value of the smart graph attribute" },
|
||||
"ERROR_ILLEGAL_SMART_GRAPH_ATTRIBUTE" : { "code" : 4004, "message" : "attribute cannot be used as smart graph attribute" },
|
||||
"ERROR_SMART_GRAPH_ATTRIBUTE_MISMATCH" : { "code" : 4005, "message" : "smart graph attribute mismatch" },
|
||||
"ERROR_CLUSTER_REPAIRS_FAILED" : { "code" : 5000, "message" : "error during cluster repairs" },
|
||||
"ERROR_CLUSTER_REPAIRS_NOT_ENOUGH_HEALTHY" : { "code" : 5001, "message" : "not enough (healthy) db servers" },
|
||||
"ERROR_CLUSTER_REPAIRS_REPLICATION_FACTOR_VIOLATED" : { "code" : 5002, "message" : "replication factor violated during cluster repairs" },
|
||||
|
|
|
@ -81,17 +81,9 @@ var findOrCreateCollectionByName = function (name, type, noCreate, options) {
|
|||
let res = false;
|
||||
if (col === null && !noCreate) {
|
||||
if (type === ArangoCollection.TYPE_DOCUMENT) {
|
||||
if (options) {
|
||||
col = db._create(name, options);
|
||||
} else {
|
||||
col = db._create(name);
|
||||
}
|
||||
col = db._create(name, options);
|
||||
} else {
|
||||
if (options) {
|
||||
col = db._createEdgeCollection(name, options);
|
||||
} else {
|
||||
col = db._createEdgeCollection(name);
|
||||
}
|
||||
col = db._createEdgeCollection(name, options);
|
||||
}
|
||||
res = true;
|
||||
} else if (!(col instanceof ArangoCollection)) {
|
||||
|
@ -320,12 +312,20 @@ var transformExampleToAQL = function (examples, collections, bindVars, varname)
|
|||
// / internal helper to sort a graph's edge definitions
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var sortEdgeDefinition = function (edgeDefinition) {
|
||||
edgeDefinition.from = edgeDefinition.from.sort();
|
||||
edgeDefinition.to = edgeDefinition.to.sort();
|
||||
var sortEdgeDefinitionInplace = function (edgeDefinition) {
|
||||
edgeDefinition.from.sort();
|
||||
edgeDefinition.to.sort();
|
||||
return edgeDefinition;
|
||||
};
|
||||
|
||||
var sortEdgeDefinition = function (edgeDefinition) {
|
||||
return {
|
||||
collection: edgeDefinition.collection,
|
||||
from: edgeDefinition.from.slice().sort(),
|
||||
to: edgeDefinition.to.slice().sort(),
|
||||
};
|
||||
};
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief create a new graph
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -731,6 +731,13 @@ var checkIfMayBeDropped = function (colName, graphName, graphs) {
|
|||
return result;
|
||||
};
|
||||
|
||||
const edgeDefinitionsEqual = function (leftEdgeDef, rightEdgeDef) {
|
||||
leftEdgeDef = sortEdgeDefinition(leftEdgeDef);
|
||||
rightEdgeDef = sortEdgeDefinition(rightEdgeDef);
|
||||
const stringify = obj => JSON.stringify(obj, Object.keys(obj).sort());
|
||||
return stringify(leftEdgeDef) === stringify(rightEdgeDef);
|
||||
};
|
||||
|
||||
// @brief Class Graph. Defines a graph in the Database.
|
||||
class Graph {
|
||||
constructor (info) {
|
||||
|
@ -762,7 +769,7 @@ class Graph {
|
|||
var self = this;
|
||||
// Create Hidden Properties
|
||||
createHiddenProperty(this, '__useBuiltIn', useBuiltIn);
|
||||
createHiddenProperty(this, '__name', info._key);
|
||||
createHiddenProperty(this, '__name', info._key || info.name);
|
||||
createHiddenProperty(this, '__vertexCollections', vertexCollections);
|
||||
createHiddenProperty(this, '__edgeCollections', edgeCollections);
|
||||
createHiddenProperty(this, '__edgeDefinitions', info.edgeDefinitions);
|
||||
|
@ -779,7 +786,7 @@ class Graph {
|
|||
|
||||
// Create Hidden Functions
|
||||
createHiddenProperty(this, '__updateBindCollections', updateBindCollections);
|
||||
createHiddenProperty(this, '__sortEdgeDefinition', sortEdgeDefinition);
|
||||
createHiddenProperty(this, '__sortEdgeDefinition', sortEdgeDefinitionInplace);
|
||||
updateBindCollections(self);
|
||||
}
|
||||
|
||||
|
@ -1551,226 +1558,6 @@ class Graph {
|
|||
return result;
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief was docuBlock JSF_general_graph__extendEdgeDefinitions
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
_extendEdgeDefinitions (edgeDefinition) {
|
||||
edgeDefinition = sortEdgeDefinition(edgeDefinition);
|
||||
var self = this;
|
||||
var err;
|
||||
// check if edgeCollection not already used
|
||||
var eC = edgeDefinition.collection;
|
||||
// ... in same graph
|
||||
if (this.__edgeCollections[eC] !== undefined) {
|
||||
err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_COLLECTION_MULTI_USE.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_GRAPH_COLLECTION_MULTI_USE.message;
|
||||
throw err;
|
||||
}
|
||||
// in different graph
|
||||
db._graphs.toArray().forEach(
|
||||
function (singleGraph) {
|
||||
var sGEDs = singleGraph.edgeDefinitions;
|
||||
sGEDs.forEach(
|
||||
function (sGED) {
|
||||
var col = sGED.collection;
|
||||
if (col === eC) {
|
||||
if (JSON.stringify(sGED) !== JSON.stringify(edgeDefinition)) {
|
||||
err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS.code;
|
||||
err.errorMessage = col + ' ' +
|
||||
arangodb.errors.ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS.message;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
findOrCreateCollectionsByEdgeDefinitions([edgeDefinition]);
|
||||
|
||||
this.__edgeDefinitions.push(edgeDefinition);
|
||||
db._graphs.update(this.__name, {edgeDefinitions: this.__edgeDefinitions});
|
||||
this.__edgeCollections[edgeDefinition.collection] = db[edgeDefinition.collection];
|
||||
edgeDefinition.from.forEach(
|
||||
function (vc) {
|
||||
self[vc] = db[vc];
|
||||
// remove from __orphanCollections
|
||||
var orphanIndex = self.__orphanCollections.indexOf(vc);
|
||||
if (orphanIndex !== -1) {
|
||||
self.__orphanCollections.splice(orphanIndex, 1);
|
||||
}
|
||||
// push into __vertexCollections
|
||||
if (self.__vertexCollections[vc] === undefined) {
|
||||
self.__vertexCollections[vc] = db[vc];
|
||||
}
|
||||
}
|
||||
);
|
||||
edgeDefinition.to.forEach(
|
||||
function (vc) {
|
||||
self[vc] = db[vc];
|
||||
// remove from __orphanCollections
|
||||
var orphanIndex = self.__orphanCollections.indexOf(vc);
|
||||
if (orphanIndex !== -1) {
|
||||
self.__orphanCollections.splice(orphanIndex, 1);
|
||||
}
|
||||
// push into __vertexCollections
|
||||
if (self.__vertexCollections[vc] === undefined) {
|
||||
self.__vertexCollections[vc] = db[vc];
|
||||
}
|
||||
}
|
||||
);
|
||||
updateBindCollections(this);
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief was docuBlock JSF_general_graph__editEdgeDefinition
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
_editEdgeDefinitions (edgeDefinition) {
|
||||
edgeDefinition = sortEdgeDefinition(edgeDefinition);
|
||||
var self = this;
|
||||
|
||||
// check, if in graphs edge definition
|
||||
if (this.__edgeCollections[edgeDefinition.collection] === undefined) {
|
||||
var err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.message;
|
||||
throw err;
|
||||
}
|
||||
|
||||
findOrCreateCollectionsByEdgeDefinitions([edgeDefinition]);
|
||||
|
||||
// evaluate collections to add to orphanage
|
||||
var possibleOrphans = [];
|
||||
var currentEdgeDefinition;
|
||||
this.__edgeDefinitions.forEach(
|
||||
function (ed) {
|
||||
if (edgeDefinition.collection === ed.collection) {
|
||||
currentEdgeDefinition = ed;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
var currentCollections = _.union(currentEdgeDefinition.from, currentEdgeDefinition.to);
|
||||
var newCollections = _.union(edgeDefinition.from, edgeDefinition.to);
|
||||
currentCollections.forEach(
|
||||
function (colName) {
|
||||
if (newCollections.indexOf(colName) === -1) {
|
||||
possibleOrphans.push(colName);
|
||||
}
|
||||
}
|
||||
);
|
||||
// change definition for ALL graphs
|
||||
var graphs = exports._listObjects();
|
||||
graphs.forEach(
|
||||
function (graph) {
|
||||
changeEdgeDefinitionsForGraph(graph, edgeDefinition, newCollections, possibleOrphans, self);
|
||||
}
|
||||
);
|
||||
updateBindCollections(this);
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief was docuBlock JSF_general_graph__deleteEdgeDefinition
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
_deleteEdgeDefinition (edgeCollection, dropCollection) {
|
||||
// check, if in graphs edge definition
|
||||
if (this.__edgeCollections[edgeCollection] === undefined) {
|
||||
var err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.message;
|
||||
throw err;
|
||||
}
|
||||
if (dropCollection) {
|
||||
checkRWPermission(edgeCollection);
|
||||
}
|
||||
|
||||
let edgeDefinitions = this.__edgeDefinitions;
|
||||
let self = this;
|
||||
let usedVertexCollections = [];
|
||||
let possibleOrphans = [];
|
||||
let index;
|
||||
|
||||
edgeDefinitions.forEach(
|
||||
function (edgeDefinition, idx) {
|
||||
if (edgeDefinition.collection === edgeCollection) {
|
||||
index = idx;
|
||||
possibleOrphans = edgeDefinition.from;
|
||||
possibleOrphans = _.union(possibleOrphans, edgeDefinition.to);
|
||||
} else {
|
||||
usedVertexCollections = _.union(usedVertexCollections, edgeDefinition.from);
|
||||
usedVertexCollections = _.union(usedVertexCollections, edgeDefinition.to);
|
||||
}
|
||||
}
|
||||
);
|
||||
this.__edgeDefinitions.splice(index, 1);
|
||||
possibleOrphans.forEach(
|
||||
function (po) {
|
||||
if (usedVertexCollections.indexOf(po) === -1) {
|
||||
self.__orphanCollections.push(po);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
updateBindCollections(this);
|
||||
let gdb = getGraphCollection();
|
||||
gdb.update(
|
||||
this.__name,
|
||||
{
|
||||
orphanCollections: this.__orphanCollections,
|
||||
edgeDefinitions: this.__edgeDefinitions
|
||||
}
|
||||
);
|
||||
|
||||
if (dropCollection) {
|
||||
db._drop(edgeCollection);
|
||||
}
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief was docuBlock JSF_general_graph__addVertexCollection
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
_addVertexCollection (vertexCollectionName, createCollection) {
|
||||
// check edgeCollection
|
||||
var ec = db._collection(vertexCollectionName);
|
||||
var err;
|
||||
if (ec === null) {
|
||||
if (createCollection !== false) {
|
||||
db._create(vertexCollectionName);
|
||||
} else {
|
||||
err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code;
|
||||
err.errorMessage = vertexCollectionName + arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message;
|
||||
throw err;
|
||||
}
|
||||
} else if (ec.type() !== 2) {
|
||||
err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.message;
|
||||
throw err;
|
||||
}
|
||||
if (this.__vertexCollections[vertexCollectionName] !== undefined) {
|
||||
err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.message;
|
||||
throw err;
|
||||
}
|
||||
if (_.includes(this.__orphanCollections, vertexCollectionName)) {
|
||||
err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_COLLECTION_USED_IN_ORPHANS.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_GRAPH_COLLECTION_USED_IN_ORPHANS.message;
|
||||
throw err;
|
||||
}
|
||||
this.__orphanCollections.push(vertexCollectionName);
|
||||
updateBindCollections(this);
|
||||
db._graphs.update(this.__name, {orphanCollections: this.__orphanCollections});
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief was docuBlock JSF_general_graph__orphanCollections
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2013,6 +1800,9 @@ exports._create = function (graphName, edgeDefinitions, orphanCollections, optio
|
|||
err.errorMessage = arangodb.errors.ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION.message;
|
||||
throw err;
|
||||
}
|
||||
|
||||
edgeDefinitions = _.cloneDeep(edgeDefinitions);
|
||||
|
||||
// check, if a collection is already used in a different edgeDefinition
|
||||
let tmpCollections = [];
|
||||
let tmpEdgeDefinitions = {};
|
||||
|
@ -2039,7 +1829,7 @@ exports._create = function (graphName, edgeDefinitions, orphanCollections, optio
|
|||
(sGED) => {
|
||||
var col = sGED.collection;
|
||||
if (tmpCollections.indexOf(col) !== -1) {
|
||||
if (JSON.stringify(sGED) !== JSON.stringify(tmpEdgeDefinitions[col])) {
|
||||
if (!edgeDefinitionsEqual(sGED, tmpEdgeDefinitions[col])) {
|
||||
let err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS.code;
|
||||
err.errorMessage = col + ' ' +
|
||||
|
@ -2076,12 +1866,7 @@ exports._create = function (graphName, edgeDefinitions, orphanCollections, optio
|
|||
}
|
||||
);
|
||||
|
||||
edgeDefinitions.forEach(
|
||||
(eD, index) => {
|
||||
var tmp = sortEdgeDefinition(eD);
|
||||
edgeDefinitions[index] = tmp;
|
||||
}
|
||||
);
|
||||
edgeDefinitions.forEach(sortEdgeDefinitionInplace);
|
||||
orphanCollections = orphanCollections.sort();
|
||||
|
||||
var data = gdb.save({
|
||||
|
@ -2089,7 +1874,7 @@ exports._create = function (graphName, edgeDefinitions, orphanCollections, optio
|
|||
'edgeDefinitions': edgeDefinitions,
|
||||
'_key': graphName,
|
||||
'numberOfShards': options.numberOfShards || 1,
|
||||
'replicationFactor': options.replicationFactor || 1
|
||||
'replicationFactor': options.replicationFactor || 1,
|
||||
}, options);
|
||||
data.orphanCollections = orphanCollections;
|
||||
data.edgeDefinitions = edgeDefinitions;
|
||||
|
@ -2257,82 +2042,82 @@ exports._listObjects = function () {
|
|||
exports._registerCompatibilityFunctions = function () {
|
||||
const aqlfunctions = require('@arangodb/aql/functions');
|
||||
aqlfunctions.register('arangodb::GRAPH_EDGES', function (graphName, vertexExample, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._edges(vertexExample, options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_VERTICES', function (graphName, vertexExample, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._vertices(vertexExample, options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_NEIGHBORS', function (graphName, vertexExample, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._neighbors(vertexExample, options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_COMMON_NEIGHBORS', function (graphName, vertex1Example, vertex2Example, options1, options2) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._commonNeighbors(vertex1Example, vertex2Example, options1, options2);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_COMMON_PROPERTIES', function (graphName, vertex1Example, vertex2Example, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._commonProperties(vertex1Example, vertex2Example, options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_PATHS', function (graphName, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._paths(options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_SHORTEST_PATH', function (graphName, startVertexExample, edgeVertexExample, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._shortestPath(startVertexExample, edgeVertexExample, options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_DISTANCE_TO', function (graphName, startVertexExample, edgeVertexExample, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._distanceTo(startVertexExample, edgeVertexExample, options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_ABSOLUTE_ECCENTRICITY', function (graphName, vertexExample, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._absoluteEccentricity(vertexExample, options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_ECCENTRICITY', function (graphName, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._eccentricity(options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_ABSOLUTE_CLOSENESS', function (graphName, vertexExample, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._farness(vertexExample, options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_CLOSENESS', function (graphName, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._closeness(options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_ABSOLUTE_BETWEENNESS', function (graphName, vertexExample, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._absoluteBetweenness(vertexExample, options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_BETWEENNESS', function (graphName, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._betweenness(options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_RADIUS', function (graphName, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._radius(options);
|
||||
}, false);
|
||||
aqlfunctions.register('arangodb::GRAPH_DIAMETER', function (graphName, options) {
|
||||
var gm = require('@arangodb/general-graph');
|
||||
var gm = require('@arangodb/general-graph-common');
|
||||
var g = gm._graph(graphName);
|
||||
return g._diameter(options);
|
||||
}, false);
|
|
@ -57,6 +57,8 @@ function GeneralGraphCreationSuite() {
|
|||
var vn3 = "UnitTestVertices3";
|
||||
var vn4 = "UnitTestVertices4";
|
||||
var gn = "UnitTestGraph";
|
||||
var gn1 = "UnitTestGraph1";
|
||||
var gn2 = "UnitTestGraph2";
|
||||
var edgeDef = graph._edgeDefinitions(
|
||||
graph._relation(rn, [vn1], [vn1]),
|
||||
graph._relation(rn1,
|
||||
|
@ -76,6 +78,14 @@ function GeneralGraphCreationSuite() {
|
|||
vc5 = "UnitTestEdgeDefDeleteVertexCol5",
|
||||
vc6 = "UnitTestEdgeDefDeleteVertexCol6";
|
||||
|
||||
var sortEdgeDefinition = function(edgeDefinition) {
|
||||
return {
|
||||
collection: edgeDefinition.collection,
|
||||
from: edgeDefinition.from.slice().sort(),
|
||||
to: edgeDefinition.to.slice().sort()
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
setUp: function() {
|
||||
|
@ -111,6 +121,12 @@ function GeneralGraphCreationSuite() {
|
|||
graph._drop(gN2, true);
|
||||
} catch(ignore) {
|
||||
}
|
||||
if (db._collection("_graphs").exists(gn1)) {
|
||||
db._collection("_graphs").remove(gn1);
|
||||
}
|
||||
if (db._collection("_graphs").exists(gn2)) {
|
||||
db._collection("_graphs").remove(gn2);
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -381,7 +397,6 @@ function GeneralGraphCreationSuite() {
|
|||
]);
|
||||
},
|
||||
|
||||
|
||||
test_create : function () {
|
||||
if (db._collection("_graphs").exists(gn)) {
|
||||
db._collection("_graphs").remove(gn);
|
||||
|
@ -467,6 +482,64 @@ function GeneralGraphCreationSuite() {
|
|||
}
|
||||
},
|
||||
|
||||
// Graphs may have overlapping edge collections, as long as their
|
||||
// definitions are equal.
|
||||
// This is also a regression test for a broken comparison of edge
|
||||
// definitions, which did rely on the edge definition object's key order
|
||||
// and thus sometimes reported spurious inequality.
|
||||
test_createGraphsWithOverlappingEdgeDefinitions: function () {
|
||||
if (db._collection("_graphs").exists(gn)) {
|
||||
db._collection("_graphs").remove(gn);
|
||||
}
|
||||
// try to provoke differently ordered keys in
|
||||
// edge definitions that are actually equal.
|
||||
const edgeDefs1 = [
|
||||
{
|
||||
collection: rn,
|
||||
from: [vn1],
|
||||
to: [vn1],
|
||||
},
|
||||
];
|
||||
const edgeDefs2 = [
|
||||
{
|
||||
to: [vn1],
|
||||
from: [vn1],
|
||||
collection: rn,
|
||||
},
|
||||
];
|
||||
graph._create(gn1, edgeDefs1);
|
||||
graph._create(gn2, edgeDefs2);
|
||||
},
|
||||
|
||||
// Graphs may have overlapping edge collections, as long as their
|
||||
// definitions are equal.
|
||||
// This is also a regression test for a broken comparison of edge
|
||||
// definitions, which did rely on the edge definition's from and to
|
||||
// arrays to be ordered.
|
||||
test_createGraphsWithLargeOverlappingEdgeDefinitions: function () {
|
||||
if (db._collection("_graphs").exists(gn)) {
|
||||
db._collection("_graphs").remove(gn);
|
||||
}
|
||||
// try to provoke differently ordered from and to arrays in
|
||||
// edge definitions that are actually equal.
|
||||
const edgeDefs1 = [
|
||||
{
|
||||
collection: rn,
|
||||
from: [vn1, vn2, vn3, vn4],
|
||||
to: [vn2, vn1, vn4, vn3],
|
||||
},
|
||||
];
|
||||
const edgeDefs2 = [
|
||||
{
|
||||
collection: rn,
|
||||
from: [vn4, vn3, vn2, vn1],
|
||||
to: [vn3, vn4, vn1, vn2],
|
||||
},
|
||||
];
|
||||
graph._create(gn1, edgeDefs1);
|
||||
graph._create(gn2, edgeDefs2);
|
||||
},
|
||||
|
||||
test_get_graph : function () {
|
||||
if (db._collection("_graphs").exists(gn)) {
|
||||
db._collection("_graphs").remove(gn);
|
||||
|
@ -582,11 +655,17 @@ function GeneralGraphCreationSuite() {
|
|||
g1._deleteEdgeDefinition(ec1);
|
||||
assertEqual([dr2, dr3], g1.__edgeDefinitions);
|
||||
assertEqual([vc1, vc2], g1._orphanCollections());
|
||||
g1 = graph._graph(gN1); // reload
|
||||
assertEqual([dr2, dr3], g1.__edgeDefinitions);
|
||||
assertEqual([vc1, vc2], g1._orphanCollections());
|
||||
assertTrue(db._collection(ec1) !== null);
|
||||
|
||||
g1._deleteEdgeDefinition(ec2);
|
||||
assertEqual([dr3], g1.__edgeDefinitions);
|
||||
assertEqual([vc1, vc2, vc3], g1._orphanCollections());
|
||||
assertEqual([vc1, vc2, vc3].sort(), g1._orphanCollections().sort());
|
||||
g1 = graph._graph(gN1); // reload
|
||||
assertEqual([dr3], g1.__edgeDefinitions);
|
||||
assertEqual([vc1, vc2, vc3].sort(), g1._orphanCollections().sort());
|
||||
assertTrue(db._collection(ec2) !== null);
|
||||
},
|
||||
|
||||
|
@ -601,14 +680,20 @@ function GeneralGraphCreationSuite() {
|
|||
g1._deleteEdgeDefinition(ec1, true);
|
||||
assertEqual([dr2, dr3], g1.__edgeDefinitions);
|
||||
assertEqual([vc1, vc2], g1._orphanCollections());
|
||||
g1 = graph._graph(gN1); // reload
|
||||
assertEqual([dr2, dr3], g1.__edgeDefinitions);
|
||||
assertEqual([vc1, vc2], g1._orphanCollections());
|
||||
assertTrue(db._collection(ec1) === null);
|
||||
|
||||
g1._deleteEdgeDefinition(ec2, true);
|
||||
assertEqual([dr3], g1.__edgeDefinitions);
|
||||
assertEqual([vc1, vc2, vc3], g1._orphanCollections());
|
||||
assertEqual([vc1, vc2, vc3].sort(), g1._orphanCollections().sort());
|
||||
g1 = graph._graph(gN1); // reload
|
||||
assertEqual([dr3], g1.__edgeDefinitions);
|
||||
assertEqual([vc1, vc2, vc3].sort(), g1._orphanCollections().sort());
|
||||
assertTrue(db._collection(ec2) === null);
|
||||
},
|
||||
|
||||
|
||||
test_extendEdgeDefinitionFromExistingGraph1: function() {
|
||||
|
||||
try {
|
||||
|
@ -622,10 +707,11 @@ function GeneralGraphCreationSuite() {
|
|||
|
||||
try {
|
||||
g1._extendEdgeDefinitions(dr2);
|
||||
fail();
|
||||
} catch (e) {
|
||||
assertEqual(
|
||||
e.errorMessage,
|
||||
arangodb.errors.ERROR_GRAPH_COLLECTION_MULTI_USE.message
|
||||
ec1 + " " + arangodb.errors.ERROR_GRAPH_COLLECTION_MULTI_USE.message
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -680,15 +766,29 @@ function GeneralGraphCreationSuite() {
|
|||
g1 = graph._create(gN1, [dr1]);
|
||||
graph._create(gN2, [dr2]);
|
||||
|
||||
const loadG1 = () => graph._graph(gN1);
|
||||
let sortEdgeDefinitions = function (a,b) {
|
||||
if (a.collection < b.collection) {
|
||||
return -1;
|
||||
}
|
||||
if (a.collection > b.collection) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
assertEqual([dr1], g1.__edgeDefinitions);
|
||||
g1._addVertexCollection(vc3);
|
||||
assertEqual([vc3], g1._orphanCollections());
|
||||
assertEqual([vc3], loadG1()._orphanCollections());
|
||||
g1._extendEdgeDefinitions(dr3);
|
||||
assertEqual([dr1, dr3], g1.__edgeDefinitions);
|
||||
assertEqual([dr1, dr3].sort(sortEdgeDefinitions), g1.__edgeDefinitions);
|
||||
assertEqual([dr1, dr3].sort(sortEdgeDefinitions), loadG1().__edgeDefinitions);
|
||||
assertEqual([], g1._orphanCollections());
|
||||
assertEqual([], loadG1()._orphanCollections());
|
||||
g1._extendEdgeDefinitions(dr2);
|
||||
assertEqual([dr1, dr3, dr2], g1.__edgeDefinitions);
|
||||
|
||||
assertEqual([dr1, dr3, dr2].sort(sortEdgeDefinitions), g1.__edgeDefinitions);
|
||||
assertEqual([dr1, dr3, dr2].sort(sortEdgeDefinitions), loadG1().__edgeDefinitions);
|
||||
},
|
||||
|
||||
test_extendEdgeDefinitionFromExistingGraph4: function() {
|
||||
|
@ -705,15 +805,22 @@ function GeneralGraphCreationSuite() {
|
|||
dr2 = graph._relation(ec2, [vc4, vc3, vc1, vc2], [vc4, vc3, vc1, vc2]),
|
||||
g1 = graph._create(gN1, [dr1]);
|
||||
|
||||
const loadG1 = () => graph._graph(gN1);
|
||||
|
||||
g1._extendEdgeDefinitions(dr2);
|
||||
dr1 = sortEdgeDefinition(dr1);
|
||||
dr2 = sortEdgeDefinition(dr2);
|
||||
assertEqual([dr1, dr2], g1.__edgeDefinitions);
|
||||
var edgeDefinition = _.find(g1.__edgeDefinitions, {collection: ec2});
|
||||
assertEqual([dr1, dr2], loadG1().__edgeDefinitions);
|
||||
let edgeDefinition = _.find(g1.__edgeDefinitions, {collection: ec2});
|
||||
assertEqual(edgeDefinition.from, [vc1, vc2, vc3, vc4]);
|
||||
assertEqual(edgeDefinition.to, [vc1, vc2, vc3, vc4]);
|
||||
edgeDefinition = _.find(loadG1().__edgeDefinitions, {collection: ec2});
|
||||
assertEqual(edgeDefinition.from, [vc1, vc2, vc3, vc4]);
|
||||
assertEqual(edgeDefinition.to, [vc1, vc2, vc3, vc4]);
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
test_editEdgeDefinitionFromExistingGraph1: function() {
|
||||
var dr1 = graph._relation(ec1, [vc1], [vc1, vc2]),
|
||||
dr2 = graph._relation(ec2, [vc3], [vc4, vc5]),
|
||||
|
@ -732,37 +839,42 @@ function GeneralGraphCreationSuite() {
|
|||
|
||||
test_editEdgeDefinitionFromExistingGraph2: function() {
|
||||
|
||||
var dr1 = graph._relation(ec1, [vc1, vc2], [vc3, vc4]),
|
||||
dr2 = graph._relation(ec2, [vc1], [vc4]),
|
||||
dr3 = graph._relation(ec1, [vc5], [vc5]),
|
||||
g1 = graph._create(gN1, [dr1, dr2]),
|
||||
g2 = graph._create(gN2, [dr1]);
|
||||
var dr1 = graph._relation(ec1, _.cloneDeep([vc1, vc2]), _.cloneDeep([vc3, vc4])),
|
||||
dr2 = graph._relation(ec2, _.cloneDeep([vc1]), _.cloneDeep([vc4])),
|
||||
dr3 = graph._relation(ec1, _.cloneDeep([vc5]), _.cloneDeep([vc5])),
|
||||
g1 = graph._create(gN1, _.cloneDeep([dr1, dr2])),
|
||||
g2 = graph._create(gN2, _.cloneDeep([dr1]));
|
||||
|
||||
g1._editEdgeDefinitions(_.cloneDeep(dr3));
|
||||
|
||||
g1 = graph._graph(gN1);
|
||||
g2 = graph._graph(gN2);
|
||||
|
||||
g1._editEdgeDefinitions(dr3);
|
||||
assertEqual([dr3, dr2], g1.__edgeDefinitions);
|
||||
assertEqual([dr3], g2.__edgeDefinitions);
|
||||
g2 = graph._graph(gN2);
|
||||
|
||||
assertEqual(g1._orphanCollections().sort(), [vc2, vc3].sort());
|
||||
assertEqual(g2._orphanCollections().sort(), [vc1, vc2, vc3, vc4].sort());
|
||||
|
||||
},
|
||||
|
||||
test_editEdgeDefinitionFromExistingGraph3: function() {
|
||||
|
||||
var dr1 = graph._relation(ec1, [vc1], [vc1, vc2]),
|
||||
dr2 = graph._relation(ec1, [vc3], [vc4, vc5]),
|
||||
dr3 = graph._relation(ec2, [vc2], [vc2, vc3]),
|
||||
g1 = graph._create(gN1, [dr1, dr3]),
|
||||
g2 = graph._create(gN2, [dr1]);
|
||||
var dr1 = graph._relation(ec1, _.cloneDeep([vc1]), _.cloneDeep([vc1, vc2])),
|
||||
dr2 = graph._relation(ec1, _.cloneDeep([vc3]), _.cloneDeep([vc4, vc5])),
|
||||
dr3 = graph._relation(ec2, _.cloneDeep([vc2]), _.cloneDeep([vc2, vc3])),
|
||||
g1 = graph._create(gN1, _.cloneDeep([dr1, dr3])),
|
||||
g2 = graph._create(gN2, _.cloneDeep([dr1]));
|
||||
|
||||
g1._addVertexCollection(vc4);
|
||||
g2._addVertexCollection(vc5);
|
||||
g2._addVertexCollection(vc6);
|
||||
g1._editEdgeDefinitions(dr2, true);
|
||||
g1._editEdgeDefinitions(dr2);
|
||||
|
||||
g2 = graph._graph(gN2);
|
||||
g1 = graph._graph(gN1);
|
||||
|
||||
assertEqual([dr2, dr3], g1.__edgeDefinitions);
|
||||
assertEqual([dr2], g2.__edgeDefinitions);
|
||||
g2 = graph._graph(gN2);
|
||||
assertEqual([vc1], g1._orphanCollections());
|
||||
assertEqual(g2._orphanCollections().sort(), [vc1, vc2, vc6].sort());
|
||||
|
||||
|
@ -919,14 +1031,17 @@ function EdgesAndVerticesSuite() {
|
|||
var myGraphName = unitTestGraphName + "2";
|
||||
var myEdgeColName = "unitTestEdgeCollection4711";
|
||||
var myVertexColName = vc1;
|
||||
|
||||
graph._create(
|
||||
myGraphName,
|
||||
graph._edgeDefinitions(
|
||||
graph._relation(myEdgeColName, myVertexColName, myVertexColName)
|
||||
)
|
||||
);
|
||||
|
||||
graph._drop(myGraphName, true);
|
||||
assertFalse(graph._exists(myGraphName));
|
||||
db._flushCache();
|
||||
assertTrue(db._collection(myVertexColName) !== null);
|
||||
assertTrue(db._collection(myEdgeColName) === null);
|
||||
},
|
||||
|
@ -1013,11 +1128,9 @@ function EdgesAndVerticesSuite() {
|
|||
graph._relation(myED, myVD2, myVD2)
|
||||
)
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
assertEqual(
|
||||
e.errorMessage,
|
||||
arangodb.errors.ERROR_GRAPH_COLLECTION_MULTI_USE.message
|
||||
);
|
||||
assertEqual(e.errorNum, arangodb.errors.ERROR_GRAPH_COLLECTION_MULTI_USE.code)
|
||||
}
|
||||
assertFalse(graph._exists(myGraphName));
|
||||
assertTrue(db._collection(myVD1) === null);
|
||||
|
@ -1144,14 +1257,14 @@ function EdgesAndVerticesSuite() {
|
|||
g[ec1].save(vertexId1, vertexId2, {});
|
||||
fail();
|
||||
} catch (e) {
|
||||
assertEqual(e.errorNum, 1906);
|
||||
assertEqual(e.errorNum, arangodb.errors.ERROR_GRAPH_INVALID_EDGE.code);
|
||||
}
|
||||
|
||||
try {
|
||||
g[ec1].insert(vertexId1, vertexId2, {});
|
||||
fail();
|
||||
} catch (e) {
|
||||
assertEqual(e.errorNum, 1906);
|
||||
assertEqual(e.errorNum, arangodb.errors.ERROR_GRAPH_INVALID_EDGE.code);
|
||||
}
|
||||
|
||||
g[vc1].remove(vertexId1);
|
||||
|
@ -1764,9 +1877,10 @@ function OrphanCollectionSuite() {
|
|||
g1._addVertexCollection(vC4, false);
|
||||
} catch (e) {
|
||||
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code);
|
||||
assertEqual(e.errorMessage, vC4 + ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message);
|
||||
assertEqual(e.errorMessage, vC4 + " " + ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message);
|
||||
}
|
||||
assertTrue(db._collection(vC4) === null);
|
||||
g1 = graph._graph(gN1);
|
||||
assertEqual(g1._orphanCollections(), []);
|
||||
},
|
||||
|
||||
|
@ -1786,7 +1900,7 @@ function OrphanCollectionSuite() {
|
|||
g1._addVertexCollection(vC1);
|
||||
} catch (e) {
|
||||
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.code);
|
||||
assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.message);
|
||||
assertEqual(e.errorMessage, vC1 + " " + ERRORS.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.message);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1795,18 +1909,19 @@ function OrphanCollectionSuite() {
|
|||
try {
|
||||
g1._removeVertexCollection(name);
|
||||
} catch (e) {
|
||||
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code);
|
||||
assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message);
|
||||
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.code);
|
||||
assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.message);
|
||||
}
|
||||
},
|
||||
|
||||
test_removeVertexCollection2: function() {
|
||||
g1._addVertexCollection(vC4, true);
|
||||
g1._addVertexCollection(vC5, true);
|
||||
assertEqual(g1._orphanCollections(), [vC4, vC5]);
|
||||
assertEqual(g1._orphanCollections().sort(), [vC4, vC5].sort());
|
||||
g1._removeVertexCollection(vC4, false);
|
||||
assertTrue(db._collection(vC4) !== null);
|
||||
assertEqual(g1._orphanCollections(), [vC5]);
|
||||
g1 = graph._graph(gN1);
|
||||
assertEqual(g1._orphanCollections().sort(), [vC5].sort());
|
||||
try {
|
||||
g1._removeVertexCollection(vC4, true);
|
||||
} catch (e) {
|
||||
|
@ -1822,6 +1937,7 @@ function OrphanCollectionSuite() {
|
|||
graph._drop(gN1, true);
|
||||
assertTrue(db._collection(vC3) !== null);
|
||||
graph._drop(gN2, true);
|
||||
db._flushCache();
|
||||
assertTrue(db._collection(vC3) === null);
|
||||
},
|
||||
|
||||
|
@ -1832,6 +1948,7 @@ function OrphanCollectionSuite() {
|
|||
graph._drop(gN2, true);
|
||||
assertTrue(db._collection(vC3) !== null);
|
||||
graph._drop(gN1, true);
|
||||
db._flushCache();
|
||||
assertTrue(db._collection(vC3) === null);
|
||||
},
|
||||
|
||||
|
@ -1843,6 +1960,7 @@ function OrphanCollectionSuite() {
|
|||
graph._drop(gN1, true);
|
||||
assertTrue(db._collection(vC4) !== null);
|
||||
graph._drop(gN2, true);
|
||||
db._flushCache();
|
||||
assertTrue(db._collection(vC4) === null);
|
||||
},
|
||||
|
||||
|
|
|
@ -62,6 +62,27 @@
|
|||
|
||||
exports.ArangoUsers = global.ArangoUsers;
|
||||
delete global.ArangoUsers;
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief ArangoGeneralGraphModule
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.ArangoGeneralGraphModule = global.ArangoGeneralGraphModule;
|
||||
delete global.ArangoGeneralGraphModule;
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief ArangoGeneralGraphClass
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.ArangoGraph = global.ArangoGraph;
|
||||
delete global.ArangoGraph;
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief ArangoSmartGraphClass
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.ArangoSmartGraph = global.ArangoSmartGraph;
|
||||
delete global.ArangoSmartGraph;
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief ArangoDatabase
|
||||
|
|
|
@ -47,8 +47,7 @@ const isZipBuffer = require('@arangodb/util').isZipBuffer;
|
|||
|
||||
const SYSTEM_SERVICE_MOUNTS = [
|
||||
'/_admin/aardvark', // Admin interface.
|
||||
'/_api/foxx', // Foxx management API.
|
||||
'/_api/gharial' // General_Graph API.
|
||||
'/_api/foxx' // Foxx management API.
|
||||
];
|
||||
|
||||
const GLOBAL_SERVICE_MAP = new Map();
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/* global ArangoGeneralGraph */
|
||||
'use strict';
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief Replication management
|
||||
// /
|
||||
// / @file
|
||||
// /
|
||||
// / DISCLAIMER
|
||||
// /
|
||||
// / Copyright 2012 triagens GmbH, Cologne, Germany
|
||||
// /
|
||||
// / Licensed under the Apache License, Version 2.0 (the "License")
|
||||
// / you may not use this file except in compliance with the License.
|
||||
// / You may obtain a copy of the License at
|
||||
// /
|
||||
// / http://www.apache.org/licenses/LICENSE-2.0
|
||||
// /
|
||||
// / Unless required by applicable law or agreed to in writing, software
|
||||
// / distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// / WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// / See the License for the specific language governing permissions and
|
||||
// / limitations under the License.
|
||||
// /
|
||||
// / Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
// /
|
||||
// / @author Heiko Kernbach
|
||||
// / @author Copyright 2018, ArangoDB GmbH, Cologne, Germany
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
const internal = require('internal'); // OK: reloadAuth
|
||||
const ggc = require('@arangodb/general-graph-common');
|
||||
const GeneralGraph = internal.ArangoGeneralGraphModule;
|
||||
|
||||
// This is supposed to be a class
|
||||
const ArangoGraph = internal.ArangoGraph;
|
||||
//const arangodb = require("@arangodb");
|
||||
|
||||
// inherited graph class
|
||||
let CommonGraph = ggc.__GraphClass;
|
||||
|
||||
// new c++ based
|
||||
CommonGraph.prototype.__updateDefinitions = function (edgeDefs, orphans) {
|
||||
this.__edgeDefinitions = edgeDefs;
|
||||
this.__orphanCollections = orphans;
|
||||
};
|
||||
|
||||
CommonGraph.prototype._deleteEdgeDefinition = function (edgeDefinition, dropCollection = false) {
|
||||
let result = ArangoGraph._deleteEdgeDefinition(this.__name, edgeDefinition, dropCollection);
|
||||
this.__updateDefinitions(result.graph.edgeDefinitions, result.graph.orphanCollections);
|
||||
};
|
||||
|
||||
CommonGraph.prototype._extendEdgeDefinitions = function (edgeDefinitions) {
|
||||
let result = ArangoGraph._extendEdgeDefinitions(this.__name, edgeDefinitions);
|
||||
this.__updateDefinitions(result.graph.edgeDefinitions, result.graph.orphanCollections);
|
||||
};
|
||||
|
||||
CommonGraph.prototype._editEdgeDefinitions = function (edgeDefinitions) {
|
||||
let result = ArangoGraph._editEdgeDefinitions(this.__name, edgeDefinitions);
|
||||
this.__updateDefinitions(result.graph.edgeDefinitions, result.graph.orphanCollections);
|
||||
};
|
||||
|
||||
CommonGraph.prototype._addVertexCollection = function (vertexName, createCollection = true) {
|
||||
let result = ArangoGraph._addVertexCollection(this.__name, vertexName, createCollection);
|
||||
this.__updateDefinitions(result.graph.edgeDefinitions, result.graph.orphanCollections);
|
||||
};
|
||||
|
||||
CommonGraph.prototype._removeVertexCollection = function (vertexName, dropCollection = false) {
|
||||
let result = ArangoGraph._removeVertexCollection(this.__name, vertexName, dropCollection);
|
||||
this.__updateDefinitions(result.graph.edgeDefinitions, result.graph.orphanCollections);
|
||||
};
|
||||
|
||||
|
||||
exports._create = function (name, edgeDefinition, orphans, options) {
|
||||
let g = GeneralGraph._create(name, edgeDefinition, orphans, options);
|
||||
return new CommonGraph(g.graph);
|
||||
};
|
||||
|
||||
exports._drop = GeneralGraph._drop;
|
||||
|
||||
exports._exists = GeneralGraph._exists;
|
||||
|
||||
exports._graph = function (graphName) {
|
||||
let g = GeneralGraph._graph(graphName);
|
||||
return new CommonGraph(g);
|
||||
};
|
||||
|
||||
exports._list = GeneralGraph._list;
|
||||
|
||||
exports._listObjects = GeneralGraph._listObjects;
|
||||
|
||||
exports._renameCollection = GeneralGraph._renameCollection;
|
||||
|
||||
// js based helper functions
|
||||
exports.__GraphClass = CommonGraph;
|
||||
exports._edgeDefinitions = ggc._edgeDefinitions;
|
||||
exports._extendEdgeDefinitions = ggc._extendEdgeDefinitions;
|
||||
exports._relation = ggc._relation;
|
||||
exports._registerCompatibilityFunctions = ggc._registerCompatibilityFunctions;
|
|
@ -30,6 +30,8 @@ class Result {
|
|||
public:
|
||||
Result() : _errorNumber(TRI_ERROR_NO_ERROR) {}
|
||||
|
||||
Result(bool avoidCastingErrors) = delete;
|
||||
|
||||
Result(int errorNumber)
|
||||
: _errorNumber(errorNumber){
|
||||
if (errorNumber != TRI_ERROR_NO_ERROR) {
|
||||
|
|
|
@ -64,12 +64,18 @@ std::string const StaticStrings::ReplaceExisting("replaceExisting");
|
|||
std::string const StaticStrings::OverWrite("overwrite");
|
||||
|
||||
// replication headers
|
||||
std::string const StaticStrings::ReplicationHeaderCheckMore("x-arango-replication-checkmore");
|
||||
std::string const StaticStrings::ReplicationHeaderLastIncluded("x-arango-replication-lastincluded");
|
||||
std::string const StaticStrings::ReplicationHeaderLastScanned("x-arango-replication-lastscanned");
|
||||
std::string const StaticStrings::ReplicationHeaderLastTick("x-arango-replication-lasttick");
|
||||
std::string const StaticStrings::ReplicationHeaderFromPresent("x-arango-replication-frompresent");
|
||||
std::string const StaticStrings::ReplicationHeaderActive("x-arango-replication-active");
|
||||
std::string const StaticStrings::ReplicationHeaderCheckMore(
|
||||
"x-arango-replication-checkmore");
|
||||
std::string const StaticStrings::ReplicationHeaderLastIncluded(
|
||||
"x-arango-replication-lastincluded");
|
||||
std::string const StaticStrings::ReplicationHeaderLastScanned(
|
||||
"x-arango-replication-lastscanned");
|
||||
std::string const StaticStrings::ReplicationHeaderLastTick(
|
||||
"x-arango-replication-lasttick");
|
||||
std::string const StaticStrings::ReplicationHeaderFromPresent(
|
||||
"x-arango-replication-frompresent");
|
||||
std::string const StaticStrings::ReplicationHeaderActive(
|
||||
"x-arango-replication-active");
|
||||
|
||||
// database and collection names
|
||||
std::string const StaticStrings::SystemDatabase("_system");
|
||||
|
@ -155,5 +161,30 @@ std::string const StaticStrings::MimeTypeText("text/plain; charset=utf-8");
|
|||
std::string const StaticStrings::MimeTypeVPack("application/x-velocypack");
|
||||
std::string const StaticStrings::MultiPartContentType("multipart/form-data");
|
||||
|
||||
// collection attributes
|
||||
std::string const StaticStrings::NumberOfShards("numberOfShards");
|
||||
std::string const StaticStrings::ReplicationFactor("replicationFactor");
|
||||
std::string const StaticStrings::DistributeShardsLike("distributeShardsLike");
|
||||
|
||||
// graph attribute names
|
||||
std::string const StaticStrings::GraphCollection("_graphs");
|
||||
std::string const StaticStrings::GraphIsSmart("isSmart");
|
||||
std::string const StaticStrings::GraphFrom("from");
|
||||
std::string const StaticStrings::GraphTo("to");
|
||||
std::string const StaticStrings::GraphOptions("options");
|
||||
std::string const StaticStrings::GraphSmartGraphAttribute(
|
||||
"smartGraphAttribute");
|
||||
std::string const StaticStrings::GraphEdgeDefinitions("edgeDefinitions");
|
||||
std::string const StaticStrings::GraphOrphans("orphanCollections");
|
||||
std::string const StaticStrings::GraphInitial("initial");
|
||||
std::string const StaticStrings::GraphInitialCid("initialCid");
|
||||
std::string const StaticStrings::GraphName("name");
|
||||
|
||||
// rest query parameter
|
||||
std::string const StaticStrings::GraphDropCollections("dropCollections");
|
||||
std::string const StaticStrings::GraphDropCollection("dropCollection");
|
||||
std::string const StaticStrings::GraphCreateCollections("createCollections");
|
||||
std::string const StaticStrings::GraphCreateCollection("createCollection");
|
||||
|
||||
// misc strings
|
||||
std::string const StaticStrings::LastValue("lastValue");
|
||||
|
|
|
@ -148,6 +148,26 @@ class StaticStrings {
|
|||
static std::string const MimeTypeVPack;
|
||||
static std::string const MultiPartContentType;
|
||||
|
||||
// graph attribute names
|
||||
static std::string const GraphCollection;
|
||||
static std::string const GraphIsSmart;
|
||||
static std::string const GraphFrom;
|
||||
static std::string const GraphTo;
|
||||
static std::string const GraphOptions;
|
||||
static std::string const GraphSmartGraphAttribute;
|
||||
static std::string const NumberOfShards;
|
||||
static std::string const DistributeShardsLike;
|
||||
static std::string const ReplicationFactor;
|
||||
static std::string const GraphDropCollections;
|
||||
static std::string const GraphDropCollection;
|
||||
static std::string const GraphCreateCollections;
|
||||
static std::string const GraphCreateCollection;
|
||||
static std::string const GraphEdgeDefinitions;
|
||||
static std::string const GraphOrphans;
|
||||
static std::string const GraphInitial;
|
||||
static std::string const GraphInitialCid;
|
||||
static std::string const GraphName;
|
||||
|
||||
// misc strings
|
||||
static std::string const LastValue;
|
||||
};
|
||||
|
|
|
@ -376,6 +376,10 @@ ERROR_GRAPH_INVALID_ID,1937,"Invalid id","Invalid id",
|
|||
ERROR_GRAPH_COLLECTION_USED_IN_ORPHANS,1938,"collection used in orphans","The collection is already used in the orphans of the graph.",
|
||||
ERROR_GRAPH_EDGE_COL_DOES_NOT_EXIST,1939,"edge collection does not exist or is not part of the graph","the specified edge collection does not exist or is not part of the graph.",
|
||||
ERROR_GRAPH_EMPTY,1940,"empty graph","The requested graph has no edge collections."
|
||||
ERROR_GRAPH_INTERNAL_DATA_CORRUPT,1941,"internal graph data corrupt","The _graphs collection contains invalid data."
|
||||
ERROR_GRAPH_INTERNAL_EDGE_COLLECTION_ALREADY_SET,1942,"edge collection already set","Tried to add an edge collection which is already defined."
|
||||
ERROR_GRAPH_CREATE_MALFORMED_ORPHAN_LIST,1943,"malformed orphan list","the orphan list argument is malformed. It has to be an array of strings."
|
||||
ERROR_GRAPH_EDGE_DEFINITION_IS_DOCUMENT,1944,"edge definition collection is a document collection","the collection used as a relation is existing, but is a document collection, it cannot be used here."
|
||||
|
||||
################################################################################
|
||||
## Session errors
|
||||
|
@ -436,6 +440,7 @@ ERROR_NO_SMART_GRAPH_ATTRIBUTE,4001,"smart graph attribute not given","The given
|
|||
ERROR_CANNOT_DROP_SMART_COLLECTION,4002,"cannot drop this smart collection","This smart collection cannot be dropped, it dictates sharding in the graph."
|
||||
ERROR_KEY_MUST_BE_PREFIXED_WITH_SMART_GRAPH_ATTRIBUTE,4003,"in smart vertex collections _key must be prefixed with the value of the smart graph attribute","In a smart vertex collection _key must be prefixed with the value of the smart graph attribute."
|
||||
ERROR_ILLEGAL_SMART_GRAPH_ATTRIBUTE,4004,"attribute cannot be used as smart graph attribute","The given smartGraph attribute is illegal and connot be used for sharding. All system attributes are forbidden."
|
||||
ERROR_SMART_GRAPH_ATTRIBUTE_MISMATCH,4005,"smart graph attribute mismatch","The smart graph attribute of the given collection does not match the smart graph attribute of the graph."
|
||||
|
||||
################################################################################
|
||||
## Cluster repair errors
|
||||
|
|
|
@ -285,6 +285,10 @@ void TRI_InitializeErrorMessages() {
|
|||
REG_ERROR(ERROR_GRAPH_COLLECTION_USED_IN_ORPHANS, "collection used in orphans");
|
||||
REG_ERROR(ERROR_GRAPH_EDGE_COL_DOES_NOT_EXIST, "edge collection does not exist or is not part of the graph");
|
||||
REG_ERROR(ERROR_GRAPH_EMPTY, "empty graph");
|
||||
REG_ERROR(ERROR_GRAPH_INTERNAL_DATA_CORRUPT, "internal graph data corrupt");
|
||||
REG_ERROR(ERROR_GRAPH_INTERNAL_EDGE_COLLECTION_ALREADY_SET, "edge collection already set");
|
||||
REG_ERROR(ERROR_GRAPH_CREATE_MALFORMED_ORPHAN_LIST, "malformed orphan list");
|
||||
REG_ERROR(ERROR_GRAPH_EDGE_DEFINITION_IS_DOCUMENT, "edge definition collection is a document collection");
|
||||
REG_ERROR(ERROR_SESSION_UNKNOWN, "unknown session");
|
||||
REG_ERROR(ERROR_SESSION_EXPIRED, "session expired");
|
||||
REG_ERROR(SIMPLE_CLIENT_UNKNOWN_ERROR, "unknown client error");
|
||||
|
@ -315,6 +319,7 @@ void TRI_InitializeErrorMessages() {
|
|||
REG_ERROR(ERROR_CANNOT_DROP_SMART_COLLECTION, "cannot drop this smart collection");
|
||||
REG_ERROR(ERROR_KEY_MUST_BE_PREFIXED_WITH_SMART_GRAPH_ATTRIBUTE, "in smart vertex collections _key must be prefixed with the value of the smart graph attribute");
|
||||
REG_ERROR(ERROR_ILLEGAL_SMART_GRAPH_ATTRIBUTE, "attribute cannot be used as smart graph attribute");
|
||||
REG_ERROR(ERROR_SMART_GRAPH_ATTRIBUTE_MISMATCH, "smart graph attribute mismatch");
|
||||
REG_ERROR(ERROR_CLUSTER_REPAIRS_FAILED, "error during cluster repairs");
|
||||
REG_ERROR(ERROR_CLUSTER_REPAIRS_NOT_ENOUGH_HEALTHY, "not enough (healthy) db servers");
|
||||
REG_ERROR(ERROR_CLUSTER_REPAIRS_REPLICATION_FACTOR_VIOLATED, "replication factor violated during cluster repairs");
|
||||
|
|
|
@ -1512,6 +1512,27 @@ constexpr int TRI_ERROR_GRAPH_EDGE_COL_DOES_NOT_EXIST
|
|||
/// The requested graph has no edge collections.
|
||||
constexpr int TRI_ERROR_GRAPH_EMPTY = 1940;
|
||||
|
||||
/// 1941: ERROR_GRAPH_INTERNAL_DATA_CORRUPT
|
||||
/// "internal graph data corrupt"
|
||||
/// The _graphs collection contains invalid data.
|
||||
constexpr int TRI_ERROR_GRAPH_INTERNAL_DATA_CORRUPT = 1941;
|
||||
|
||||
/// 1942: ERROR_GRAPH_INTERNAL_EDGE_COLLECTION_ALREADY_SET
|
||||
/// "edge collection already set"
|
||||
/// Tried to add an edge collection which is already defined.
|
||||
constexpr int TRI_ERROR_GRAPH_INTERNAL_EDGE_COLLECTION_ALREADY_SET = 1942;
|
||||
|
||||
/// 1943: ERROR_GRAPH_CREATE_MALFORMED_ORPHAN_LIST
|
||||
/// "malformed orphan list"
|
||||
/// the orphan list argument is malformed. It has to be an array of strings.
|
||||
constexpr int TRI_ERROR_GRAPH_CREATE_MALFORMED_ORPHAN_LIST = 1943;
|
||||
|
||||
/// 1944: ERROR_GRAPH_EDGE_DEFINITION_IS_DOCUMENT
|
||||
/// "edge definition collection is a document collection"
|
||||
/// the collection used as a relation is existing, but is a document
|
||||
/// collection, it cannot be used here.
|
||||
constexpr int TRI_ERROR_GRAPH_EDGE_DEFINITION_IS_DOCUMENT = 1944;
|
||||
|
||||
/// 1950: ERROR_SESSION_UNKNOWN
|
||||
/// "unknown session"
|
||||
/// Will be raised when an invalid/unknown session id is passed to the server.
|
||||
|
@ -1665,6 +1686,12 @@ constexpr int TRI_ERROR_KEY_MUST_BE_PREFIXED_WITH_SMART_GRAPH_ATTRIBUTE
|
|||
/// All system attributes are forbidden.
|
||||
constexpr int TRI_ERROR_ILLEGAL_SMART_GRAPH_ATTRIBUTE = 4004;
|
||||
|
||||
/// 4005: ERROR_SMART_GRAPH_ATTRIBUTE_MISMATCH
|
||||
/// "smart graph attribute mismatch"
|
||||
/// The smart graph attribute of the given collection does not match the smart
|
||||
/// graph attribute of the graph.
|
||||
constexpr int TRI_ERROR_SMART_GRAPH_ATTRIBUTE_MISMATCH = 4005;
|
||||
|
||||
/// 5000: ERROR_CLUSTER_REPAIRS_FAILED
|
||||
/// "error during cluster repairs"
|
||||
/// General error during cluster repairs
|
||||
|
|
|
@ -49,6 +49,39 @@ enum class RequestType {
|
|||
ILLEGAL // must be last
|
||||
};
|
||||
|
||||
inline const char* requestToString(RequestType requestType) {
|
||||
switch (requestType) {
|
||||
case RequestType::DELETE_REQ:
|
||||
return "DELETE";
|
||||
case RequestType::GET:
|
||||
return "GET";
|
||||
case RequestType::POST:
|
||||
return "POST";
|
||||
case RequestType::PUT:
|
||||
return "PUT";
|
||||
case RequestType::HEAD:
|
||||
return "HEAD";
|
||||
case RequestType::PATCH:
|
||||
return "PATCH";
|
||||
case RequestType::OPTIONS:
|
||||
return "OPTIONS";
|
||||
case RequestType::VSTREAM_CRED:
|
||||
return "VSTREAM_CRED";
|
||||
case RequestType::VSTREAM_REGISTER:
|
||||
return "VSTREAM_REGISTER";
|
||||
case RequestType::VSTREAM_STATUS:
|
||||
return "VSTREAM_STATUS";
|
||||
case RequestType::ILLEGAL:
|
||||
default:
|
||||
return "ILLEGAL";
|
||||
}
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& ostream,
|
||||
RequestType requestType) {
|
||||
return ostream << requestToString(requestType);
|
||||
}
|
||||
|
||||
enum class ContentType {
|
||||
CUSTOM, // use Content-Type from _headers
|
||||
JSON, // application/json
|
||||
|
@ -122,6 +155,112 @@ enum class ResponseCode {
|
|||
BANDWIDTH_LIMIT_EXCEEDED = 509,
|
||||
NOT_EXTENDED = 510
|
||||
};
|
||||
|
||||
inline const char* responseToString(ResponseCode responseCode) {
|
||||
switch (responseCode) {
|
||||
case ResponseCode::CONTINUE:
|
||||
return "100 CONTINUE";
|
||||
case ResponseCode::SWITCHING_PROTOCOLS:
|
||||
return "101 SWITCHING_PROTOCOLS";
|
||||
case ResponseCode::PROCESSING:
|
||||
return "102 PROCESSING";
|
||||
case ResponseCode::OK:
|
||||
return "200 OK";
|
||||
case ResponseCode::CREATED:
|
||||
return "201 CREATED";
|
||||
case ResponseCode::ACCEPTED:
|
||||
return "202 ACCEPTED";
|
||||
case ResponseCode::PARTIAL:
|
||||
return "203 PARTIAL";
|
||||
case ResponseCode::NO_CONTENT:
|
||||
return "204 NO_CONTENT";
|
||||
case ResponseCode::RESET_CONTENT:
|
||||
return "205 RESET_CONTENT";
|
||||
case ResponseCode::PARTIAL_CONTENT:
|
||||
return "206 PARTIAL_CONTENT";
|
||||
case ResponseCode::MOVED_PERMANENTLY:
|
||||
return "301 MOVED_PERMANENTLY";
|
||||
case ResponseCode::FOUND:
|
||||
return "302 FOUND";
|
||||
case ResponseCode::SEE_OTHER:
|
||||
return "303 SEE_OTHER";
|
||||
case ResponseCode::NOT_MODIFIED:
|
||||
return "304 NOT_MODIFIED";
|
||||
case ResponseCode::TEMPORARY_REDIRECT:
|
||||
return "307 TEMPORARY_REDIRECT";
|
||||
case ResponseCode::PERMANENT_REDIRECT:
|
||||
return "308 PERMANENT_REDIRECT";
|
||||
case ResponseCode::BAD:
|
||||
return "400 BAD";
|
||||
case ResponseCode::UNAUTHORIZED:
|
||||
return "401 UNAUTHORIZED";
|
||||
case ResponseCode::PAYMENT_REQUIRED:
|
||||
return "402 PAYMENT_REQUIRED";
|
||||
case ResponseCode::FORBIDDEN:
|
||||
return "403 FORBIDDEN";
|
||||
case ResponseCode::NOT_FOUND:
|
||||
return "404 NOT_FOUND";
|
||||
case ResponseCode::METHOD_NOT_ALLOWED:
|
||||
return "405 METHOD_NOT_ALLOWED";
|
||||
case ResponseCode::NOT_ACCEPTABLE:
|
||||
return "406 NOT_ACCEPTABLE";
|
||||
case ResponseCode::REQUEST_TIMEOUT:
|
||||
return "408 REQUEST_TIMEOUT";
|
||||
case ResponseCode::CONFLICT:
|
||||
return "409 CONFLICT";
|
||||
case ResponseCode::GONE:
|
||||
return "410 GONE";
|
||||
case ResponseCode::LENGTH_REQUIRED:
|
||||
return "411 LENGTH_REQUIRED";
|
||||
case ResponseCode::PRECONDITION_FAILED:
|
||||
return "412 PRECONDITION_FAILED";
|
||||
case ResponseCode::REQUEST_ENTITY_TOO_LARGE:
|
||||
return "413 REQUEST_ENTITY_TOO_LARGE";
|
||||
case ResponseCode::REQUEST_URI_TOO_LONG:
|
||||
return "414 REQUEST_URI_TOO_LONG";
|
||||
case ResponseCode::UNSUPPORTED_MEDIA_TYPE:
|
||||
return "415 UNSUPPORTED_MEDIA_TYPE";
|
||||
case ResponseCode::REQUESTED_RANGE_NOT_SATISFIABLE:
|
||||
return "416 REQUESTED_RANGE_NOT_SATISFIABLE";
|
||||
case ResponseCode::EXPECTATION_FAILED:
|
||||
return "417 EXPECTATION_FAILED";
|
||||
case ResponseCode::I_AM_A_TEAPOT:
|
||||
return "418 I_AM_A_TEAPOT";
|
||||
case ResponseCode::UNPROCESSABLE_ENTITY:
|
||||
return "422 UNPROCESSABLE_ENTITY";
|
||||
case ResponseCode::LOCKED:
|
||||
return "423 LOCKED";
|
||||
case ResponseCode::PRECONDITION_REQUIRED:
|
||||
return "428 PRECONDITION_REQUIRED";
|
||||
case ResponseCode::TOO_MANY_REQUESTS:
|
||||
return "429 TOO_MANY_REQUESTS";
|
||||
case ResponseCode::REQUEST_HEADER_FIELDS_TOO_LARGE:
|
||||
return "431 REQUEST_HEADER_FIELDS_TOO_LARGE";
|
||||
case ResponseCode::UNAVAILABLE_FOR_LEGAL_REASONS:
|
||||
return "451 UNAVAILABLE_FOR_LEGAL_REASONS";
|
||||
case ResponseCode::SERVER_ERROR:
|
||||
return "500 SERVER_ERROR";
|
||||
case ResponseCode::NOT_IMPLEMENTED:
|
||||
return "501 NOT_IMPLEMENTED";
|
||||
case ResponseCode::BAD_GATEWAY:
|
||||
return "502 BAD_GATEWAY";
|
||||
case ResponseCode::SERVICE_UNAVAILABLE:
|
||||
return "503 SERVICE_UNAVAILABLE";
|
||||
case ResponseCode::HTTP_VERSION_NOT_SUPPORTED:
|
||||
return "505 HTTP_VERSION_NOT_SUPPORTED";
|
||||
case ResponseCode::BANDWIDTH_LIMIT_EXCEEDED:
|
||||
return "509 BANDWIDTH_LIMIT_EXCEEDED";
|
||||
case ResponseCode::NOT_EXTENDED:
|
||||
return "510 NOT_EXTENDED";
|
||||
default:
|
||||
return "??? UNEXPECTED";
|
||||
}
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& ostream,
|
||||
ResponseCode responseCode) {
|
||||
return ostream << responseToString(responseCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -347,7 +347,6 @@ rest::ResponseCode GeneralResponse::responseCode(int code) {
|
|||
case TRI_ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX:
|
||||
case TRI_ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION:
|
||||
case TRI_ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF:
|
||||
case TRI_ERROR_GRAPH_EDGE_COLLECTION_NOT_USED:
|
||||
case TRI_ERROR_GRAPH_INVALID_EXAMPLE_ARRAY_OBJECT_STRING:
|
||||
case TRI_ERROR_GRAPH_INVALID_EXAMPLE_ARRAY_OBJECT:
|
||||
case TRI_ERROR_GRAPH_INVALID_NUMBER_OF_ARGUMENTS:
|
||||
|
@ -380,6 +379,7 @@ rest::ResponseCode GeneralResponse::responseCode(int code) {
|
|||
case TRI_ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST:
|
||||
case TRI_ERROR_GRAPH_NO_GRAPH_COLLECTION:
|
||||
case TRI_ERROR_QUEUE_UNKNOWN:
|
||||
case TRI_ERROR_GRAPH_EDGE_COLLECTION_NOT_USED:
|
||||
return ResponseCode::NOT_FOUND;
|
||||
|
||||
case TRI_ERROR_CLUSTER_SHARD_LEADER_REFUSES_REPLICATION:
|
||||
|
|
|
@ -38,6 +38,11 @@ TRI_v8_global_t::TRI_v8_global_t(v8::Isolate* isolate)
|
|||
VocbaseTempl(),
|
||||
EnvTempl(),
|
||||
UsersTempl(),
|
||||
GeneralGraphModuleTempl(),
|
||||
GeneralGraphTempl(),
|
||||
#ifdef USE_ENTERPRISE
|
||||
SmartGraphTempl(),
|
||||
#endif
|
||||
|
||||
BufferTempl(),
|
||||
|
||||
|
|
|
@ -363,6 +363,19 @@ struct TRI_v8_global_t {
|
|||
/// @brief users template
|
||||
v8::Persistent<v8::ObjectTemplate> UsersTempl;
|
||||
|
||||
/// @brief general graphs module template
|
||||
v8::Persistent<v8::ObjectTemplate> GeneralGraphModuleTempl;
|
||||
|
||||
/// @brief general graph class template
|
||||
v8::Persistent<v8::ObjectTemplate> GeneralGraphTempl;
|
||||
|
||||
#ifdef USE_ENTERPRISE
|
||||
/// @brief smart graph class template
|
||||
v8::Persistent<v8::ObjectTemplate> SmartGraphTempl;
|
||||
// there is no smart graph module becuase they are
|
||||
// identical, just return different graph instances.
|
||||
#endif
|
||||
|
||||
/// @brief Buffer template
|
||||
v8::Persistent<v8::FunctionTemplate> BufferTempl;
|
||||
|
||||
|
|
1173
lib/V8/v8-json.cpp
1173
lib/V8/v8-json.cpp
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue