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
|
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
|
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.
|
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}
|
@RESTQUERYPARAM{waitForSync,boolean,optional}
|
||||||
Define if the request should wait until synced to disk.
|
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
|
@RESTHEADERPARAMETERS
|
||||||
|
|
||||||
@RESTHEADERPARAM{if-match,string,optional}
|
@RESTHEADERPARAM{if-match,string,optional}
|
||||||
|
|
|
@ -26,6 +26,16 @@ Define if the request should wait until synced to disk.
|
||||||
@RESTQUERYPARAM{keepNull,boolean,optional}
|
@RESTQUERYPARAM{keepNull,boolean,optional}
|
||||||
Define if values set to null should be stored. By default the key is not removed from the document.
|
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}
|
@RESTALLBODYPARAM{updateAttributes,object,required}
|
||||||
The body has to be a JSON object containing the attributes to be updated.
|
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}
|
@RESTQUERYPARAM{waitForSync,boolean,optional}
|
||||||
Define if the request should wait until synced to disk.
|
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
|
@RESTHEADERPARAMETERS
|
||||||
|
|
||||||
@RESTHEADERPARAM{if-match,string,optional}
|
@RESTHEADERPARAM{if-match,string,optional}
|
||||||
|
|
|
@ -23,6 +23,14 @@ The *_key* attribute of the vertex.
|
||||||
@RESTQUERYPARAM{waitForSync,boolean,optional}
|
@RESTQUERYPARAM{waitForSync,boolean,optional}
|
||||||
Define if the request should wait until synced to disk.
|
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
|
@RESTHEADERPARAMETERS
|
||||||
|
|
||||||
@RESTHEADERPARAM{if-match,string,optional}
|
@RESTHEADERPARAM{if-match,string,optional}
|
||||||
|
|
|
@ -26,6 +26,13 @@ Define if the request should wait until synced to disk.
|
||||||
@RESTQUERYPARAM{keepNull,boolean,optional}
|
@RESTQUERYPARAM{keepNull,boolean,optional}
|
||||||
Define if values set to null should be stored. By default the key is not removed from the document.
|
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
|
@RESTHEADERPARAMETERS
|
||||||
|
|
||||||
@RESTHEADERPARAM{if-match,string,optional}
|
@RESTHEADERPARAM{if-match,string,optional}
|
||||||
|
|
|
@ -23,6 +23,16 @@ The *_key* attribute of the vertex.
|
||||||
@RESTQUERYPARAM{waitForSync,boolean,optional}
|
@RESTQUERYPARAM{waitForSync,boolean,optional}
|
||||||
Define if the request should wait until synced to disk.
|
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
|
@RESTHEADERPARAMETERS
|
||||||
|
|
||||||
@RESTHEADERPARAM{if-match,string,optional}
|
@RESTHEADERPARAM{if-match,string,optional}
|
||||||
|
|
|
@ -159,7 +159,6 @@ describe ArangoDB do
|
||||||
return doc
|
return doc
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def create_edge (waitForSync, graph_name, collection, from, to, body, options = {})
|
def create_edge (waitForSync, graph_name, collection, from, to, body, options = {})
|
||||||
cmd = edge_endpoint(graph_name, collection)
|
cmd = edge_endpoint(graph_name, collection)
|
||||||
cmd = cmd + "?waitForSync=#{waitForSync}"
|
cmd = cmd + "?waitForSync=#{waitForSync}"
|
||||||
|
@ -282,6 +281,7 @@ describe ArangoDB do
|
||||||
second_def = { "collection" => bought_collection, "from" => [user_collection], "to" => [product_collection] }
|
second_def = { "collection" => bought_collection, "from" => [user_collection], "to" => [product_collection] }
|
||||||
doc = additional_edge_definition(sync, graph_name, second_def )
|
doc = additional_edge_definition(sync, graph_name, second_def )
|
||||||
edge_definition.push(second_def)
|
edge_definition.push(second_def)
|
||||||
|
edge_definition = edge_definition.sort_by { |d| [ -d["collection"] ] }
|
||||||
|
|
||||||
doc.code.should eq(202)
|
doc.code.should eq(202)
|
||||||
doc.parsed_response['error'].should eq(false)
|
doc.parsed_response['error'].should eq(false)
|
||||||
|
@ -848,7 +848,10 @@ describe ArangoDB do
|
||||||
it "can not replace a non existing edge" do
|
it "can not replace a non existing edge" do
|
||||||
key = "unknownKey"
|
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.code.should eq(404)
|
||||||
doc.parsed_response['error'].should eq(true)
|
doc.parsed_response['error'].should eq(true)
|
||||||
doc.parsed_response['errorMessage'].should include("document not found")
|
doc.parsed_response['errorMessage'].should include("document not found")
|
||||||
|
@ -1169,11 +1172,18 @@ describe ArangoDB do
|
||||||
doc.parsed_response['code'].should eq(404)
|
doc.parsed_response['code'].should eq(404)
|
||||||
end
|
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)
|
def check404Edge (doc)
|
||||||
check404(doc)
|
check404(doc)
|
||||||
doc.parsed_response['errorNum'].should eq(1930)
|
doc.parsed_response['errorNum'].should eq(1930)
|
||||||
doc.parsed_response['errorMessage'].should eq("edge collection not used in graph")
|
doc.parsed_response['errorMessage'].should eq("edge collection not used in graph")
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def check404Vertex (doc)
|
def check404Vertex (doc)
|
||||||
|
@ -1181,10 +1191,23 @@ describe ArangoDB do
|
||||||
doc.parsed_response['errorNum'].should eq(1926)
|
doc.parsed_response['errorNum'].should eq(1926)
|
||||||
end
|
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)
|
def check404CRUD (doc)
|
||||||
check404(doc)
|
check404(doc)
|
||||||
doc.parsed_response['errorNum'].should eq(1203)
|
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
|
end
|
||||||
|
|
||||||
it "change edge definition" do
|
it "change edge definition" do
|
||||||
|
@ -1197,7 +1220,8 @@ describe ArangoDB do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "delete vertex collection" do
|
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
|
end
|
||||||
|
|
||||||
it "create vertex" do
|
it "create vertex" do
|
||||||
|
@ -1208,6 +1232,8 @@ describe ArangoDB do
|
||||||
check404CRUD(get_vertex(graph_name, unknown_name, unknown_name))
|
check404CRUD(get_vertex(graph_name, unknown_name, unknown_name))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO add tests where the edge/vertex collection is not part of the graph, but
|
||||||
|
# the given key exists!
|
||||||
it "update vertex" do
|
it "update vertex" do
|
||||||
check404CRUD(update_vertex( sync, graph_name, unknown_name, unknown_name, {}))
|
check404CRUD(update_vertex( sync, graph_name, unknown_name, unknown_name, {}))
|
||||||
end
|
end
|
||||||
|
@ -1221,7 +1247,7 @@ describe ArangoDB do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "create edge" do
|
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
|
end
|
||||||
|
|
||||||
it "get edge" do
|
it "get edge" do
|
||||||
|
@ -1277,7 +1303,10 @@ describe ArangoDB do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "replace edge" do
|
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
|
end
|
||||||
|
|
||||||
it "delete edge" do
|
it "delete edge" do
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "Basics/StringUtils.h"
|
#include "Basics/StringUtils.h"
|
||||||
#include "Basics/tri-strings.h"
|
#include "Basics/tri-strings.h"
|
||||||
#include "Cluster/ClusterInfo.h"
|
#include "Cluster/ClusterInfo.h"
|
||||||
|
#include "Graph/Graph.h"
|
||||||
#include "Transaction/Helpers.h"
|
#include "Transaction/Helpers.h"
|
||||||
#include "Utils/CollectionNameResolver.h"
|
#include "Utils/CollectionNameResolver.h"
|
||||||
#include "VocBase/LogicalCollection.h"
|
#include "VocBase/LogicalCollection.h"
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "Aql/Query.h"
|
#include "Aql/Query.h"
|
||||||
#include "Cluster/ServerState.h"
|
#include "Cluster/ServerState.h"
|
||||||
#include "Graph/BaseOptions.h"
|
#include "Graph/BaseOptions.h"
|
||||||
|
#include "Graph/Graph.h"
|
||||||
#include "Utils/CollectionNameResolver.h"
|
#include "Utils/CollectionNameResolver.h"
|
||||||
#include "VocBase/LogicalCollection.h"
|
#include "VocBase/LogicalCollection.h"
|
||||||
|
|
||||||
|
|
|
@ -32,12 +32,11 @@ namespace arangodb {
|
||||||
|
|
||||||
namespace graph {
|
namespace graph {
|
||||||
struct BaseOptions;
|
struct BaseOptions;
|
||||||
|
class Graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace aql {
|
namespace aql {
|
||||||
|
|
||||||
class Graph;
|
|
||||||
|
|
||||||
// @brief This is a pure virtual super-class for all AQL graph operations
|
// @brief This is a pure virtual super-class for all AQL graph operations
|
||||||
// It does the generally required:
|
// It does the generally required:
|
||||||
// * graph info parsing
|
// * graph info parsing
|
||||||
|
@ -145,7 +144,7 @@ class GraphNode : public ExecutionNode {
|
||||||
Variable const* _edgeOutVariable;
|
Variable const* _edgeOutVariable;
|
||||||
|
|
||||||
/// @brief our graph...
|
/// @brief our graph...
|
||||||
Graph const* _graphObj;
|
graph::Graph const* _graphObj;
|
||||||
|
|
||||||
/// @brief Temporary pseudo variable for the currently traversed object.
|
/// @brief Temporary pseudo variable for the currently traversed object.
|
||||||
Variable const* _tmpObjVariable;
|
Variable const* _tmpObjVariable;
|
||||||
|
|
|
@ -21,20 +21,17 @@
|
||||||
/// @author Michael Hackstein
|
/// @author Michael Hackstein
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <velocypack/Iterator.h>
|
||||||
|
|
||||||
#include "Graphs.h"
|
#include "Graphs.h"
|
||||||
#include "Aql/AstNode.h"
|
#include "Aql/AstNode.h"
|
||||||
#include "Basics/StaticStrings.h"
|
#include "Basics/StaticStrings.h"
|
||||||
#include "Basics/VelocyPackHelper.h"
|
#include "Basics/VelocyPackHelper.h"
|
||||||
|
#include "Graph/Graph.h"
|
||||||
#include <velocypack/Iterator.h>
|
|
||||||
#include <velocypack/velocypack-aliases.h>
|
|
||||||
|
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
using namespace arangodb::aql;
|
using namespace arangodb::aql;
|
||||||
|
|
||||||
char const* Graph::_attrEdgeDefs = "edgeDefinitions";
|
|
||||||
char const* Graph::_attrOrphans = "orphanCollections";
|
|
||||||
|
|
||||||
EdgeConditionBuilder::EdgeConditionBuilder(AstNode* modCondition)
|
EdgeConditionBuilder::EdgeConditionBuilder(AstNode* modCondition)
|
||||||
: _fromCondition(nullptr),
|
: _fromCondition(nullptr),
|
||||||
_toCondition(nullptr),
|
_toCondition(nullptr),
|
||||||
|
@ -161,83 +158,3 @@ void EdgeConditionBuilderContainer::setVertexId(std::string const& id) {
|
||||||
_compareNode->setStringValue(id.c_str(), id.length());
|
_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
|
#ifndef ARANGOD_AQL_GRAPHS_H
|
||||||
#define ARANGOD_AQL_GRAPHS_H 1
|
#define ARANGOD_AQL_GRAPHS_H 1
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
|
||||||
#include "Aql/VariableGenerator.h"
|
#include "Aql/VariableGenerator.h"
|
||||||
|
#include "Basics/Common.h"
|
||||||
|
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
|
|
||||||
|
@ -141,51 +141,6 @@ class EdgeConditionBuilderContainer final : public EdgeConditionBuilder {
|
||||||
VariableGenerator _varGen;
|
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 aql
|
||||||
} // namespace arangodb
|
} // namespace arangodb
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
#include "Basics/fasthash.h"
|
#include "Basics/fasthash.h"
|
||||||
#include "Cluster/ServerState.h"
|
#include "Cluster/ServerState.h"
|
||||||
#include "GeneralServer/AuthenticationFeature.h"
|
#include "GeneralServer/AuthenticationFeature.h"
|
||||||
|
#include "Graph/Graph.h"
|
||||||
|
#include "Graph/GraphManager.h"
|
||||||
#include "Logger/Logger.h"
|
#include "Logger/Logger.h"
|
||||||
#include "RestServer/AqlFeature.h"
|
#include "RestServer/AqlFeature.h"
|
||||||
#include "StorageEngine/TransactionState.h"
|
#include "StorageEngine/TransactionState.h"
|
||||||
|
@ -49,12 +51,9 @@
|
||||||
#include "V8/v8-conv.h"
|
#include "V8/v8-conv.h"
|
||||||
#include "V8/v8-vpack.h"
|
#include "V8/v8-vpack.h"
|
||||||
#include "V8Server/V8DealerFeature.h"
|
#include "V8Server/V8DealerFeature.h"
|
||||||
#include "VocBase/Graphs.h"
|
|
||||||
#include "VocBase/vocbase.h"
|
#include "VocBase/vocbase.h"
|
||||||
|
|
||||||
#include <velocypack/Builder.h>
|
|
||||||
#include <velocypack/Iterator.h>
|
#include <velocypack/Iterator.h>
|
||||||
#include <velocypack/velocypack-aliases.h>
|
|
||||||
|
|
||||||
#ifndef USE_PLAN_CACHE
|
#ifndef USE_PLAN_CACHE
|
||||||
#undef 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
|
/// @brief look up a graph either from our cache list or from the _graphs
|
||||||
/// collection
|
/// collection
|
||||||
Graph const* Query::lookupGraphByName(std::string const& name) {
|
graph::Graph const* Query::lookupGraphByName(std::string const& name) {
|
||||||
auto it = _graphs.find(name);
|
auto it = _graphs.find(name);
|
||||||
|
|
||||||
if (it == _graphs.end()) {
|
if (it != _graphs.end()) {
|
||||||
std::unique_ptr<arangodb::aql::Graph> g(
|
return it->second.get();
|
||||||
arangodb::lookupGraphByName(createTransactionContext(), name));
|
|
||||||
|
|
||||||
if (g == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = _graphs.emplace(name, std::move(g));
|
|
||||||
TRI_ASSERT(result.second);
|
|
||||||
it = result.first;
|
|
||||||
}
|
}
|
||||||
|
graph::GraphManager graphManager{_vocbase, _contextOwnedByExterior};
|
||||||
TRI_ASSERT((*it).second != nullptr);
|
|
||||||
return (*it).second.get();
|
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
|
/// @brief returns the next query id
|
||||||
|
|
|
@ -58,6 +58,10 @@ namespace velocypack {
|
||||||
class Builder;
|
class Builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace graph {
|
||||||
|
class Graph;
|
||||||
|
}
|
||||||
|
|
||||||
namespace aql {
|
namespace aql {
|
||||||
|
|
||||||
struct AstNode;
|
struct AstNode;
|
||||||
|
@ -280,7 +284,7 @@ class Query {
|
||||||
std::string getStateString() const;
|
std::string getStateString() const;
|
||||||
|
|
||||||
/// @brief look up a graph in the _graphs collection
|
/// @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
|
/// @brief return the bind parameters as passed by the user
|
||||||
std::shared_ptr<arangodb::velocypack::Builder> bindParameters() const {
|
std::shared_ptr<arangodb::velocypack::Builder> bindParameters() const {
|
||||||
|
@ -355,7 +359,7 @@ class Query {
|
||||||
V8Context* _context;
|
V8Context* _context;
|
||||||
|
|
||||||
/// @brief graphs used in query, identified by name
|
/// @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
|
/// @brief the actual query string
|
||||||
QueryString _queryString;
|
QueryString _queryString;
|
||||||
|
|
|
@ -556,7 +556,7 @@ auth::Level auth::User::collectionAuthLevel(std::string const& dbname,
|
||||||
return auth::Level::NONE; // invalid collection names
|
return auth::Level::NONE; // invalid collection names
|
||||||
}
|
}
|
||||||
// we must have got a non-empty collection name when we get here
|
// 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] == '_';
|
bool isSystem = cname[0] == '_';
|
||||||
if (isSystem) {
|
if (isSystem) {
|
||||||
|
|
|
@ -738,8 +738,9 @@ auth::Level auth::UserManager::collectionAuthLevel(std::string const& user,
|
||||||
}
|
}
|
||||||
|
|
||||||
auth::Level level;
|
auth::Level level;
|
||||||
if (coll[0] >= '0' && coll[0] <= '9') {
|
if (isdigit(coll[0])) {
|
||||||
std::string tmpColl = DatabaseFeature::DATABASE->translateCollectionName(dbname, coll);
|
std::string tmpColl =
|
||||||
|
DatabaseFeature::DATABASE->translateCollectionName(dbname, coll);
|
||||||
level = it->second.collectionAuthLevel(dbname, tmpColl);
|
level = it->second.collectionAuthLevel(dbname, tmpColl);
|
||||||
} else {
|
} else {
|
||||||
level = it->second.collectionAuthLevel(dbname, coll);
|
level = it->second.collectionAuthLevel(dbname, coll);
|
||||||
|
|
|
@ -323,6 +323,9 @@ SET(ARANGOD_SOURCES
|
||||||
Graph/ConstantWeightShortestPathFinder.cpp
|
Graph/ConstantWeightShortestPathFinder.cpp
|
||||||
Graph/ClusterTraverserCache.cpp
|
Graph/ClusterTraverserCache.cpp
|
||||||
Graph/EdgeCollectionInfo.cpp
|
Graph/EdgeCollectionInfo.cpp
|
||||||
|
Graph/Graph.cpp
|
||||||
|
Graph/GraphManager.cpp
|
||||||
|
Graph/GraphOperations.cpp
|
||||||
Graph/NeighborsEnumerator.cpp
|
Graph/NeighborsEnumerator.cpp
|
||||||
Graph/PathEnumerator.cpp
|
Graph/PathEnumerator.cpp
|
||||||
Graph/ShortestPathOptions.cpp
|
Graph/ShortestPathOptions.cpp
|
||||||
|
@ -404,6 +407,7 @@ SET(ARANGOD_SOURCES
|
||||||
RestHandler/RestEndpointHandler.cpp
|
RestHandler/RestEndpointHandler.cpp
|
||||||
RestHandler/RestEngineHandler.cpp
|
RestHandler/RestEngineHandler.cpp
|
||||||
RestHandler/RestExplainHandler.cpp
|
RestHandler/RestExplainHandler.cpp
|
||||||
|
RestHandler/RestGraphHandler.cpp
|
||||||
RestHandler/RestImportHandler.cpp
|
RestHandler/RestImportHandler.cpp
|
||||||
RestHandler/RestIndexHandler.cpp
|
RestHandler/RestIndexHandler.cpp
|
||||||
RestHandler/RestJobHandler.cpp
|
RestHandler/RestJobHandler.cpp
|
||||||
|
@ -507,6 +511,7 @@ SET(ARANGOD_SOURCES
|
||||||
V8Server/v8-vocbase.cpp
|
V8Server/v8-vocbase.cpp
|
||||||
V8Server/v8-voccursor.cpp
|
V8Server/v8-voccursor.cpp
|
||||||
V8Server/v8-vocindex.cpp
|
V8Server/v8-vocindex.cpp
|
||||||
|
V8Server/v8-general-graph.cpp
|
||||||
VocBase/Methods/AqlUserFunctions.cpp
|
VocBase/Methods/AqlUserFunctions.cpp
|
||||||
VocBase/Methods/Collections.cpp
|
VocBase/Methods/Collections.cpp
|
||||||
VocBase/Methods/Databases.cpp
|
VocBase/Methods/Databases.cpp
|
||||||
|
@ -516,7 +521,6 @@ SET(ARANGOD_SOURCES
|
||||||
VocBase/Methods/Upgrade.cpp
|
VocBase/Methods/Upgrade.cpp
|
||||||
VocBase/Methods/UpgradeTasks.cpp
|
VocBase/Methods/UpgradeTasks.cpp
|
||||||
VocBase/Methods/Version.cpp
|
VocBase/Methods/Version.cpp
|
||||||
VocBase/Graphs.cpp
|
|
||||||
VocBase/KeyGenerator.cpp
|
VocBase/KeyGenerator.cpp
|
||||||
VocBase/LogicalCollection.cpp
|
VocBase/LogicalCollection.cpp
|
||||||
VocBase/LogicalDataSource.cpp
|
VocBase/LogicalDataSource.cpp
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
|
#include "Basics/Result.h"
|
||||||
|
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
|
|
||||||
|
@ -57,7 +58,13 @@ namespace arangodb {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ResultT : public arangodb::Result {
|
class ResultT : public arangodb::Result {
|
||||||
public:
|
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) {
|
ResultT static error(int errorNumber) {
|
||||||
return ResultT(boost::none, errorNumber);
|
return ResultT(boost::none, errorNumber);
|
||||||
|
@ -67,17 +74,23 @@ class ResultT : public arangodb::Result {
|
||||||
return ResultT(boost::none, errorNumber, errorMessage);
|
return ResultT(boost::none, errorNumber, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is not explicit on purpose
|
// These are not explicit on purpose
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
|
|
||||||
ResultT(Result const& other) : Result(other) {
|
ResultT(Result const& other) : Result(other) {
|
||||||
// .ok() is not allowed here, as _val should be expected to be initialized
|
// .ok() is not allowed here, as _val should be expected to be initialized
|
||||||
// iff .ok() is true.
|
// iff .ok() is true.
|
||||||
TRI_ASSERT(other.fail());
|
TRI_ASSERT(other.fail());
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is not explicit on purpose
|
ResultT(Result&& other) : Result(std::move(other)) {
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
|
// .ok() is not allowed here, as _val should be expected to be initialized
|
||||||
ResultT(T&& val) : ResultT(std::forward<T>(val), TRI_ERROR_NO_ERROR) {}
|
// 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;
|
ResultT() = delete;
|
||||||
|
|
||||||
|
@ -91,6 +104,8 @@ class ResultT : public arangodb::Result {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result copy_result() const { return *this; }
|
||||||
|
|
||||||
// These would be very convenient, but also make it very easy to accidentally
|
// 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.
|
// 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;
|
boost::optional<T> _val;
|
||||||
|
|
||||||
ResultT(boost::optional<T>&& val_, int errorNumber)
|
ResultT(boost::optional<T>&& val_, int errorNumber)
|
||||||
: Result(errorNumber), _val(val_) {}
|
: Result(errorNumber), _val(std::move(val_)) {}
|
||||||
|
|
||||||
ResultT(boost::optional<T>&& val_, int errorNumber,
|
ResultT(boost::optional<T>&& val_, int errorNumber,
|
||||||
std::string const& errorMessage)
|
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
|
} // namespace arangodb
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "GeneralServer/AuthenticationFeature.h"
|
#include "GeneralServer/AuthenticationFeature.h"
|
||||||
#include "GeneralServer/GeneralServer.h"
|
#include "GeneralServer/GeneralServer.h"
|
||||||
#include "GeneralServer/RestHandlerFactory.h"
|
#include "GeneralServer/RestHandlerFactory.h"
|
||||||
|
#include "Graph/Graph.h"
|
||||||
#include "InternalRestHandler/InternalRestTraverserHandler.h"
|
#include "InternalRestHandler/InternalRestTraverserHandler.h"
|
||||||
#include "ProgramOptions/Parameters.h"
|
#include "ProgramOptions/Parameters.h"
|
||||||
#include "ProgramOptions/ProgramOptions.h"
|
#include "ProgramOptions/ProgramOptions.h"
|
||||||
|
@ -60,6 +61,7 @@
|
||||||
#include "RestHandler/RestEndpointHandler.h"
|
#include "RestHandler/RestEndpointHandler.h"
|
||||||
#include "RestHandler/RestEngineHandler.h"
|
#include "RestHandler/RestEngineHandler.h"
|
||||||
#include "RestHandler/RestExplainHandler.h"
|
#include "RestHandler/RestExplainHandler.h"
|
||||||
|
#include "RestHandler/RestGraphHandler.h"
|
||||||
#include "RestHandler/RestHandlerCreator.h"
|
#include "RestHandler/RestHandlerCreator.h"
|
||||||
#include "RestHandler/RestImportHandler.h"
|
#include "RestHandler/RestImportHandler.h"
|
||||||
#include "RestHandler/RestIndexHandler.h"
|
#include "RestHandler/RestIndexHandler.h"
|
||||||
|
@ -68,9 +70,9 @@
|
||||||
#include "RestHandler/RestPregelHandler.h"
|
#include "RestHandler/RestPregelHandler.h"
|
||||||
#include "RestHandler/RestQueryCacheHandler.h"
|
#include "RestHandler/RestQueryCacheHandler.h"
|
||||||
#include "RestHandler/RestQueryHandler.h"
|
#include "RestHandler/RestQueryHandler.h"
|
||||||
|
#include "RestHandler/RestRepairHandler.h"
|
||||||
#include "RestHandler/RestShutdownHandler.h"
|
#include "RestHandler/RestShutdownHandler.h"
|
||||||
#include "RestHandler/RestSimpleHandler.h"
|
#include "RestHandler/RestSimpleHandler.h"
|
||||||
#include "RestHandler/RestRepairHandler.h"
|
|
||||||
#include "RestHandler/RestSimpleQueryHandler.h"
|
#include "RestHandler/RestSimpleQueryHandler.h"
|
||||||
#include "RestHandler/RestStatusHandler.h"
|
#include "RestHandler/RestStatusHandler.h"
|
||||||
#include "RestHandler/RestTasksHandler.h"
|
#include "RestHandler/RestTasksHandler.h"
|
||||||
|
@ -335,6 +337,10 @@ void GeneralServerFeature::defineHandlers() {
|
||||||
RestVocbaseBaseHandler::EDGES_PATH,
|
RestVocbaseBaseHandler::EDGES_PATH,
|
||||||
RestHandlerCreator<RestEdgesHandler>::createNoData);
|
RestHandlerCreator<RestEdgesHandler>::createNoData);
|
||||||
|
|
||||||
|
_handlerFactory->addPrefixHandler(
|
||||||
|
RestVocbaseBaseHandler::GHARIAL_PATH,
|
||||||
|
RestHandlerCreator<RestGraphHandler>::createNoData);
|
||||||
|
|
||||||
_handlerFactory->addPrefixHandler(
|
_handlerFactory->addPrefixHandler(
|
||||||
RestVocbaseBaseHandler::ENDPOINT_PATH,
|
RestVocbaseBaseHandler::ENDPOINT_PATH,
|
||||||
RestHandlerCreator<RestEndpointHandler>::createNoData);
|
RestHandlerCreator<RestEndpointHandler>::createNoData);
|
||||||
|
|
|
@ -84,7 +84,7 @@ class GeneralServerFeature final
|
||||||
|
|
||||||
return GENERAL_SERVER->_accessControlAllowOrigins;
|
return GENERAL_SERVER->_accessControlAllowOrigins;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static GeneralServerFeature* GENERAL_SERVER;
|
static GeneralServerFeature* GENERAL_SERVER;
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ class GeneralServerFeature final
|
||||||
void start() override final;
|
void start() override final;
|
||||||
void stop() override final;
|
void stop() override final;
|
||||||
void unprepare() override final;
|
void unprepare() override final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double _keepAliveTimeout = 300.0;
|
double _keepAliveTimeout = 300.0;
|
||||||
bool _allowMethodOverride;
|
bool _allowMethodOverride;
|
||||||
|
@ -118,7 +118,9 @@ class GeneralServerFeature final
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<rest::RestHandlerFactory> _handlerFactory;
|
std::unique_ptr<rest::RestHandlerFactory> _handlerFactory;
|
||||||
std::unique_ptr<rest::AsyncJobManager> _jobManager;
|
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;
|
std::vector<rest::GeneralServer*> _servers;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace arangodb {
|
||||||
class GeneralRequest;
|
class GeneralRequest;
|
||||||
class RequestStatistics;
|
class RequestStatistics;
|
||||||
|
|
||||||
enum class RestStatus { DONE, WAITING, FAIL};
|
enum class RestStatus { DONE, WAITING, FAIL };
|
||||||
|
|
||||||
namespace rest {
|
namespace rest {
|
||||||
class RestHandler : public std::enable_shared_from_this<RestHandler> {
|
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 "RestControlPregelHandler.h"
|
||||||
|
|
||||||
#include "ApplicationFeatures/ApplicationServer.h"
|
#include "ApplicationFeatures/ApplicationServer.h"
|
||||||
#include "Aql/Graphs.h"
|
|
||||||
#include "Basics/VelocyPackHelper.h"
|
#include "Basics/VelocyPackHelper.h"
|
||||||
#include "Cluster/ServerState.h"
|
#include "Cluster/ServerState.h"
|
||||||
#include "Pregel/Conductor.h"
|
#include "Pregel/Conductor.h"
|
||||||
|
@ -33,7 +32,8 @@
|
||||||
#include "Transaction/StandaloneContext.h"
|
#include "Transaction/StandaloneContext.h"
|
||||||
#include "V8/v8-vpack.h"
|
#include "V8/v8-vpack.h"
|
||||||
#include "V8Server/V8DealerFeature.h"
|
#include "V8Server/V8DealerFeature.h"
|
||||||
#include "VocBase/Graphs.h"
|
#include "Graph/Graph.h"
|
||||||
|
#include "Graph/GraphManager.h"
|
||||||
#include "VocBase/Methods/Tasks.h"
|
#include "VocBase/Methods/Tasks.h"
|
||||||
|
|
||||||
#include <velocypack/Builder.h>
|
#include <velocypack/Builder.h>
|
||||||
|
@ -133,12 +133,13 @@ void RestControlPregelHandler::startExecution() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ctx = transaction::StandaloneContext::Create(_vocbase);
|
graph::GraphManager gmngr{_vocbase};
|
||||||
auto graph = lookupGraphByName(ctx, gs);
|
auto graphRes = gmngr.lookupGraphByName(gs);
|
||||||
if (nullptr == graph) {
|
if (graphRes.fail()) {
|
||||||
generateError(TRI_ERROR_GRAPH_NOT_FOUND);
|
generateError(graphRes.copy_result());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
std::unique_ptr<graph::Graph> graph = std::move(graphRes.get());
|
||||||
|
|
||||||
auto gv = graph->vertexCollections();
|
auto gv = graph->vertexCollections();
|
||||||
for (auto& v : gv) {
|
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()) {
|
if (ClusterInfo* clusterInfo = ClusterInfo::instance()) {
|
||||||
clusterInfo->loadPlan();
|
clusterInfo->loadPlan();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return RestStatus::DONE;
|
return RestStatus::DONE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,12 @@ std::string const RestVocbaseBaseHandler::DOCUMENT_PATH = "/_api/document";
|
||||||
|
|
||||||
std::string const RestVocbaseBaseHandler::EDGES_PATH = "/_api/edges";
|
std::string const RestVocbaseBaseHandler::EDGES_PATH = "/_api/edges";
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief gharial graph api path
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::string const RestVocbaseBaseHandler::GHARIAL_PATH = "/_api/gharial";
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief endpoint path
|
/// @brief endpoint path
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -103,6 +103,12 @@ class RestVocbaseBaseHandler : public RestBaseHandler {
|
||||||
|
|
||||||
static std::string const EDGES_PATH;
|
static std::string const EDGES_PATH;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief gharial graph api path
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static std::string const GHARIAL_PATH;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief endpoint 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
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||||
///
|
///
|
||||||
/// @author Michael Hackstein
|
/// @author Heiko Kernbach
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef ARANGOD_VOCBASE_GRAPHS_H
|
#ifndef ARANGOD_V8_SERVER_V8_GENERAL_GRAPH_H
|
||||||
#define ARANGOD_VOCBASE_GRAPHS_H 1
|
#define ARANGOD_V8_SERVER_V8_GENERAL_GRAPH_H 1
|
||||||
|
|
||||||
#include "VocBase/vocbase.h"
|
#include <v8.h>
|
||||||
|
|
||||||
namespace arangodb {
|
struct TRI_vocbase_t;
|
||||||
namespace aql {
|
struct TRI_v8_global_t;
|
||||||
class Graph;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace transaction {
|
void TRI_InitV8GeneralGraph(v8::Handle<v8::Context> context,
|
||||||
class Context;
|
TRI_vocbase_t* vocbase, TRI_v8_global_t* v8g,
|
||||||
}
|
v8::Isolate* isolate);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @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
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -79,6 +79,7 @@
|
||||||
#include "V8Server/v8-views.h"
|
#include "V8Server/v8-views.h"
|
||||||
#include "V8Server/v8-voccursor.h"
|
#include "V8Server/v8-voccursor.h"
|
||||||
#include "V8Server/v8-vocindex.h"
|
#include "V8Server/v8-vocindex.h"
|
||||||
|
#include "V8Server/v8-general-graph.h"
|
||||||
#include "VocBase/KeyGenerator.h"
|
#include "VocBase/KeyGenerator.h"
|
||||||
#include "VocBase/LogicalCollection.h"
|
#include "VocBase/LogicalCollection.h"
|
||||||
#include "VocBase/Methods/Databases.h"
|
#include "VocBase/Methods/Databases.h"
|
||||||
|
@ -2068,6 +2069,7 @@ void TRI_InitV8VocBridge(
|
||||||
TRI_InitV8Collections(context, &vocbase, v8g, isolate, ArangoNS);
|
TRI_InitV8Collections(context, &vocbase, v8g, isolate, ArangoNS);
|
||||||
TRI_InitV8Views(context, &vocbase, v8g, isolate, ArangoNS);
|
TRI_InitV8Views(context, &vocbase, v8g, isolate, ArangoNS);
|
||||||
TRI_InitV8Users(context, &vocbase, v8g, isolate);
|
TRI_InitV8Users(context, &vocbase, v8g, isolate);
|
||||||
|
TRI_InitV8GeneralGraph(context, &vocbase, v8g, isolate);
|
||||||
|
|
||||||
TRI_InitV8cursor(context, v8g);
|
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);
|
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.appendJsonEncoded(oldName.c_str(), oldName.size());
|
||||||
buffer.appendChar(',');
|
buffer.appendChar(',');
|
||||||
buffer.appendJsonEncoded(newName.c_str(), newName.size());
|
buffer.appendJsonEncoded(newName.c_str(), newName.size());
|
||||||
|
|
|
@ -655,7 +655,7 @@
|
||||||
} else {
|
} else {
|
||||||
newCollectionObject.isSmart = true;
|
newCollectionObject.isSmart = true;
|
||||||
newCollectionObject.options = {
|
newCollectionObject.options = {
|
||||||
numberOfShards: $('#new-numberOfShards').val(),
|
numberOfShards: parseInt($('#new-numberOfShards').val()),
|
||||||
smartGraphAttribute: $('#new-smartGraphAttribute').val(),
|
smartGraphAttribute: $('#new-smartGraphAttribute').val(),
|
||||||
replicationFactor: parseInt($('#new-replicationFactor').val())
|
replicationFactor: parseInt($('#new-replicationFactor').val())
|
||||||
};
|
};
|
||||||
|
@ -664,15 +664,15 @@
|
||||||
if (frontendConfig.isCluster) {
|
if (frontendConfig.isCluster) {
|
||||||
if ($('#general-numberOfShards').val().length > 0) {
|
if ($('#general-numberOfShards').val().length > 0) {
|
||||||
newCollectionObject.options = {
|
newCollectionObject.options = {
|
||||||
numberOfShards: $('#general-numberOfShards').val()
|
numberOfShards: parseInt($('#general-numberOfShards').val())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if ($('#general-replicationFactor').val().length > 0) {
|
if ($('#general-replicationFactor').val().length > 0) {
|
||||||
if (newCollectionObject.options) {
|
if (newCollectionObject.options) {
|
||||||
newCollectionObject.options.replicationFactor = $('#general-replicationFactor').val();
|
newCollectionObject.options.replicationFactor = parseInt($('#general-replicationFactor').val());
|
||||||
} else {
|
} else {
|
||||||
newCollectionObject.options = {
|
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
|
// / @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 arangodb = require('@arangodb');
|
||||||
const request = require('@arangodb/request');
|
const request = require('@arangodb/request');
|
||||||
|
|
||||||
const ERRORS = arangodb.errors;
|
const ERRORS = arangodb.errors;
|
||||||
const db = arangodb.db;
|
const db = arangodb.db;
|
||||||
const wait = require('internal').wait;
|
const internal = require('internal');
|
||||||
const extend = require('lodash').extend;
|
const wait = internal.wait;
|
||||||
|
|
||||||
describe('_api/gharial', () => {
|
describe('_api/gharial', () => {
|
||||||
|
|
||||||
|
@ -314,4 +316,296 @@ describe('_api/gharial', () => {
|
||||||
expect(db._collection(vName)).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', () => {
|
||||||
|
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_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_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_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_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
|
||||||
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
|
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
|
||||||
"SIMPLE_CLIENT_UNKNOWN_ERROR" : { "code" : 2000, "message" : "unknown client error" },
|
"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_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_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_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_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_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" },
|
"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;
|
let res = false;
|
||||||
if (col === null && !noCreate) {
|
if (col === null && !noCreate) {
|
||||||
if (type === ArangoCollection.TYPE_DOCUMENT) {
|
if (type === ArangoCollection.TYPE_DOCUMENT) {
|
||||||
if (options) {
|
col = db._create(name, options);
|
||||||
col = db._create(name, options);
|
|
||||||
} else {
|
|
||||||
col = db._create(name);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (options) {
|
col = db._createEdgeCollection(name, options);
|
||||||
col = db._createEdgeCollection(name, options);
|
|
||||||
} else {
|
|
||||||
col = db._createEdgeCollection(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
res = true;
|
res = true;
|
||||||
} else if (!(col instanceof ArangoCollection)) {
|
} 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
|
// / internal helper to sort a graph's edge definitions
|
||||||
// //////////////////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
var sortEdgeDefinition = function (edgeDefinition) {
|
var sortEdgeDefinitionInplace = function (edgeDefinition) {
|
||||||
edgeDefinition.from = edgeDefinition.from.sort();
|
edgeDefinition.from.sort();
|
||||||
edgeDefinition.to = edgeDefinition.to.sort();
|
edgeDefinition.to.sort();
|
||||||
return edgeDefinition;
|
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
|
// / @brief create a new graph
|
||||||
// //////////////////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -731,6 +731,13 @@ var checkIfMayBeDropped = function (colName, graphName, graphs) {
|
||||||
return result;
|
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.
|
// @brief Class Graph. Defines a graph in the Database.
|
||||||
class Graph {
|
class Graph {
|
||||||
constructor (info) {
|
constructor (info) {
|
||||||
|
@ -762,7 +769,7 @@ class Graph {
|
||||||
var self = this;
|
var self = this;
|
||||||
// Create Hidden Properties
|
// Create Hidden Properties
|
||||||
createHiddenProperty(this, '__useBuiltIn', useBuiltIn);
|
createHiddenProperty(this, '__useBuiltIn', useBuiltIn);
|
||||||
createHiddenProperty(this, '__name', info._key);
|
createHiddenProperty(this, '__name', info._key || info.name);
|
||||||
createHiddenProperty(this, '__vertexCollections', vertexCollections);
|
createHiddenProperty(this, '__vertexCollections', vertexCollections);
|
||||||
createHiddenProperty(this, '__edgeCollections', edgeCollections);
|
createHiddenProperty(this, '__edgeCollections', edgeCollections);
|
||||||
createHiddenProperty(this, '__edgeDefinitions', info.edgeDefinitions);
|
createHiddenProperty(this, '__edgeDefinitions', info.edgeDefinitions);
|
||||||
|
@ -779,7 +786,7 @@ class Graph {
|
||||||
|
|
||||||
// Create Hidden Functions
|
// Create Hidden Functions
|
||||||
createHiddenProperty(this, '__updateBindCollections', updateBindCollections);
|
createHiddenProperty(this, '__updateBindCollections', updateBindCollections);
|
||||||
createHiddenProperty(this, '__sortEdgeDefinition', sortEdgeDefinition);
|
createHiddenProperty(this, '__sortEdgeDefinition', sortEdgeDefinitionInplace);
|
||||||
updateBindCollections(self);
|
updateBindCollections(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1551,226 +1558,6 @@ class Graph {
|
||||||
return result;
|
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
|
// / @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;
|
err.errorMessage = arangodb.errors.ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION.message;
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
edgeDefinitions = _.cloneDeep(edgeDefinitions);
|
||||||
|
|
||||||
// check, if a collection is already used in a different edgeDefinition
|
// check, if a collection is already used in a different edgeDefinition
|
||||||
let tmpCollections = [];
|
let tmpCollections = [];
|
||||||
let tmpEdgeDefinitions = {};
|
let tmpEdgeDefinitions = {};
|
||||||
|
@ -2039,7 +1829,7 @@ exports._create = function (graphName, edgeDefinitions, orphanCollections, optio
|
||||||
(sGED) => {
|
(sGED) => {
|
||||||
var col = sGED.collection;
|
var col = sGED.collection;
|
||||||
if (tmpCollections.indexOf(col) !== -1) {
|
if (tmpCollections.indexOf(col) !== -1) {
|
||||||
if (JSON.stringify(sGED) !== JSON.stringify(tmpEdgeDefinitions[col])) {
|
if (!edgeDefinitionsEqual(sGED, tmpEdgeDefinitions[col])) {
|
||||||
let err = new ArangoError();
|
let err = new ArangoError();
|
||||||
err.errorNum = arangodb.errors.ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS.code;
|
err.errorNum = arangodb.errors.ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS.code;
|
||||||
err.errorMessage = col + ' ' +
|
err.errorMessage = col + ' ' +
|
||||||
|
@ -2076,12 +1866,7 @@ exports._create = function (graphName, edgeDefinitions, orphanCollections, optio
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
edgeDefinitions.forEach(
|
edgeDefinitions.forEach(sortEdgeDefinitionInplace);
|
||||||
(eD, index) => {
|
|
||||||
var tmp = sortEdgeDefinition(eD);
|
|
||||||
edgeDefinitions[index] = tmp;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
orphanCollections = orphanCollections.sort();
|
orphanCollections = orphanCollections.sort();
|
||||||
|
|
||||||
var data = gdb.save({
|
var data = gdb.save({
|
||||||
|
@ -2089,7 +1874,7 @@ exports._create = function (graphName, edgeDefinitions, orphanCollections, optio
|
||||||
'edgeDefinitions': edgeDefinitions,
|
'edgeDefinitions': edgeDefinitions,
|
||||||
'_key': graphName,
|
'_key': graphName,
|
||||||
'numberOfShards': options.numberOfShards || 1,
|
'numberOfShards': options.numberOfShards || 1,
|
||||||
'replicationFactor': options.replicationFactor || 1
|
'replicationFactor': options.replicationFactor || 1,
|
||||||
}, options);
|
}, options);
|
||||||
data.orphanCollections = orphanCollections;
|
data.orphanCollections = orphanCollections;
|
||||||
data.edgeDefinitions = edgeDefinitions;
|
data.edgeDefinitions = edgeDefinitions;
|
||||||
|
@ -2257,82 +2042,82 @@ exports._listObjects = function () {
|
||||||
exports._registerCompatibilityFunctions = function () {
|
exports._registerCompatibilityFunctions = function () {
|
||||||
const aqlfunctions = require('@arangodb/aql/functions');
|
const aqlfunctions = require('@arangodb/aql/functions');
|
||||||
aqlfunctions.register('arangodb::GRAPH_EDGES', function (graphName, vertexExample, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._edges(vertexExample, options);
|
return g._edges(vertexExample, options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_VERTICES', function (graphName, vertexExample, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._vertices(vertexExample, options);
|
return g._vertices(vertexExample, options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_NEIGHBORS', function (graphName, vertexExample, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._neighbors(vertexExample, options);
|
return g._neighbors(vertexExample, options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_COMMON_NEIGHBORS', function (graphName, vertex1Example, vertex2Example, options1, options2) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._commonNeighbors(vertex1Example, vertex2Example, options1, options2);
|
return g._commonNeighbors(vertex1Example, vertex2Example, options1, options2);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_COMMON_PROPERTIES', function (graphName, vertex1Example, vertex2Example, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._commonProperties(vertex1Example, vertex2Example, options);
|
return g._commonProperties(vertex1Example, vertex2Example, options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_PATHS', function (graphName, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._paths(options);
|
return g._paths(options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_SHORTEST_PATH', function (graphName, startVertexExample, edgeVertexExample, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._shortestPath(startVertexExample, edgeVertexExample, options);
|
return g._shortestPath(startVertexExample, edgeVertexExample, options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_DISTANCE_TO', function (graphName, startVertexExample, edgeVertexExample, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._distanceTo(startVertexExample, edgeVertexExample, options);
|
return g._distanceTo(startVertexExample, edgeVertexExample, options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_ABSOLUTE_ECCENTRICITY', function (graphName, vertexExample, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._absoluteEccentricity(vertexExample, options);
|
return g._absoluteEccentricity(vertexExample, options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_ECCENTRICITY', function (graphName, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._eccentricity(options);
|
return g._eccentricity(options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_ABSOLUTE_CLOSENESS', function (graphName, vertexExample, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._farness(vertexExample, options);
|
return g._farness(vertexExample, options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_CLOSENESS', function (graphName, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._closeness(options);
|
return g._closeness(options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_ABSOLUTE_BETWEENNESS', function (graphName, vertexExample, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._absoluteBetweenness(vertexExample, options);
|
return g._absoluteBetweenness(vertexExample, options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_BETWEENNESS', function (graphName, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._betweenness(options);
|
return g._betweenness(options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_RADIUS', function (graphName, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._radius(options);
|
return g._radius(options);
|
||||||
}, false);
|
}, false);
|
||||||
aqlfunctions.register('arangodb::GRAPH_DIAMETER', function (graphName, options) {
|
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);
|
var g = gm._graph(graphName);
|
||||||
return g._diameter(options);
|
return g._diameter(options);
|
||||||
}, false);
|
}, false);
|
|
@ -57,6 +57,8 @@ function GeneralGraphCreationSuite() {
|
||||||
var vn3 = "UnitTestVertices3";
|
var vn3 = "UnitTestVertices3";
|
||||||
var vn4 = "UnitTestVertices4";
|
var vn4 = "UnitTestVertices4";
|
||||||
var gn = "UnitTestGraph";
|
var gn = "UnitTestGraph";
|
||||||
|
var gn1 = "UnitTestGraph1";
|
||||||
|
var gn2 = "UnitTestGraph2";
|
||||||
var edgeDef = graph._edgeDefinitions(
|
var edgeDef = graph._edgeDefinitions(
|
||||||
graph._relation(rn, [vn1], [vn1]),
|
graph._relation(rn, [vn1], [vn1]),
|
||||||
graph._relation(rn1,
|
graph._relation(rn1,
|
||||||
|
@ -76,6 +78,14 @@ function GeneralGraphCreationSuite() {
|
||||||
vc5 = "UnitTestEdgeDefDeleteVertexCol5",
|
vc5 = "UnitTestEdgeDefDeleteVertexCol5",
|
||||||
vc6 = "UnitTestEdgeDefDeleteVertexCol6";
|
vc6 = "UnitTestEdgeDefDeleteVertexCol6";
|
||||||
|
|
||||||
|
var sortEdgeDefinition = function(edgeDefinition) {
|
||||||
|
return {
|
||||||
|
collection: edgeDefinition.collection,
|
||||||
|
from: edgeDefinition.from.slice().sort(),
|
||||||
|
to: edgeDefinition.to.slice().sort()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
||||||
setUp: function() {
|
setUp: function() {
|
||||||
|
@ -111,6 +121,12 @@ function GeneralGraphCreationSuite() {
|
||||||
graph._drop(gN2, true);
|
graph._drop(gN2, true);
|
||||||
} catch(ignore) {
|
} 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 () {
|
test_create : function () {
|
||||||
if (db._collection("_graphs").exists(gn)) {
|
if (db._collection("_graphs").exists(gn)) {
|
||||||
db._collection("_graphs").remove(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 () {
|
test_get_graph : function () {
|
||||||
if (db._collection("_graphs").exists(gn)) {
|
if (db._collection("_graphs").exists(gn)) {
|
||||||
db._collection("_graphs").remove(gn);
|
db._collection("_graphs").remove(gn);
|
||||||
|
@ -582,11 +655,17 @@ function GeneralGraphCreationSuite() {
|
||||||
g1._deleteEdgeDefinition(ec1);
|
g1._deleteEdgeDefinition(ec1);
|
||||||
assertEqual([dr2, dr3], g1.__edgeDefinitions);
|
assertEqual([dr2, dr3], g1.__edgeDefinitions);
|
||||||
assertEqual([vc1, vc2], g1._orphanCollections());
|
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);
|
assertTrue(db._collection(ec1) !== null);
|
||||||
|
|
||||||
g1._deleteEdgeDefinition(ec2);
|
g1._deleteEdgeDefinition(ec2);
|
||||||
assertEqual([dr3], g1.__edgeDefinitions);
|
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);
|
assertTrue(db._collection(ec2) !== null);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -601,14 +680,20 @@ function GeneralGraphCreationSuite() {
|
||||||
g1._deleteEdgeDefinition(ec1, true);
|
g1._deleteEdgeDefinition(ec1, true);
|
||||||
assertEqual([dr2, dr3], g1.__edgeDefinitions);
|
assertEqual([dr2, dr3], g1.__edgeDefinitions);
|
||||||
assertEqual([vc1, vc2], g1._orphanCollections());
|
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);
|
assertTrue(db._collection(ec1) === null);
|
||||||
|
|
||||||
g1._deleteEdgeDefinition(ec2, true);
|
g1._deleteEdgeDefinition(ec2, true);
|
||||||
assertEqual([dr3], g1.__edgeDefinitions);
|
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);
|
assertTrue(db._collection(ec2) === null);
|
||||||
},
|
},
|
||||||
|
|
||||||
test_extendEdgeDefinitionFromExistingGraph1: function() {
|
test_extendEdgeDefinitionFromExistingGraph1: function() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -622,10 +707,11 @@ function GeneralGraphCreationSuite() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
g1._extendEdgeDefinitions(dr2);
|
g1._extendEdgeDefinitions(dr2);
|
||||||
|
fail();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assertEqual(
|
assertEqual(
|
||||||
e.errorMessage,
|
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]);
|
g1 = graph._create(gN1, [dr1]);
|
||||||
graph._create(gN2, [dr2]);
|
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);
|
assertEqual([dr1], g1.__edgeDefinitions);
|
||||||
g1._addVertexCollection(vc3);
|
g1._addVertexCollection(vc3);
|
||||||
assertEqual([vc3], g1._orphanCollections());
|
assertEqual([vc3], g1._orphanCollections());
|
||||||
|
assertEqual([vc3], loadG1()._orphanCollections());
|
||||||
g1._extendEdgeDefinitions(dr3);
|
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([], g1._orphanCollections());
|
||||||
|
assertEqual([], loadG1()._orphanCollections());
|
||||||
g1._extendEdgeDefinitions(dr2);
|
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() {
|
test_extendEdgeDefinitionFromExistingGraph4: function() {
|
||||||
|
@ -705,15 +805,22 @@ function GeneralGraphCreationSuite() {
|
||||||
dr2 = graph._relation(ec2, [vc4, vc3, vc1, vc2], [vc4, vc3, vc1, vc2]),
|
dr2 = graph._relation(ec2, [vc4, vc3, vc1, vc2], [vc4, vc3, vc1, vc2]),
|
||||||
g1 = graph._create(gN1, [dr1]);
|
g1 = graph._create(gN1, [dr1]);
|
||||||
|
|
||||||
|
const loadG1 = () => graph._graph(gN1);
|
||||||
|
|
||||||
g1._extendEdgeDefinitions(dr2);
|
g1._extendEdgeDefinitions(dr2);
|
||||||
|
dr1 = sortEdgeDefinition(dr1);
|
||||||
|
dr2 = sortEdgeDefinition(dr2);
|
||||||
assertEqual([dr1, dr2], g1.__edgeDefinitions);
|
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.from, [vc1, vc2, vc3, vc4]);
|
||||||
assertEqual(edgeDefinition.to, [vc1, vc2, vc3, vc4]);
|
assertEqual(edgeDefinition.to, [vc1, vc2, vc3, vc4]);
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
test_editEdgeDefinitionFromExistingGraph1: function() {
|
test_editEdgeDefinitionFromExistingGraph1: function() {
|
||||||
var dr1 = graph._relation(ec1, [vc1], [vc1, vc2]),
|
var dr1 = graph._relation(ec1, [vc1], [vc1, vc2]),
|
||||||
dr2 = graph._relation(ec2, [vc3], [vc4, vc5]),
|
dr2 = graph._relation(ec2, [vc3], [vc4, vc5]),
|
||||||
|
@ -732,37 +839,42 @@ function GeneralGraphCreationSuite() {
|
||||||
|
|
||||||
test_editEdgeDefinitionFromExistingGraph2: function() {
|
test_editEdgeDefinitionFromExistingGraph2: function() {
|
||||||
|
|
||||||
var dr1 = graph._relation(ec1, [vc1, vc2], [vc3, vc4]),
|
var dr1 = graph._relation(ec1, _.cloneDeep([vc1, vc2]), _.cloneDeep([vc3, vc4])),
|
||||||
dr2 = graph._relation(ec2, [vc1], [vc4]),
|
dr2 = graph._relation(ec2, _.cloneDeep([vc1]), _.cloneDeep([vc4])),
|
||||||
dr3 = graph._relation(ec1, [vc5], [vc5]),
|
dr3 = graph._relation(ec1, _.cloneDeep([vc5]), _.cloneDeep([vc5])),
|
||||||
g1 = graph._create(gN1, [dr1, dr2]),
|
g1 = graph._create(gN1, _.cloneDeep([dr1, dr2])),
|
||||||
g2 = graph._create(gN2, [dr1]);
|
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, dr2], g1.__edgeDefinitions);
|
||||||
assertEqual([dr3], g2.__edgeDefinitions);
|
assertEqual([dr3], g2.__edgeDefinitions);
|
||||||
g2 = graph._graph(gN2);
|
|
||||||
assertEqual(g1._orphanCollections().sort(), [vc2, vc3].sort());
|
assertEqual(g1._orphanCollections().sort(), [vc2, vc3].sort());
|
||||||
assertEqual(g2._orphanCollections().sort(), [vc1, vc2, vc3, vc4].sort());
|
assertEqual(g2._orphanCollections().sort(), [vc1, vc2, vc3, vc4].sort());
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
test_editEdgeDefinitionFromExistingGraph3: function() {
|
test_editEdgeDefinitionFromExistingGraph3: function() {
|
||||||
|
|
||||||
var dr1 = graph._relation(ec1, [vc1], [vc1, vc2]),
|
var dr1 = graph._relation(ec1, _.cloneDeep([vc1]), _.cloneDeep([vc1, vc2])),
|
||||||
dr2 = graph._relation(ec1, [vc3], [vc4, vc5]),
|
dr2 = graph._relation(ec1, _.cloneDeep([vc3]), _.cloneDeep([vc4, vc5])),
|
||||||
dr3 = graph._relation(ec2, [vc2], [vc2, vc3]),
|
dr3 = graph._relation(ec2, _.cloneDeep([vc2]), _.cloneDeep([vc2, vc3])),
|
||||||
g1 = graph._create(gN1, [dr1, dr3]),
|
g1 = graph._create(gN1, _.cloneDeep([dr1, dr3])),
|
||||||
g2 = graph._create(gN2, [dr1]);
|
g2 = graph._create(gN2, _.cloneDeep([dr1]));
|
||||||
|
|
||||||
g1._addVertexCollection(vc4);
|
g1._addVertexCollection(vc4);
|
||||||
g2._addVertexCollection(vc5);
|
g2._addVertexCollection(vc5);
|
||||||
g2._addVertexCollection(vc6);
|
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, dr3], g1.__edgeDefinitions);
|
||||||
assertEqual([dr2], g2.__edgeDefinitions);
|
assertEqual([dr2], g2.__edgeDefinitions);
|
||||||
g2 = graph._graph(gN2);
|
|
||||||
assertEqual([vc1], g1._orphanCollections());
|
assertEqual([vc1], g1._orphanCollections());
|
||||||
assertEqual(g2._orphanCollections().sort(), [vc1, vc2, vc6].sort());
|
assertEqual(g2._orphanCollections().sort(), [vc1, vc2, vc6].sort());
|
||||||
|
|
||||||
|
@ -919,14 +1031,17 @@ function EdgesAndVerticesSuite() {
|
||||||
var myGraphName = unitTestGraphName + "2";
|
var myGraphName = unitTestGraphName + "2";
|
||||||
var myEdgeColName = "unitTestEdgeCollection4711";
|
var myEdgeColName = "unitTestEdgeCollection4711";
|
||||||
var myVertexColName = vc1;
|
var myVertexColName = vc1;
|
||||||
|
|
||||||
graph._create(
|
graph._create(
|
||||||
myGraphName,
|
myGraphName,
|
||||||
graph._edgeDefinitions(
|
graph._edgeDefinitions(
|
||||||
graph._relation(myEdgeColName, myVertexColName, myVertexColName)
|
graph._relation(myEdgeColName, myVertexColName, myVertexColName)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
graph._drop(myGraphName, true);
|
graph._drop(myGraphName, true);
|
||||||
assertFalse(graph._exists(myGraphName));
|
assertFalse(graph._exists(myGraphName));
|
||||||
|
db._flushCache();
|
||||||
assertTrue(db._collection(myVertexColName) !== null);
|
assertTrue(db._collection(myVertexColName) !== null);
|
||||||
assertTrue(db._collection(myEdgeColName) === null);
|
assertTrue(db._collection(myEdgeColName) === null);
|
||||||
},
|
},
|
||||||
|
@ -1013,11 +1128,9 @@ function EdgesAndVerticesSuite() {
|
||||||
graph._relation(myED, myVD2, myVD2)
|
graph._relation(myED, myVD2, myVD2)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
fail();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assertEqual(
|
assertEqual(e.errorNum, arangodb.errors.ERROR_GRAPH_COLLECTION_MULTI_USE.code)
|
||||||
e.errorMessage,
|
|
||||||
arangodb.errors.ERROR_GRAPH_COLLECTION_MULTI_USE.message
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
assertFalse(graph._exists(myGraphName));
|
assertFalse(graph._exists(myGraphName));
|
||||||
assertTrue(db._collection(myVD1) === null);
|
assertTrue(db._collection(myVD1) === null);
|
||||||
|
@ -1144,14 +1257,14 @@ function EdgesAndVerticesSuite() {
|
||||||
g[ec1].save(vertexId1, vertexId2, {});
|
g[ec1].save(vertexId1, vertexId2, {});
|
||||||
fail();
|
fail();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assertEqual(e.errorNum, 1906);
|
assertEqual(e.errorNum, arangodb.errors.ERROR_GRAPH_INVALID_EDGE.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
g[ec1].insert(vertexId1, vertexId2, {});
|
g[ec1].insert(vertexId1, vertexId2, {});
|
||||||
fail();
|
fail();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assertEqual(e.errorNum, 1906);
|
assertEqual(e.errorNum, arangodb.errors.ERROR_GRAPH_INVALID_EDGE.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
g[vc1].remove(vertexId1);
|
g[vc1].remove(vertexId1);
|
||||||
|
@ -1764,9 +1877,10 @@ function OrphanCollectionSuite() {
|
||||||
g1._addVertexCollection(vC4, false);
|
g1._addVertexCollection(vC4, false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code);
|
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);
|
assertTrue(db._collection(vC4) === null);
|
||||||
|
g1 = graph._graph(gN1);
|
||||||
assertEqual(g1._orphanCollections(), []);
|
assertEqual(g1._orphanCollections(), []);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1786,7 +1900,7 @@ function OrphanCollectionSuite() {
|
||||||
g1._addVertexCollection(vC1);
|
g1._addVertexCollection(vC1);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.code);
|
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 {
|
try {
|
||||||
g1._removeVertexCollection(name);
|
g1._removeVertexCollection(name);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code);
|
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.code);
|
||||||
assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message);
|
assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
test_removeVertexCollection2: function() {
|
test_removeVertexCollection2: function() {
|
||||||
g1._addVertexCollection(vC4, true);
|
g1._addVertexCollection(vC4, true);
|
||||||
g1._addVertexCollection(vC5, true);
|
g1._addVertexCollection(vC5, true);
|
||||||
assertEqual(g1._orphanCollections(), [vC4, vC5]);
|
assertEqual(g1._orphanCollections().sort(), [vC4, vC5].sort());
|
||||||
g1._removeVertexCollection(vC4, false);
|
g1._removeVertexCollection(vC4, false);
|
||||||
assertTrue(db._collection(vC4) !== null);
|
assertTrue(db._collection(vC4) !== null);
|
||||||
assertEqual(g1._orphanCollections(), [vC5]);
|
g1 = graph._graph(gN1);
|
||||||
|
assertEqual(g1._orphanCollections().sort(), [vC5].sort());
|
||||||
try {
|
try {
|
||||||
g1._removeVertexCollection(vC4, true);
|
g1._removeVertexCollection(vC4, true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -1822,6 +1937,7 @@ function OrphanCollectionSuite() {
|
||||||
graph._drop(gN1, true);
|
graph._drop(gN1, true);
|
||||||
assertTrue(db._collection(vC3) !== null);
|
assertTrue(db._collection(vC3) !== null);
|
||||||
graph._drop(gN2, true);
|
graph._drop(gN2, true);
|
||||||
|
db._flushCache();
|
||||||
assertTrue(db._collection(vC3) === null);
|
assertTrue(db._collection(vC3) === null);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1832,6 +1948,7 @@ function OrphanCollectionSuite() {
|
||||||
graph._drop(gN2, true);
|
graph._drop(gN2, true);
|
||||||
assertTrue(db._collection(vC3) !== null);
|
assertTrue(db._collection(vC3) !== null);
|
||||||
graph._drop(gN1, true);
|
graph._drop(gN1, true);
|
||||||
|
db._flushCache();
|
||||||
assertTrue(db._collection(vC3) === null);
|
assertTrue(db._collection(vC3) === null);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1843,6 +1960,7 @@ function OrphanCollectionSuite() {
|
||||||
graph._drop(gN1, true);
|
graph._drop(gN1, true);
|
||||||
assertTrue(db._collection(vC4) !== null);
|
assertTrue(db._collection(vC4) !== null);
|
||||||
graph._drop(gN2, true);
|
graph._drop(gN2, true);
|
||||||
|
db._flushCache();
|
||||||
assertTrue(db._collection(vC4) === null);
|
assertTrue(db._collection(vC4) === null);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,27 @@
|
||||||
|
|
||||||
exports.ArangoUsers = global.ArangoUsers;
|
exports.ArangoUsers = global.ArangoUsers;
|
||||||
delete 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
|
// / @brief ArangoDatabase
|
||||||
|
|
|
@ -47,8 +47,7 @@ const isZipBuffer = require('@arangodb/util').isZipBuffer;
|
||||||
|
|
||||||
const SYSTEM_SERVICE_MOUNTS = [
|
const SYSTEM_SERVICE_MOUNTS = [
|
||||||
'/_admin/aardvark', // Admin interface.
|
'/_admin/aardvark', // Admin interface.
|
||||||
'/_api/foxx', // Foxx management API.
|
'/_api/foxx' // Foxx management API.
|
||||||
'/_api/gharial' // General_Graph API.
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const GLOBAL_SERVICE_MAP = new Map();
|
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:
|
public:
|
||||||
Result() : _errorNumber(TRI_ERROR_NO_ERROR) {}
|
Result() : _errorNumber(TRI_ERROR_NO_ERROR) {}
|
||||||
|
|
||||||
|
Result(bool avoidCastingErrors) = delete;
|
||||||
|
|
||||||
Result(int errorNumber)
|
Result(int errorNumber)
|
||||||
: _errorNumber(errorNumber){
|
: _errorNumber(errorNumber){
|
||||||
if (errorNumber != TRI_ERROR_NO_ERROR) {
|
if (errorNumber != TRI_ERROR_NO_ERROR) {
|
||||||
|
|
|
@ -64,12 +64,18 @@ std::string const StaticStrings::ReplaceExisting("replaceExisting");
|
||||||
std::string const StaticStrings::OverWrite("overwrite");
|
std::string const StaticStrings::OverWrite("overwrite");
|
||||||
|
|
||||||
// replication headers
|
// replication headers
|
||||||
std::string const StaticStrings::ReplicationHeaderCheckMore("x-arango-replication-checkmore");
|
std::string const StaticStrings::ReplicationHeaderCheckMore(
|
||||||
std::string const StaticStrings::ReplicationHeaderLastIncluded("x-arango-replication-lastincluded");
|
"x-arango-replication-checkmore");
|
||||||
std::string const StaticStrings::ReplicationHeaderLastScanned("x-arango-replication-lastscanned");
|
std::string const StaticStrings::ReplicationHeaderLastIncluded(
|
||||||
std::string const StaticStrings::ReplicationHeaderLastTick("x-arango-replication-lasttick");
|
"x-arango-replication-lastincluded");
|
||||||
std::string const StaticStrings::ReplicationHeaderFromPresent("x-arango-replication-frompresent");
|
std::string const StaticStrings::ReplicationHeaderLastScanned(
|
||||||
std::string const StaticStrings::ReplicationHeaderActive("x-arango-replication-active");
|
"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
|
// database and collection names
|
||||||
std::string const StaticStrings::SystemDatabase("_system");
|
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::MimeTypeVPack("application/x-velocypack");
|
||||||
std::string const StaticStrings::MultiPartContentType("multipart/form-data");
|
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
|
// misc strings
|
||||||
std::string const StaticStrings::LastValue("lastValue");
|
std::string const StaticStrings::LastValue("lastValue");
|
||||||
|
|
|
@ -148,6 +148,26 @@ class StaticStrings {
|
||||||
static std::string const MimeTypeVPack;
|
static std::string const MimeTypeVPack;
|
||||||
static std::string const MultiPartContentType;
|
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
|
// misc strings
|
||||||
static std::string const LastValue;
|
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_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_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_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
|
## 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_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_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_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
|
## 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_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_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_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_UNKNOWN, "unknown session");
|
||||||
REG_ERROR(ERROR_SESSION_EXPIRED, "session expired");
|
REG_ERROR(ERROR_SESSION_EXPIRED, "session expired");
|
||||||
REG_ERROR(SIMPLE_CLIENT_UNKNOWN_ERROR, "unknown client error");
|
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_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_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_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_FAILED, "error during cluster repairs");
|
||||||
REG_ERROR(ERROR_CLUSTER_REPAIRS_NOT_ENOUGH_HEALTHY, "not enough (healthy) db servers");
|
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");
|
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.
|
/// The requested graph has no edge collections.
|
||||||
constexpr int TRI_ERROR_GRAPH_EMPTY = 1940;
|
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
|
/// 1950: ERROR_SESSION_UNKNOWN
|
||||||
/// "unknown session"
|
/// "unknown session"
|
||||||
/// Will be raised when an invalid/unknown session id is passed to the server.
|
/// 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.
|
/// All system attributes are forbidden.
|
||||||
constexpr int TRI_ERROR_ILLEGAL_SMART_GRAPH_ATTRIBUTE = 4004;
|
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
|
/// 5000: ERROR_CLUSTER_REPAIRS_FAILED
|
||||||
/// "error during cluster repairs"
|
/// "error during cluster repairs"
|
||||||
/// General error during cluster repairs
|
/// General error during cluster repairs
|
||||||
|
|
|
@ -49,6 +49,39 @@ enum class RequestType {
|
||||||
ILLEGAL // must be last
|
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 {
|
enum class ContentType {
|
||||||
CUSTOM, // use Content-Type from _headers
|
CUSTOM, // use Content-Type from _headers
|
||||||
JSON, // application/json
|
JSON, // application/json
|
||||||
|
@ -122,6 +155,112 @@ enum class ResponseCode {
|
||||||
BANDWIDTH_LIMIT_EXCEEDED = 509,
|
BANDWIDTH_LIMIT_EXCEEDED = 509,
|
||||||
NOT_EXTENDED = 510
|
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
|
#endif
|
||||||
|
|
|
@ -347,7 +347,6 @@ rest::ResponseCode GeneralResponse::responseCode(int code) {
|
||||||
case TRI_ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX:
|
case TRI_ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX:
|
||||||
case TRI_ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION:
|
case TRI_ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION:
|
||||||
case TRI_ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF:
|
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_STRING:
|
||||||
case TRI_ERROR_GRAPH_INVALID_EXAMPLE_ARRAY_OBJECT:
|
case TRI_ERROR_GRAPH_INVALID_EXAMPLE_ARRAY_OBJECT:
|
||||||
case TRI_ERROR_GRAPH_INVALID_NUMBER_OF_ARGUMENTS:
|
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_VERTEX_COL_DOES_NOT_EXIST:
|
||||||
case TRI_ERROR_GRAPH_NO_GRAPH_COLLECTION:
|
case TRI_ERROR_GRAPH_NO_GRAPH_COLLECTION:
|
||||||
case TRI_ERROR_QUEUE_UNKNOWN:
|
case TRI_ERROR_QUEUE_UNKNOWN:
|
||||||
|
case TRI_ERROR_GRAPH_EDGE_COLLECTION_NOT_USED:
|
||||||
return ResponseCode::NOT_FOUND;
|
return ResponseCode::NOT_FOUND;
|
||||||
|
|
||||||
case TRI_ERROR_CLUSTER_SHARD_LEADER_REFUSES_REPLICATION:
|
case TRI_ERROR_CLUSTER_SHARD_LEADER_REFUSES_REPLICATION:
|
||||||
|
|
|
@ -38,6 +38,11 @@ TRI_v8_global_t::TRI_v8_global_t(v8::Isolate* isolate)
|
||||||
VocbaseTempl(),
|
VocbaseTempl(),
|
||||||
EnvTempl(),
|
EnvTempl(),
|
||||||
UsersTempl(),
|
UsersTempl(),
|
||||||
|
GeneralGraphModuleTempl(),
|
||||||
|
GeneralGraphTempl(),
|
||||||
|
#ifdef USE_ENTERPRISE
|
||||||
|
SmartGraphTempl(),
|
||||||
|
#endif
|
||||||
|
|
||||||
BufferTempl(),
|
BufferTempl(),
|
||||||
|
|
||||||
|
|
|
@ -363,6 +363,19 @@ struct TRI_v8_global_t {
|
||||||
/// @brief users template
|
/// @brief users template
|
||||||
v8::Persistent<v8::ObjectTemplate> UsersTempl;
|
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
|
/// @brief Buffer template
|
||||||
v8::Persistent<v8::FunctionTemplate> BufferTempl;
|
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