diff --git a/CHANGELOG b/CHANGELOG
index 25a1e0191f..f83650bafe 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,8 @@
v2.2.0 (XXXX-XX-XX)
-------------------
+* fixed check-version for empty directory
+
* moved try/catch block to the top of routing chain
* added mountedApp function for foxx-manager
diff --git a/Documentation/Books/Users/Aql/GraphOperations.mdpp b/Documentation/Books/Users/Aql/GraphOperations.mdpp
index a08dd9598c..41b1b70920 100644
--- a/Documentation/Books/Users/Aql/GraphOperations.mdpp
+++ b/Documentation/Books/Users/Aql/GraphOperations.mdpp
@@ -7,25 +7,2878 @@ This chapter describe graph related aql functions.
+
+`GRAPH_PATHS (graphName, direction, followCycles, minLength, maxLength)`
+*The GRAPH\_PATHS function returns all paths of a graph.*
+
+This function determines all available paths in a graph identified by *graphName*.
+Except for *graphName* every other parameter is optional.
+
+* String *graphName* : The name of the graph.
+* String *direction* : The direction of the edges.
+Possible values are *any*, *inbound* and *outbound* (default).
+* Boolean *followCycles* : If set to *true* the query follows cycles in the graph,
+default is false.
+* Number *minLength* : Defines the minimal length a path must
+have to be returned (default is 0).
+* Number *maxLength* : Defines the maximal length a path must
+have to be returned (default is 10).
+
+@EXAMPLES
+
+Return all paths of the graph "social":
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> db._query("RETURN GRAPH_PATHS('social')").toArray();
+[
+ [
+ {
+ "vertices" : [
+ {
+ "_id" : "female/alice",
+ "_rev" : "196719176",
+ "_key" : "alice",
+ "name" : "Alice"
+ }
+ ],
+ "edges" : [ ],
+ "source" : {
+ "_id" : "female/alice",
+ "_rev" : "196719176",
+ "_key" : "alice",
+ "name" : "Alice"
+ },
+ "destination" : {
+ "_id" : "female/alice",
+ "_rev" : "196719176",
+ "_key" : "alice",
+ "name" : "Alice"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "female/alice",
+ "_rev" : "196719176",
+ "_key" : "alice",
+ "name" : "Alice"
+ },
+ {
+ "_id" : "male/bob",
+ "_rev" : "197112392",
+ "_key" : "bob",
+ "name" : "Bob"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/aliceAndBob",
+ "_rev" : "197898824",
+ "_key" : "aliceAndBob",
+ "_from" : "female/alice",
+ "_to" : "male/bob",
+ "type" : "married"
+ }
+ ],
+ "source" : {
+ "_id" : "female/alice",
+ "_rev" : "196719176",
+ "_key" : "alice",
+ "name" : "Alice"
+ },
+ "destination" : {
+ "_id" : "male/bob",
+ "_rev" : "197112392",
+ "_key" : "bob",
+ "name" : "Bob"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "female/alice",
+ "_rev" : "196719176",
+ "_key" : "alice",
+ "name" : "Alice"
+ },
+ {
+ "_id" : "male/bob",
+ "_rev" : "197112392",
+ "_key" : "bob",
+ "name" : "Bob"
+ },
+ {
+ "_id" : "female/diana",
+ "_rev" : "197505608",
+ "_key" : "diana",
+ "name" : "Diana"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/aliceAndBob",
+ "_rev" : "197898824",
+ "_key" : "aliceAndBob",
+ "_from" : "female/alice",
+ "_to" : "male/bob",
+ "type" : "married"
+ },
+ {
+ "_id" : "relation/bobAndDiana",
+ "_rev" : "198554184",
+ "_key" : "bobAndDiana",
+ "_from" : "male/bob",
+ "_to" : "female/diana",
+ "type" : "friend"
+ }
+ ],
+ "source" : {
+ "_id" : "female/alice",
+ "_rev" : "196719176",
+ "_key" : "alice",
+ "name" : "Alice"
+ },
+ "destination" : {
+ "_id" : "female/diana",
+ "_rev" : "197505608",
+ "_key" : "diana",
+ "name" : "Diana"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "female/alice",
+ "_rev" : "196719176",
+ "_key" : "alice",
+ "name" : "Alice"
+ },
+ {
+ "_id" : "male/charly",
+ "_rev" : "197309000",
+ "_key" : "charly",
+ "name" : "Charly"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/aliceAndCharly",
+ "_rev" : "198160968",
+ "_key" : "aliceAndCharly",
+ "_from" : "female/alice",
+ "_to" : "male/charly",
+ "type" : "friend"
+ }
+ ],
+ "source" : {
+ "_id" : "female/alice",
+ "_rev" : "196719176",
+ "_key" : "alice",
+ "name" : "Alice"
+ },
+ "destination" : {
+ "_id" : "male/charly",
+ "_rev" : "197309000",
+ "_key" : "charly",
+ "name" : "Charly"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "female/alice",
+ "_rev" : "196719176",
+ "_key" : "alice",
+ "name" : "Alice"
+ },
+ {
+ "_id" : "male/charly",
+ "_rev" : "197309000",
+ "_key" : "charly",
+ "name" : "Charly"
+ },
+ {
+ "_id" : "female/diana",
+ "_rev" : "197505608",
+ "_key" : "diana",
+ "name" : "Diana"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/aliceAndCharly",
+ "_rev" : "198160968",
+ "_key" : "aliceAndCharly",
+ "_from" : "female/alice",
+ "_to" : "male/charly",
+ "type" : "friend"
+ },
+ {
+ "_id" : "relation/charlyAndDiana",
+ "_rev" : "198357576",
+ "_key" : "charlyAndDiana",
+ "_from" : "male/charly",
+ "_to" : "female/diana",
+ "type" : "married"
+ }
+ ],
+ "source" : {
+ "_id" : "female/alice",
+ "_rev" : "196719176",
+ "_key" : "alice",
+ "name" : "Alice"
+ },
+ "destination" : {
+ "_id" : "female/diana",
+ "_rev" : "197505608",
+ "_key" : "diana",
+ "name" : "Diana"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "female/diana",
+ "_rev" : "197505608",
+ "_key" : "diana",
+ "name" : "Diana"
+ }
+ ],
+ "edges" : [ ],
+ "source" : {
+ "_id" : "female/diana",
+ "_rev" : "197505608",
+ "_key" : "diana",
+ "name" : "Diana"
+ },
+ "destination" : {
+ "_id" : "female/diana",
+ "_rev" : "197505608",
+ "_key" : "diana",
+ "name" : "Diana"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "male/bob",
+ "_rev" : "197112392",
+ "_key" : "bob",
+ "name" : "Bob"
+ }
+ ],
+ "edges" : [ ],
+ "source" : {
+ "_id" : "male/bob",
+ "_rev" : "197112392",
+ "_key" : "bob",
+ "name" : "Bob"
+ },
+ "destination" : {
+ "_id" : "male/bob",
+ "_rev" : "197112392",
+ "_key" : "bob",
+ "name" : "Bob"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "male/bob",
+ "_rev" : "197112392",
+ "_key" : "bob",
+ "name" : "Bob"
+ },
+ {
+ "_id" : "female/diana",
+ "_rev" : "197505608",
+ "_key" : "diana",
+ "name" : "Diana"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/bobAndDiana",
+ "_rev" : "198554184",
+ "_key" : "bobAndDiana",
+ "_from" : "male/bob",
+ "_to" : "female/diana",
+ "type" : "friend"
+ }
+ ],
+ "source" : {
+ "_id" : "male/bob",
+ "_rev" : "197112392",
+ "_key" : "bob",
+ "name" : "Bob"
+ },
+ "destination" : {
+ "_id" : "female/diana",
+ "_rev" : "197505608",
+ "_key" : "diana",
+ "name" : "Diana"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "male/charly",
+ "_rev" : "197309000",
+ "_key" : "charly",
+ "name" : "Charly"
+ }
+ ],
+ "edges" : [ ],
+ "source" : {
+ "_id" : "male/charly",
+ "_rev" : "197309000",
+ "_key" : "charly",
+ "name" : "Charly"
+ },
+ "destination" : {
+ "_id" : "male/charly",
+ "_rev" : "197309000",
+ "_key" : "charly",
+ "name" : "Charly"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "male/charly",
+ "_rev" : "197309000",
+ "_key" : "charly",
+ "name" : "Charly"
+ },
+ {
+ "_id" : "female/diana",
+ "_rev" : "197505608",
+ "_key" : "diana",
+ "name" : "Diana"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/charlyAndDiana",
+ "_rev" : "198357576",
+ "_key" : "charlyAndDiana",
+ "_from" : "male/charly",
+ "_to" : "female/diana",
+ "type" : "married"
+ }
+ ],
+ "source" : {
+ "_id" : "male/charly",
+ "_rev" : "197309000",
+ "_key" : "charly",
+ "name" : "Charly"
+ },
+ "destination" : {
+ "_id" : "female/diana",
+ "_rev" : "197505608",
+ "_key" : "diana",
+ "name" : "Diana"
+ }
+ }
+ ]
+]
+```
+
+Return all inbound paths of the graph "social" with a maximal
+length of 1 and a minimal length of 2:
+
+
+```
+arangosh> ~require("internal").db;
+-1
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> db._query("RETURN GRAPH_PATHS('social', 'inbound', false, 1, 2)").toArray();
+[
+ [
+ {
+ "vertices" : [
+ {
+ "_id" : "female/diana",
+ "_rev" : "128496200",
+ "_key" : "diana",
+ "name" : "Diana"
+ },
+ {
+ "_id" : "male/charly",
+ "_rev" : "128299592",
+ "_key" : "charly",
+ "name" : "Charly"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/charlyAndDiana",
+ "_rev" : "129348168",
+ "_key" : "charlyAndDiana",
+ "_from" : "male/charly",
+ "_to" : "female/diana",
+ "type" : "married"
+ }
+ ],
+ "source" : {
+ "_id" : "female/diana",
+ "_rev" : "128496200",
+ "_key" : "diana",
+ "name" : "Diana"
+ },
+ "destination" : {
+ "_id" : "male/charly",
+ "_rev" : "128299592",
+ "_key" : "charly",
+ "name" : "Charly"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "female/diana",
+ "_rev" : "128496200",
+ "_key" : "diana",
+ "name" : "Diana"
+ },
+ {
+ "_id" : "male/charly",
+ "_rev" : "128299592",
+ "_key" : "charly",
+ "name" : "Charly"
+ },
+ {
+ "_id" : "female/alice",
+ "_rev" : "127709768",
+ "_key" : "alice",
+ "name" : "Alice"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/charlyAndDiana",
+ "_rev" : "129348168",
+ "_key" : "charlyAndDiana",
+ "_from" : "male/charly",
+ "_to" : "female/diana",
+ "type" : "married"
+ },
+ {
+ "_id" : "relation/aliceAndCharly",
+ "_rev" : "129151560",
+ "_key" : "aliceAndCharly",
+ "_from" : "female/alice",
+ "_to" : "male/charly",
+ "type" : "friend"
+ }
+ ],
+ "source" : {
+ "_id" : "female/diana",
+ "_rev" : "128496200",
+ "_key" : "diana",
+ "name" : "Diana"
+ },
+ "destination" : {
+ "_id" : "female/alice",
+ "_rev" : "127709768",
+ "_key" : "alice",
+ "name" : "Alice"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "female/diana",
+ "_rev" : "128496200",
+ "_key" : "diana",
+ "name" : "Diana"
+ },
+ {
+ "_id" : "male/bob",
+ "_rev" : "128102984",
+ "_key" : "bob",
+ "name" : "Bob"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/bobAndDiana",
+ "_rev" : "129544776",
+ "_key" : "bobAndDiana",
+ "_from" : "male/bob",
+ "_to" : "female/diana",
+ "type" : "friend"
+ }
+ ],
+ "source" : {
+ "_id" : "female/diana",
+ "_rev" : "128496200",
+ "_key" : "diana",
+ "name" : "Diana"
+ },
+ "destination" : {
+ "_id" : "male/bob",
+ "_rev" : "128102984",
+ "_key" : "bob",
+ "name" : "Bob"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "female/diana",
+ "_rev" : "128496200",
+ "_key" : "diana",
+ "name" : "Diana"
+ },
+ {
+ "_id" : "male/bob",
+ "_rev" : "128102984",
+ "_key" : "bob",
+ "name" : "Bob"
+ },
+ {
+ "_id" : "female/alice",
+ "_rev" : "127709768",
+ "_key" : "alice",
+ "name" : "Alice"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/bobAndDiana",
+ "_rev" : "129544776",
+ "_key" : "bobAndDiana",
+ "_from" : "male/bob",
+ "_to" : "female/diana",
+ "type" : "friend"
+ },
+ {
+ "_id" : "relation/aliceAndBob",
+ "_rev" : "128889416",
+ "_key" : "aliceAndBob",
+ "_from" : "female/alice",
+ "_to" : "male/bob",
+ "type" : "married"
+ }
+ ],
+ "source" : {
+ "_id" : "female/diana",
+ "_rev" : "128496200",
+ "_key" : "diana",
+ "name" : "Diana"
+ },
+ "destination" : {
+ "_id" : "female/alice",
+ "_rev" : "127709768",
+ "_key" : "alice",
+ "name" : "Alice"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "male/bob",
+ "_rev" : "128102984",
+ "_key" : "bob",
+ "name" : "Bob"
+ },
+ {
+ "_id" : "female/alice",
+ "_rev" : "127709768",
+ "_key" : "alice",
+ "name" : "Alice"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/aliceAndBob",
+ "_rev" : "128889416",
+ "_key" : "aliceAndBob",
+ "_from" : "female/alice",
+ "_to" : "male/bob",
+ "type" : "married"
+ }
+ ],
+ "source" : {
+ "_id" : "male/bob",
+ "_rev" : "128102984",
+ "_key" : "bob",
+ "name" : "Bob"
+ },
+ "destination" : {
+ "_id" : "female/alice",
+ "_rev" : "127709768",
+ "_key" : "alice",
+ "name" : "Alice"
+ }
+ },
+ {
+ "vertices" : [
+ {
+ "_id" : "male/charly",
+ "_rev" : "128299592",
+ "_key" : "charly",
+ "name" : "Charly"
+ },
+ {
+ "_id" : "female/alice",
+ "_rev" : "127709768",
+ "_key" : "alice",
+ "name" : "Alice"
+ }
+ ],
+ "edges" : [
+ {
+ "_id" : "relation/aliceAndCharly",
+ "_rev" : "129151560",
+ "_key" : "aliceAndCharly",
+ "_from" : "female/alice",
+ "_to" : "male/charly",
+ "type" : "friend"
+ }
+ ],
+ "source" : {
+ "_id" : "male/charly",
+ "_rev" : "128299592",
+ "_key" : "charly",
+ "name" : "Charly"
+ },
+ "destination" : {
+ "_id" : "female/alice",
+ "_rev" : "127709768",
+ "_key" : "alice",
+ "name" : "Alice"
+ }
+ }
+ ]
+]
+```
+
!SUBSECTION GRAPH_SHORTEST_PATH
-!SUBSECTION_GRAPH_DISTANCE_TO
+
+`GRAPH_SHORTEST_PATH (graphName, startVertexExample, endVertexExample, options)`
+*The GRAPH\_SHORTEST\_PATH function returns all shortest paths of a graph.*
+
+This function determines all shortest paths in a graph identified by *graphName*.
+The function accepts an id, an example, a list of examples
+or even an empty example as parameter for
+start and end vertex. If one wants to calls this function to receive nearly all
+shortest paths for a graph the
+option *algorithm* should be set to *Floyd-Warshall* to increase performance.
+If no algorithm is provided in the options the function chooses the appropriate
+one (either *Floyd-Warshall* or *Dijsktra*) according to its parameters.
+The length of a path is by default the amount of edges from one start vertex to
+an end vertex. The option weight allows the user to define an edge attribute
+representing the length.
+
+* String *graphName* : The name of the graph.
+* String|Object|Array *startVertexExample* : An example for the desired
+start Vertices (see below).
+* String|Object|Array *endVertexExample* : An example for the desired
+end Vertices (see below).
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction of the edges.
+Possible values are *outbound*, *inbound* and *any* (default).
+* String|Array *edgeCollectionRestriction* : One or multiple edge
+collections that should be considered.
+* String|Array *startVertexCollectionRestriction* : One or multiple vertex
+collections that should be considered.
+* String|Array *endVertexCollectionRestriction* : One or multiple vertex
+collections that should be considered.
+* String|Object|Array *edgeExamples* : A filter example for the
+edges in the shortest paths (see below).
+* String *algorithm* : The algorithm to calculate
+the shortest paths. If both start and end vertex examples are empty *Floyd-Warshall* is
+used, otherwise the default is *Dijkstra*
+* String *weight* : The name of the attribute of
+the edges containing the length.
+* Number *defaultWeight* : Only used with the option *weight*.
+If an edge does not have the attribute named as defined in option *weight* this default
+is used as length.
+If no default is supplied the default would be positive Infinity so the path could
+not be calculated.
+
+Examples for startVertexExample/endVertexExample:
+* {} : Returns all possible start/end vertices for this graph.
+* *idString* : Returns the vertex with the id *idString*.
+* {*key* : *value*} : Returns the vertices that match this example.
+* [{*key1* : *value1*}, {*key2* : *value2*}] : Returns the vertices that match one of
+the examples.
+
+@EXAMPLES
+
+A route planner example, shortest distance from all villages to other cities:
+
-
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_SHORTEST_PATH("
+........> +"'routeplanner', {}, {}, {weight : 'distance', endVertexCollectionRestriction : 'city', " +
+........> "startVertexCollectionRestriction : 'village'}) RETURN [e.startVertex, e.vertex._id, " +
+........> "e.distance, LENGTH(e.paths)]"
+........> ).toArray();
+[
+ [
+ "village/Rosenheim",
+ "city/Cologne",
+ 730,
+ 1
+ ],
+ [
+ "village/Rosenheim",
+ "city/Berlin",
+ 680,
+ 1
+ ],
+ [
+ "village/Rosenheim",
+ "city/Munich",
+ 80,
+ 1
+ ],
+ [
+ "village/Olpe",
+ "city/Berlin",
+ 700,
+ 1
+ ],
+ [
+ "village/Olpe",
+ "city/Munich",
+ 600,
+ 1
+ ],
+ [
+ "village/Olpe",
+ "city/Cologne",
+ 100,
+ 1
+ ]
+]
+```
+
+A route planner example, shortest distance from Munich and Cologne to Olpe:
+
-!SUBSECTION_GRAPH_TRAVERSAL
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_SHORTEST_PATH("
+........> +"'routeplanner', [{_id: 'city/Cologne'},{_id: 'city/Munich'}], 'village/Olpe', " +
+........> "{weight : 'distance'}) RETURN [e.startVertex, e.vertex._id, e.distance, LENGTH(e.paths)]"
+........> ).toArray();
+[
+ [
+ "city/Cologne",
+ "village/Olpe",
+ 100,
+ 1
+ ],
+ [
+ "city/Munich",
+ "village/Olpe",
+ 600,
+ 1
+ ]
+]
+```
+
+
+!SUBSECTION GRAPH_TRAVERSAL
-!SUBSECTION_GRAPH_TRAVERSAL_TREE
+
+`GRAPH_TRAVERSAL (graphName, startVertexExample, direction, options)`
+*The GRAPH\_TRAVERSAL function traverses through the graph.*
+
+This function performs traversals on the given graph.
+For a more detailed documentation on the optional parameters see
+[Traversals](../Traversals/README.md).
+
+* String *graphName* : The name of the graph.
+* String|Object|Array *startVerte* : The ID of the start vertex of the traversal.
+* String|Object|Array *direction* : The direction of the edges. Possible values
+are *outbound*, *inbound* and *any* (default).
+* Object *options* : Optional options, see below:
+
+@EXAMPLES
+
+A route planner example, start a traversal from Munich :
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_TRAVERSAL('routeplanner', 'city/Munich'," +
+........> " 'outbound') RETURN e"
+........> ).toArray();
+[
+ {
+ "vertex" : {
+ "_id" : "city/Munich",
+ "_rev" : "113553992",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ }
+ },
+ {
+ "vertex" : {
+ "_id" : "city/Cologne",
+ "_rev" : "113357384",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ }
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Olpe",
+ "_rev" : "114012744",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Rosenheim",
+ "_rev" : "114209352",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Rosenheim",
+ "_rev" : "114209352",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Olpe",
+ "_rev" : "114012744",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ }
+]
+```
+
+A route planner example, start a traversal from Munich with a max depth of 1
+so only the direct neighbors of munich are returned:
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_TRAVERSAL('routeplanner', 'city/Munich'," +
+........> " 'outbound', {maxDepth : 1}) RETURN e"
+........> ).toArray();
+[
+ {
+ "vertex" : {
+ "_id" : "city/Munich",
+ "_rev" : "118600264",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ }
+ },
+ {
+ "vertex" : {
+ "_id" : "city/Cologne",
+ "_rev" : "118403656",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ }
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Rosenheim",
+ "_rev" : "119255624",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Olpe",
+ "_rev" : "119059016",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ }
+]
+```
+
+
+!SUBSECTION GRAPH_TRAVERSAL_TREE
-!SUBSECTION_GRAPH_NEIGHBORS
+
+`GRAPH_TRAVERSAL_TREE (graphName, startVertexExample, direction, connectName, options)`
+*The GRAPH\_TRAVERSAL\_TREE function traverses through the graph.*
+This function creates a tree format from the result for a better visualization of
+the path.
+This function performs traversals on the given graph.
+For a more detailed documentation on the optional parameters see
+[Traversals](../Traversals/README.md).
+
+* String *graphName* : The name of the graph.
+* String|Object|Array *startVerte* : The ID of the start vertex
+of the traversal.
+* String|Object|Array *direction* : The direction of the edges.
+Possible values are *outbound*, *inbound* and *any* (default).
+* String|Object|Array *connectName* : The result attribute which
+contains the connection.
+* Object *options* : Optional options, see below:
+
+@EXAMPLES
+
+A route planner example, start a traversal from Munich :
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_TRAVERSAL_TREE('routeplanner', 'city/Munich'," +
+........> " 'outbound', 'connnection') RETURN e"
+........> ).toArray();
+[
+ [
+ {
+ "_id" : "city/Munich",
+ "_rev" : "157004360",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000,
+ "connnection" : [
+ {
+ "_id" : "city/Cologne",
+ "_rev" : "156807752",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000,
+ "connnection" : [
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "157463112",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ {
+ "_id" : "village/Rosenheim",
+ "_rev" : "157659720",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ },
+ {
+ "_id" : "village/Rosenheim",
+ "_rev" : "157659720",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "157463112",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ }
+ ]
+]
+```
+
+A route planner example, start a traversal from Munich with a max depth of 1 so
+only the direct neighbors of munich are returned:
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_TRAVERSAL_TREE('routeplanner', 'city/Munich',"+
+........> " 'outbound', 'connnection', {maxDepth : 1}) RETURN e"
+........> ).toArray();
+[
+ [
+ {
+ "_id" : "city/Munich",
+ "_rev" : "162050632",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000,
+ "connnection" : [
+ {
+ "_id" : "city/Cologne",
+ "_rev" : "161854024",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ },
+ {
+ "_id" : "village/Rosenheim",
+ "_rev" : "162705992",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "162509384",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ }
+ ]
+]
+```
+
+
+!SUBSECTION GRAPH_DISTANCE_TO
+
+
+
+
+`GENERAL_GRAPH_DISTANCE_TO (graphName, startVertexExample, endVertexExample, options)`
+/// *The GRAPH\_DISTANCE\_TO function returns all paths and there distance within a graph.*
+///
+/// This function is a wrapper of [GRAPH\_SHORTEST\_PATH](#SUBSECTION GRAPH_SHORTEST_PATH).
+/// It does not return the actual path but only the distance between two vertices.
+
+
+!SUBSECTION GRAPH_NEIGHBORS
+
+`GRAPH_NEIGHBORS (graphName, vertexExample, options)`
+*The GRAPH\_NEIGHBORS function returns all neighbors of vertices.*
+
+The function accepts an id, an example, a list of examples or even an empty
+example as parameter for vertex.
+
+* String *graphName* : The name of the graph.
+* String|Object|Array *vertexExample* : An example for the desired
+vertices (see below).
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction
+of the edges. Possible values are *outbound*, *inbound* and *any* (default).
+* String|Object|Array *edgeExamples* : A filter example
+for the edges to the neighbors (see below).
+* String|Object|Array *neighborExamples* : An example for
+the desired neighbors (see below).
+* String|Array *edgeCollectionRestriction* : One or multiple
+edge collections that should be considered.
+* String|Array *vertexCollectionRestriction* : One or multiple
+vertex collections that should be considered.
+* Number *minDepth* : Defines the minimal
+depth a path to a neighbor must have to be returned (default is 1).
+* Number *maxDepth* : Defines the maximal
+depth a path to a neighbor must have to be returned (default is 1).
+
+Examples for edgeExamples/neighborExamples:
+* {} : Returns all possible edges/neighbors for this graph.
+* *idString* : Returns the edge/vertex with the id *idString*.
+* {*key* : *value*} : Returns the edges/vertices that match this example.
+* [{*key1* : *value1*}, {*key2* : *value2*}] : Returns the edges/vertices that
+match one of the examples.
+
+@EXAMPLES
+
+A route planner example, all neighbors of locations with a distance of either
+700 or 600.:
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_NEIGHBORS("
+........> +"'routeplanner', {}, {edgeExamples : [{distance: 600}, {distance: 700}]}) RETURN e"
+........> ).toArray();
+[
+ {
+ "vertex" : {
+ "_id" : "city/Munich",
+ "_rev" : "78230088",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ },
+ "path" : {
+ "edges" : [
+ {
+ "_id" : "highway/79475272",
+ "_rev" : "79475272",
+ "_key" : "79475272",
+ "_from" : "city/Berlin",
+ "_to" : "city/Munich",
+ "distance" : 600
+ }
+ ],
+ "vertices" : [
+ {
+ "_id" : "city/Berlin",
+ "_rev" : "77836872",
+ "_key" : "Berlin",
+ "isCapital" : true,
+ "population" : 3000000
+ },
+ {
+ "_id" : "city/Munich",
+ "_rev" : "78230088",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ }
+ ]
+ },
+ "startVertex" : "city/Berlin"
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Olpe",
+ "_rev" : "78688840",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ "path" : {
+ "edges" : [
+ {
+ "_id" : "road/80065096",
+ "_rev" : "80065096",
+ "_key" : "80065096",
+ "_from" : "city/Berlin",
+ "_to" : "village/Olpe",
+ "distance" : 700
+ }
+ ],
+ "vertices" : [
+ {
+ "_id" : "city/Berlin",
+ "_rev" : "77836872",
+ "_key" : "Berlin",
+ "isCapital" : true,
+ "population" : 3000000
+ },
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "78688840",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ },
+ "startVertex" : "city/Berlin"
+ },
+ {
+ "vertex" : {
+ "_id" : "city/Berlin",
+ "_rev" : "77836872",
+ "_key" : "Berlin",
+ "isCapital" : true,
+ "population" : 3000000
+ },
+ "path" : {
+ "edges" : [
+ {
+ "_id" : "highway/79475272",
+ "_rev" : "79475272",
+ "_key" : "79475272",
+ "_from" : "city/Berlin",
+ "_to" : "city/Munich",
+ "distance" : 600
+ }
+ ],
+ "vertices" : [
+ {
+ "_id" : "city/Munich",
+ "_rev" : "78230088",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ },
+ {
+ "_id" : "city/Berlin",
+ "_rev" : "77836872",
+ "_key" : "Berlin",
+ "isCapital" : true,
+ "population" : 3000000
+ }
+ ]
+ },
+ "startVertex" : "city/Munich"
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Olpe",
+ "_rev" : "78688840",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ "path" : {
+ "edges" : [
+ {
+ "_id" : "road/80654920",
+ "_rev" : "80654920",
+ "_key" : "80654920",
+ "_from" : "city/Munich",
+ "_to" : "village/Olpe",
+ "distance" : 600
+ }
+ ],
+ "vertices" : [
+ {
+ "_id" : "city/Munich",
+ "_rev" : "78230088",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ },
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "78688840",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ },
+ "startVertex" : "city/Munich"
+ },
+ {
+ "vertex" : {
+ "_id" : "city/Berlin",
+ "_rev" : "77836872",
+ "_key" : "Berlin",
+ "isCapital" : true,
+ "population" : 3000000
+ },
+ "path" : {
+ "edges" : [
+ {
+ "_id" : "road/80065096",
+ "_rev" : "80065096",
+ "_key" : "80065096",
+ "_from" : "city/Berlin",
+ "_to" : "village/Olpe",
+ "distance" : 700
+ }
+ ],
+ "vertices" : [
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "78688840",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ {
+ "_id" : "city/Berlin",
+ "_rev" : "77836872",
+ "_key" : "Berlin",
+ "isCapital" : true,
+ "population" : 3000000
+ }
+ ]
+ },
+ "startVertex" : "village/Olpe"
+ },
+ {
+ "vertex" : {
+ "_id" : "city/Munich",
+ "_rev" : "78230088",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ },
+ "path" : {
+ "edges" : [
+ {
+ "_id" : "road/80654920",
+ "_rev" : "80654920",
+ "_key" : "80654920",
+ "_from" : "city/Munich",
+ "_to" : "village/Olpe",
+ "distance" : 600
+ }
+ ],
+ "vertices" : [
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "78688840",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ {
+ "_id" : "city/Munich",
+ "_rev" : "78230088",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ }
+ ]
+ },
+ "startVertex" : "village/Olpe"
+ }
+]
+```
+
+A route planner example, all outbound neighbors of munich with a maximal depth of 2 :
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_NEIGHBORS("
+........> +"'routeplanner', 'city/Munich', {direction : 'outbound', maxDepth : 2}) RETURN e"
+........> ).toArray();
+[
+ {
+ "vertex" : {
+ "_id" : "city/Cologne",
+ "_rev" : "131576392",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ },
+ "path" : {
+ "edges" : [
+ {
+ "_id" : "highway/133214792",
+ "_rev" : "133214792",
+ "_key" : "133214792",
+ "_from" : "city/Munich",
+ "_to" : "city/Cologne",
+ "distance" : 650
+ }
+ ],
+ "vertices" : [
+ {
+ "_id" : "city/Munich",
+ "_rev" : "131773000",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ },
+ {
+ "_id" : "city/Cologne",
+ "_rev" : "131576392",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ }
+ ]
+ },
+ "startVertex" : "city/Munich"
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Olpe",
+ "_rev" : "132231752",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ "path" : {
+ "edges" : [
+ {
+ "_id" : "highway/133214792",
+ "_rev" : "133214792",
+ "_key" : "133214792",
+ "_from" : "city/Munich",
+ "_to" : "city/Cologne",
+ "distance" : 650
+ },
+ {
+ "_id" : "road/134394440",
+ "_rev" : "134394440",
+ "_key" : "134394440",
+ "_from" : "city/Cologne",
+ "_to" : "village/Olpe",
+ "distance" : 100
+ }
+ ],
+ "vertices" : [
+ {
+ "_id" : "city/Munich",
+ "_rev" : "131773000",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ },
+ {
+ "_id" : "city/Cologne",
+ "_rev" : "131576392",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ },
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "132231752",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ },
+ "startVertex" : "city/Munich"
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Rosenheim",
+ "_rev" : "132428360",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ "path" : {
+ "edges" : [
+ {
+ "_id" : "highway/133214792",
+ "_rev" : "133214792",
+ "_key" : "133214792",
+ "_from" : "city/Munich",
+ "_to" : "city/Cologne",
+ "distance" : 650
+ },
+ {
+ "_id" : "road/134591048",
+ "_rev" : "134591048",
+ "_key" : "134591048",
+ "_from" : "city/Cologne",
+ "_to" : "village/Rosenheim",
+ "distance" : 750
+ }
+ ],
+ "vertices" : [
+ {
+ "_id" : "city/Munich",
+ "_rev" : "131773000",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ },
+ {
+ "_id" : "city/Cologne",
+ "_rev" : "131576392",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ },
+ {
+ "_id" : "village/Rosenheim",
+ "_rev" : "132428360",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ },
+ "startVertex" : "city/Munich"
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Rosenheim",
+ "_rev" : "132428360",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ "path" : {
+ "edges" : [
+ {
+ "_id" : "road/134001224",
+ "_rev" : "134001224",
+ "_key" : "134001224",
+ "_from" : "city/Munich",
+ "_to" : "village/Rosenheim",
+ "distance" : 80
+ }
+ ],
+ "vertices" : [
+ {
+ "_id" : "city/Munich",
+ "_rev" : "131773000",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ },
+ {
+ "_id" : "village/Rosenheim",
+ "_rev" : "132428360",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ },
+ "startVertex" : "city/Munich"
+ },
+ {
+ "vertex" : {
+ "_id" : "village/Olpe",
+ "_rev" : "132231752",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ "path" : {
+ "edges" : [
+ {
+ "_id" : "road/134197832",
+ "_rev" : "134197832",
+ "_key" : "134197832",
+ "_from" : "city/Munich",
+ "_to" : "village/Olpe",
+ "distance" : 600
+ }
+ ],
+ "vertices" : [
+ {
+ "_id" : "city/Munich",
+ "_rev" : "131773000",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ },
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "132231752",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ },
+ "startVertex" : "city/Munich"
+ }
+]
+```
+
+
+
+
+!SUBSECTION GRAPH_EDGES
+
+
+
+
+`GRAPH_EDGES (graphName, vertexExample, options)`
+*The GRAPH\_EDGES function returns all edges of vertices.*
+
+The function accepts an id, an example, a list of examples or even an empty
+example as parameter for vertex.
+
+* String *graphName* : The name of the graph.
+* String|Object|Array *vertexExample* : An example for the desired
+vertices (see below).
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction
+of the edges. Possible values are *outbound*, *inbound* and *any* (default).
+* String|Array *edgeCollectionRestriction* : One or multiple
+edge collections that should be considered.
+* String|Array *startVertexCollectionRestriction* : One or multiple
+vertex collections that should be considered.
+* String|Array *endVertexCollectionRestriction* : One or multiple
+vertex collections that should be considered.
+* String|Object|Array *edgeExamples* : A filter example
+for the edges (see below).
+* String|Object|Array *neighborExamples* : An example for
+the desired neighbors (see below).
+* Number *minDepth* : Defines the minimal
+depth a path to a neighbor must have to be returned (default is 1).
+* Number *maxDepth* : Defines the maximal
+depth a path to a neighbor must have to be returned (default is 1).
+
+Examples for edgeExamples/neighborExamples:
+* {} : Returns all possible edges/neighbors for this graph.
+* *idString* : Returns the edge/vertex with the id *idString*.
+* {*key* : *value*} : Returns the edges/vertices that match this example.
+* [{*key1* : *value1*}, {*key2* : *value2*}] : Returns the edges/vertices that
+match one of the examples.
+
+@EXAMPLES
+
+A route planner example, all edges to locations with a distance of either 700 or 600.:
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_EDGES("
+........> +"'routeplanner', {}, {edgeExamples : [{distance: 600}, {distance: 700}]}) RETURN e"
+........> ).toArray();
+[
+ {
+ "_id" : "highway/29012552",
+ "_rev" : "29012552",
+ "_key" : "29012552",
+ "_from" : "city/Berlin",
+ "_to" : "city/Munich",
+ "distance" : 600
+ },
+ {
+ "_id" : "road/29602376",
+ "_rev" : "29602376",
+ "_key" : "29602376",
+ "_from" : "city/Berlin",
+ "_to" : "village/Olpe",
+ "distance" : 700
+ },
+ {
+ "_id" : "highway/29012552",
+ "_rev" : "29012552",
+ "_key" : "29012552",
+ "_from" : "city/Berlin",
+ "_to" : "city/Munich",
+ "distance" : 600
+ },
+ {
+ "_id" : "road/30192200",
+ "_rev" : "30192200",
+ "_key" : "30192200",
+ "_from" : "city/Munich",
+ "_to" : "village/Olpe",
+ "distance" : 600
+ },
+ {
+ "_id" : "road/29602376",
+ "_rev" : "29602376",
+ "_key" : "29602376",
+ "_from" : "city/Berlin",
+ "_to" : "village/Olpe",
+ "distance" : 700
+ },
+ {
+ "_id" : "road/30192200",
+ "_rev" : "30192200",
+ "_key" : "30192200",
+ "_from" : "city/Munich",
+ "_to" : "village/Olpe",
+ "distance" : 600
+ }
+]
+```
+
+A route planner example, all outbound edges of munich with a maximal depth of 2 :
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_EDGES("
+........> +"'routeplanner', 'city/Munich', {direction : 'outbound', maxDepth : 2}) RETURN e"
+........> ).toArray();
+[
+ {
+ "_id" : "highway/34255432",
+ "_rev" : "34255432",
+ "_key" : "34255432",
+ "_from" : "city/Munich",
+ "_to" : "city/Cologne",
+ "distance" : 650
+ },
+ {
+ "_id" : "highway/34255432",
+ "_rev" : "34255432",
+ "_key" : "34255432",
+ "_from" : "city/Munich",
+ "_to" : "city/Cologne",
+ "distance" : 650
+ },
+ {
+ "_id" : "road/35435080",
+ "_rev" : "35435080",
+ "_key" : "35435080",
+ "_from" : "city/Cologne",
+ "_to" : "village/Olpe",
+ "distance" : 100
+ },
+ {
+ "_id" : "highway/34255432",
+ "_rev" : "34255432",
+ "_key" : "34255432",
+ "_from" : "city/Munich",
+ "_to" : "city/Cologne",
+ "distance" : 650
+ },
+ {
+ "_id" : "road/35631688",
+ "_rev" : "35631688",
+ "_key" : "35631688",
+ "_from" : "city/Cologne",
+ "_to" : "village/Rosenheim",
+ "distance" : 750
+ },
+ {
+ "_id" : "road/35041864",
+ "_rev" : "35041864",
+ "_key" : "35041864",
+ "_from" : "city/Munich",
+ "_to" : "village/Rosenheim",
+ "distance" : 80
+ },
+ {
+ "_id" : "road/35238472",
+ "_rev" : "35238472",
+ "_key" : "35238472",
+ "_from" : "city/Munich",
+ "_to" : "village/Olpe",
+ "distance" : 600
+ }
+]
+```
+
+
+
+
+!SUBSECTION GRAPH_VERTICES
+
+
+
+
+`GRAPH_VERTICES (graphName, vertexExample, options)`
+*The GRAPH\_VERTICES function returns all vertices.*
+
+The function accepts an id, an example, a list of examples or even an empty
+example as parameter for vertex.
+According to the optional filters it will only return vertices that have
+outbound, onbound or any (default) edges.
+
+* String *graphName* : The name of the graph.
+* String|Object|Array *vertexExample* : An example for the desired
+vertices (see below).
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction of the
+edges. Possible values are *outbound*, *inbound* and *any* (default).
+* String|Array *vertexCollectionRestriction* : One or multiple
+vertex collections that should be considered.
+
+Examples for vertexExample:
+* {} : Returns all possible vertices for this graph.
+* *idString* : Returns the vertex with the id *idString*.
+* {*key* : *value*} : Returns the vertices that match this example.
+* [{*key1* : *value1*}, {*key2* : *value2*}] : Returns the vertices that
+match one of the examples.
+
+@EXAMPLES
+
+A route planner example, all vertices of the graph
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_COMMON_NEIGHBORS("
+........> +"'routeplanner', {}) RETURN e"
+........> ).toArray();
+[ArangoError 1541: invalid number of arguments for function '_AQL:GRAPH_COMMON_NEIGHBORS()']
+```
+
+A route planner example, all vertices from collection *city*.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_COMMON_NEIGHBORS("
+........> +"'routeplanner', {}, {direction : 'any', vertexCollectionRestriction" +
+........> " : 'city'}) RETURN e"
+........> ).toArray();
+[ ]
+```
+
+
+
+!SUBSECTION GRAPH_COMMON_NEIGHBORS
+
+
+
+
+`GRAPH_VERTICES (graphName, vertexExample, options)`
+*The GRAPH\_VERTICES function returns all vertices.*
+
+The function accepts an id, an example, a list of examples or even an empty
+example as parameter for vertex.
+According to the optional filters it will only return vertices that have
+outbound, onbound or any (default) edges.
+
+* String *graphName* : The name of the graph.
+* String|Object|Array *vertexExample* : An example for the desired
+vertices (see below).
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction of the
+edges. Possible values are *outbound*, *inbound* and *any* (default).
+* String|Array *vertexCollectionRestriction* : One or multiple
+vertex collections that should be considered.
+
+Examples for vertexExample:
+* {} : Returns all possible vertices for this graph.
+* *idString* : Returns the vertex with the id *idString*.
+* {*key* : *value*} : Returns the vertices that match this example.
+* [{*key1* : *value1*}, {*key2* : *value2*}] : Returns the vertices that
+match one of the examples.
+
+@EXAMPLES
+
+A route planner example, all vertices of the graph
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_COMMON_NEIGHBORS("
+........> +"'routeplanner', {isCapital : true}, {isCapital : true}) RETURN e"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : {
+ "city/Munich" : [
+ {
+ "_id" : "city/Cologne",
+ "_rev" : "214651185",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ },
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "215306545",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ {
+ "_id" : "village/Rosenheim",
+ "_rev" : "215503153",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ }
+ },
+ {
+ "city/Munich" : {
+ "city/Berlin" : [
+ {
+ "_id" : "city/Cologne",
+ "_rev" : "214651185",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ },
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "215306545",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ {
+ "_id" : "village/Rosenheim",
+ "_rev" : "215503153",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ }
+ }
+]
+```
+
+A route planner example, all vertices from collection *city*.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_COMMON_NEIGHBORS("
+........> +"'routeplanner', 'city/Munich', {}, {direction : 'outbound', maxDepth : 2}, "+
+........> "{direction : 'outbound', maxDepth : 2}) RETURN e"
+........> ).toArray();
+[
+ {
+ "city/Munich" : {
+ "city/Berlin" : [
+ {
+ "_id" : "city/Cologne",
+ "_rev" : "204558641",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ },
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "205214001",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ {
+ "_id" : "village/Rosenheim",
+ "_rev" : "205410609",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ],
+ "city/Cologne" : [
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "205214001",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ {
+ "_id" : "village/Rosenheim",
+ "_rev" : "205410609",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ }
+ }
+]
+```
+
+
+
+
+!SUBSECTION GRAPH_COMMON_PROPERTIES
+
+
+
+
+`GRAPH_COMMON_PROPERTIES (graphName, vertex1Example, vertex2Examples, options)`
+*The GRAPH\_COMMON\_PROPERTIES function returns all vertices
+defined by the examples that share common properties
+
+The function accepts an id, an example, a list of examples or even an empty
+example as parameter for vertex1Example and vertex2Example.
+
+* String *graphName* : The name of the graph.
+* String|Object|Array *vertex1Example* : An example for the desired
+vertices (see below).
+* String|Object|Array *vertex2Example* : An example for the desired
+vertices (see below).
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+// * String|Array *vertex1CollectionRestriction* : One or multiple
+vertex collections that should be considered.
+* String|Array *vertex2CollectionRestriction* : One or multiple
+vertex collections that should be considered.
+* String|Array *ignoreProperties* : One or multiple
+attributes of a document that should be ignored.
+
+Examples for vertexExample:
+* {} : Returns all possible vertices for this graph.
+* *idString* : Returns the vertex with the id *idString*.
+* {*key* : *value*} : Returns the vertices that match this example.
+* [{*key1* : *value1*}, {*key2* : *value2*}] : Returns the vertices that
+match one of the examples.
+
+@EXAMPLES
+
+A route planner example, all locations with the same properties:
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_COMMON_PROPERTIES("
+........> +"'routeplanner', {}, {}) RETURN e"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : [
+ {
+ "_id" : "city/Munich",
+ "_rev" : "77156657",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ }
+ ]
+ },
+ {
+ "city/Munich" : [
+ {
+ "_id" : "city/Berlin",
+ "_rev" : "76763441",
+ "_key" : "Berlin",
+ "isCapital" : true,
+ "population" : 3000000
+ },
+ {
+ "_id" : "city/Cologne",
+ "_rev" : "76960049",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ }
+ ]
+ },
+ {
+ "city/Cologne" : [
+ {
+ "_id" : "village/Rosenheim",
+ "_rev" : "77812017",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "77615409",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ },
+ {
+ "_id" : "city/Munich",
+ "_rev" : "77156657",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ }
+ ]
+ },
+ {
+ "village/Rosenheim" : [
+ {
+ "_id" : "city/Cologne",
+ "_rev" : "76960049",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ },
+ {
+ "_id" : "village/Olpe",
+ "_rev" : "77615409",
+ "_key" : "Olpe",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ },
+ {
+ "village/Olpe" : [
+ {
+ "_id" : "city/Cologne",
+ "_rev" : "76960049",
+ "_key" : "Cologne",
+ "isCapital" : false,
+ "population" : 1000000
+ },
+ {
+ "_id" : "village/Rosenheim",
+ "_rev" : "77812017",
+ "_key" : "Rosenheim",
+ "isCapital" : false,
+ "population" : 80000
+ }
+ ]
+ }
+]
+```
+
+A route planner example, all cities which share same properties except for population.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("FOR e IN GRAPH_COMMON_PROPERTIES("
+........> +"'routeplanner', {}, {}, {vertex1CollectionRestriction : 'city', " +
+........> "vertex2CollectionRestriction : 'city'" +
+........> " ,ignoreProperties: 'population'}) RETURN e"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : [
+ {
+ "_id" : "city/Munich",
+ "_rev" : "67064113",
+ "_key" : "Munich",
+ "isCapital" : true,
+ "population" : 1000000
+ }
+ ]
+ },
+ {
+ "city/Munich" : [
+ {
+ "_id" : "city/Berlin",
+ "_rev" : "66670897",
+ "_key" : "Berlin",
+ "isCapital" : true,
+ "population" : 3000000
+ }
+ ]
+ }
+]
+```
+
+
+
+
+!SUBSECTION GRAPH_ABSOLUTE_ECCENTRICITY
+
+
+
+
+`GRAPH_ABSOLUTE_ECCENTRICITY (graphName, vertexExample, options)`
+*The GRAPH\_ABSOLUTE\_ECCENTRICITY function returns the
+[eccentricity](http://en.wikipedia.org/wiki/Distance_%28graph_theory%29)
+of the vertices defined by the examples.
+
+The function accepts an id, an example, a list of examples or even an empty
+example as parameter for vertexExample.
+
+* String *graphName* : The name of the graph.
+* String|Object|Array *vertexExample* : An example for the desired
+vertices (see below).
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction of the edges.
+Possible values are *outbound*, *inbound* and *any* (default).
+* String|Array *edgeCollectionRestriction* : One or multiple edge
+collections that should be considered.
+* String|Array *startVertexCollectionRestriction* : One or multiple vertex
+collections that should be considered.
+* String|Array *endVertexCollectionRestriction* : One or multiple vertex
+collections that should be considered.
+* String|Object|Array *edgeExamples* : A filter example for the
+edges in the shortest paths (see below).
+* String *algorithm* : The algorithm to calculate
+the shortest paths.
+* String *weight* : The name of the attribute of
+the edges containing the length.
+* Number *defaultWeight* : Only used with the option *weight*.
+If an edge does not have the attribute named as defined in option *weight* this default
+is used as length.
+If no default is supplied the default would be positive Infinity so the path and
+hence the eccentricity can not be calculated.
+
+Examples for vertexExample:
+* {} : Returns all possible vertices for this graph.
+* *idString* : Returns the vertex with the id *idString*.
+* {*key* : *value*} : Returns the vertices that match this example.
+* [{*key1* : *value1*}, {*key2* : *value2*}] : Returns the vertices that
+match one of the examples.
+
+@EXAMPLES
+
+A route planner example, the absolute eccentricity of all locations.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_ABSOLUTE_ECCENTRICITY("
+........> +"'routeplanner', {})"
+........> ).toArray();
+[
+ {
+ "city/Munich" : 1,
+ "city/Cologne" : 1,
+ "city/Berlin" : 1,
+ "village/Olpe" : 2,
+ "village/Rosenheim" : 2
+ }
+]
+```
+
+A route planner example, the absolute eccentricity of all locations.
+This considers the actual distances.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_ABSOLUTE_ECCENTRICITY("
+........> +"'routeplanner', {}, {weight : 'distance'})"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 800,
+ "city/Munich" : 650,
+ "city/Cologne" : 800,
+ "village/Rosenheim" : 730,
+ "village/Olpe" : 700
+ }
+]
+```
+
+A route planner example, the absolute eccentricity of all cities regarding only
+outbound pathes.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_ABSOLUTE_ECCENTRICITY("
+........> + "'routeplanner', {}, {startVertexCollectionRestriction : 'city', " +
+........> "direction : 'outbound', weight : 'distance'})"
+........> ).toArray();
+[
+ {
+ "city/Munich" : 650,
+ "city/Berlin" : 850,
+ "city/Cologne" : 750
+ }
+]
+```
+
+
+
+!SUBSECTION GRAPH_ECCENTRICITY
+
+
+
+
+`GRAPH_ECCENTRICITY (graphName, options)`
+*The GRAPH\_ECCENTRICITY function returns the normalized
+[eccentricity](http://en.wikipedia.org/wiki/Distance_%28graph_theory%29)
+of the graphs vertices
+
+* String *graphName* : The name of the graph.
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction of the edges.
+Possible values are *outbound*, *inbound* and *any* (default).
+* String *algorithm* : The algorithm to calculate
+the shortest paths.
+* String *weight* : The name of the attribute of
+the edges containing the length.
+* Number *defaultWeight* : Only used with the option *weight*.
+If an edge does not have the attribute named as defined in option *weight* this default
+is used as length.
+If no default is supplied the default would be positive Infinity so the path and
+hence the eccentricity can not be calculated.
+
+@EXAMPLES
+
+A route planner example, the eccentricity of all locations.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_ECCENTRICITY("
+........> +"'routeplanner')"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 1,
+ "city/Munich" : 1,
+ "city/Cologne" : 1,
+ "village/Rosenheim" : 0.5,
+ "village/Olpe" : 0.5
+ }
+]
+```
+
+A route planner example, the eccentricity of all locations.
+This considers the actual distances.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_ECCENTRICITY("
+........> +"'routeplanner', {weight : 'distance'})"
+........> ).toArray();
+[
+ {
+ "city/Munich" : 1,
+ "city/Cologne" : 0.8125,
+ "city/Berlin" : 0.8125,
+ "village/Olpe" : 0.9285714285714286,
+ "village/Rosenheim" : 0.8904109589041096
+ }
+]
+```
+
+
+!SUBSECTION GRAPH_ABSOLUTE_CLOSENESS
+
+
+
+
+`GRAPH_ABSOLUTE_CLOSENESS (graphName, vertexExample, options)`
+*The GRAPH\_ABSOLUTE\_CLOSENESS function returns the
+[closeness](http://en.wikipedia.org/wiki/Centrality#Closeness_centrality)
+of the vertices defined by the examples.
+
+The function accepts an id, an example, a list of examples or even an empty
+example as parameter for vertexExample.
+
+* String *graphName* : The name of the graph.
+* String|Object|Array *vertexExample* : An example for the desired
+vertices (see below).
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction of the edges.
+Possible values are *outbound*, *inbound* and *any* (default).
+* String|Array *edgeCollectionRestriction* : One or multiple edge
+collections that should be considered.
+* String|Array *startVertexCollectionRestriction* : One or multiple vertex
+collections that should be considered.
+* String|Array *endVertexCollectionRestriction* : One or multiple vertex
+collections that should be considered.
+* String|Object|Array *edgeExamples* : A filter example for the
+edges in the shortest paths (see below).
+* String *algorithm* : The algorithm to calculate
+the shortest paths.
+* String *weight* : The name of the attribute of
+the edges containing the length.
+* Number *defaultWeight* : Only used with the option *weight*.
+If an edge does not have the attribute named as defined in option *weight* this default
+is used as length.
+If no default is supplied the default would be positive Infinity so the path and
+hence the eccentricity can not be calculated.
+
+Examples for vertexExample:
+* {} : Returns all possible vertices for this graph.
+* *idString* : Returns the vertex with the id *idString*.
+* {*key* : *value*} : Returns the vertices that match this example.
+* [{*key1* : *value1*}, {*key2* : *value2*}] : Returns the vertices that
+match one of the examples.
+
+@EXAMPLES
+
+A route planner example, the absolute closeness of all locations.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_ABSOLUTE_CLOSENESS("
+........> +"'routeplanner', {})"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 4,
+ "city/Cologne" : 4,
+ "city/Munich" : 4,
+ "village/Rosenheim" : 5,
+ "village/Olpe" : 5
+ }
+]
+```
+
+A route planner example, the absolute closeness of all locations.
+This considers the actual distances.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_ABSOLUTE_CLOSENESS("
+........> +"'routeplanner', {}, {weight : 'distance'})"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 2780,
+ "city/Cologne" : 2280,
+ "city/Munich" : 1930,
+ "village/Olpe" : 2080,
+ "village/Rosenheim" : 2170
+ }
+]
+```
+
+A route planner example, the absolute closeness of all cities regarding only
+outbound pathes.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_ABSOLUTE_CLOSENESS("
+........> + "'routeplanner', {}, {startVertexCollectionRestriction : 'city', " +
+........> "direction : 'outbound', weight : 'distance'})"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 2830,
+ "city/Munich" : 1330,
+ "city/Cologne" : 850
+ }
+]
+```
+
+
+!SUBSECTION GRAPH_CLOSENESS
+
+
+
+
+`GRAPH_CLOSENESS (graphName, options)`
+*The GRAPH\_CLOSENESS function returns the normalized
+[closeness](http://en.wikipedia.org/wiki/Centrality#Closeness_centrality)
+of graphs vertices.
+
+* String *graphName* : The name of the graph.
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction of the edges.
+Possible values are *outbound*, *inbound* and *any* (default).
+* String *algorithm* : The algorithm to calculate
+the shortest paths.
+* String *weight* : The name of the attribute of
+the edges containing the length.
+* Number *defaultWeight* : Only used with the option *weight*.
+If an edge does not have the attribute named as defined in option *weight* this default
+is used as length.
+If no default is supplied the default would be positive Infinity so the path and
+hence the eccentricity can not be calculated.
+
+@EXAMPLES
+
+A route planner example, the closeness of all locations.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_CLOSENESS("
+........> +"'routeplanner')"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 1,
+ "city/Munich" : 1,
+ "city/Cologne" : 1,
+ "village/Rosenheim" : 0.8,
+ "village/Olpe" : 0.8
+ }
+]
+```
+
+A route planner example, the closeness of all locations.
+This considers the actual distances.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_CLOSENESS("
+........> +"'routeplanner', {weight : 'distance'})"
+........> ).toArray();
+[
+ {
+ "city/Munich" : 1,
+ "city/Cologne" : 0.8464912280701755,
+ "city/Berlin" : 0.6942446043165468,
+ "village/Rosenheim" : 0.8894009216589862,
+ "village/Olpe" : 0.9278846153846155
+ }
+]
+```
+
+A route planner example, the absolute closeness of all cities regarding only
+outbound pathes.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_CLOSENESS("
+........> + "'routeplanner',{direction : 'outbound', weight : 'distance'})"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 0.3656319670725433,
+ "city/Munich" : 1,
+ "city/Cologne" : 0.7216326530612246,
+ "village/Rosenheim" : 0,
+ "village/Olpe" : 0
+ }
+]
+```
+
+
+!SUBSECTION GRAPH_ABSOLUTE_BETWEENNESS
+
+
+
+
+`GRAPH_ABSOLUTE_BETWEENNESS (graphName, vertexExample, options)`
+*The GRAPH\_ABSOLUTE\_BETWEENNESS function returns the
+[betweenness](http://en.wikipedia.org/wiki/Betweenness_centrality)
+of all vertices in the graph.
+
+
+* String *graphName* : The name of the graph.
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction of the edges.
+Possible values are *outbound*, *inbound* and *any* (default).
+* String *weight* : The name of the attribute of
+the edges containing the length.
+* Number *defaultWeight* : Only used with the option *weight*.
+If an edge does not have the attribute named as defined in option *weight* this default
+is used as length.
+If no default is supplied the default would be positive Infinity so the path and
+hence the eccentricity can not be calculated.
+
+@EXAMPLES
+
+A route planner example, the absolute betweenness of all locations.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_ABSOLUTE_BETWEENNESS("
+........> +"'routeplanner', {})"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 0.6666666666666666,
+ "city/Cologne" : 0.6666666666666666,
+ "city/Munich" : 0.6666666666666666,
+ "village/Olpe" : 0,
+ "village/Rosenheim" : 0
+ }
+]
+```
+
+A route planner example, the absolute closeness of all locations.
+This considers the actual distances.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_ABSOLUTE_BETWEENNESS("
+........> +"'routeplanner', {weight : 'distance'})"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 0,
+ "city/Munich" : 6,
+ "city/Cologne" : 0,
+ "village/Olpe" : 2,
+ "village/Rosenheim" : 0
+ }
+]
+```
+
+A route planner example, the absolute closeness of all cities regarding only
+outbound pathes.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_ABSOLUTE_BETWEENNESS("
+........> + "'routeplanner', {direction : 'outbound', weight : 'distance'})"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 0,
+ "city/Munich" : 1,
+ "city/Cologne" : 0,
+ "village/Rosenheim" : 0,
+ "village/Olpe" : 0
+ }
+]
+```
+
+
+!SUBSECTION GRAPH_BETWEENNESS
+
+
+
+
+`GRAPH_BETWEENNESS (graphName, options)`
+*The GRAPH\_BETWEENNESS function returns the
+[betweenness](http://en.wikipedia.org/wiki/Betweenness_centrality)
+of graphs vertices.
+
+* String *graphName* : The name of the graph.
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction of the edges.
+Possible values are *outbound*, *inbound* and *any* (default).
+* String *weight* : The name of the attribute of
+the edges containing the length.
+* Number *defaultWeight* : Only used with the option *weight*.
+If an edge does not have the attribute named as defined in option *weight* this default
+is used as length.
+If no default is supplied the default would be positive Infinity so the path and
+hence the eccentricity can not be calculated.
+
+@EXAMPLES
+
+A route planner example, the betweenness of all locations.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_BETWEENNESS("
+........> +"'routeplanner')"
+........> ).toArray();
+[
+ {
+ "city/Munich" : 1,
+ "city/Cologne" : 1,
+ "city/Berlin" : 1,
+ "village/Olpe" : 0,
+ "village/Rosenheim" : 0
+ }
+]
+```
+
+A route planner example, the closeness of all locations.
+This considers the actual distances.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_BETWEENNESS("
+........> +"'routeplanner', {weight : 'distance'})"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 0,
+ "city/Cologne" : 0,
+ "village/Olpe" : 0.3333333333333333,
+ "city/Munich" : 1,
+ "village/Rosenheim" : 0
+ }
+]
+```
+
+A route planner example, the closeness of all cities regarding only
+outbound pathes.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_BETWEENNESS("
+........> + "'routeplanner', {direction : 'outbound', weight : 'distance'})"
+........> ).toArray();
+[
+ {
+ "city/Berlin" : 0,
+ "city/Munich" : 1,
+ "city/Cologne" : 0,
+ "village/Rosenheim" : 0,
+ "village/Olpe" : 0
+ }
+]
+```
+
+
+!SUBSECTION GRAPH_RADIUS
+
+
+
+
+`GRAPH_RADIUS (graphName, options)`
+*The GRAPH\_RADIUS function returns the
+[radius](http://en.wikipedia.org/wiki/Eccentricity_%28graph_theory%29)
+of a graph.
+
+* String *graphName* : The name of the graph.
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction of the edges.
+Possible values are *outbound*, *inbound* and *any* (default).
+* String *algorithm* : The algorithm to calculate
+the shortest paths.
+* String *weight* : The name of the attribute of
+the edges containing the length.
+* Number *defaultWeight* : Only used with the option *weight*.
+If an edge does not have the attribute named as defined in option *weight* this default
+is used as length.
+If no default is supplied the default would be positive Infinity so the path and
+hence the eccentricity can not be calculated.
+
+@EXAMPLES
+
+A route planner example, the radius of the graph.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_RADIUS("
+........> +"'routeplanner')"
+........> ).toArray();
+[
+ 1
+]
+```
+
+A route planner example, the radius of the graph.
+This considers the actual distances.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_RADIUS("
+........> +"'routeplanner', {weight : 'distance'})"
+........> ).toArray();
+[
+ 650
+]
+```
+
+A route planner example, the cradius of the graph regarding only
+outbound pathes.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_RADIUS("
+........> + "'routeplanner', {direction : 'outbound', weight : 'distance'})"
+........> ).toArray();
+[
+ 650
+]
+```
+
+
+!SUBSECTION GRAPH_DIAMETER
+
+
+
+
+`GRAPH_DIAMETER (graphName, options)`
+*The GRAPH\_DIAMETER function returns the
+[diameter](http://en.wikipedia.org/wiki/Eccentricity_%28graph_theory%29)
+of a graph.
+
+* String *graphName* : The name of the graph.
+* Object *options* : Optional options, see below:
+
+Possible options and there defaults:
+* String *direction* : The direction of the edges.
+Possible values are *outbound*, *inbound* and *any* (default).
+* String *algorithm* : The algorithm to calculate
+the shortest paths.
+* String *weight* : The name of the attribute of
+the edges containing the length.
+* Number *defaultWeight* : Only used with the option *weight*.
+If an edge does not have the attribute named as defined in option *weight* this default
+is used as length.
+If no default is supplied the default would be positive Infinity so the path and
+hence the eccentricity can not be calculated.
+
+@EXAMPLES
+
+A route planner example, the diameter of the graph.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_DIAMETER("
+........> +"'routeplanner')"
+........> ).toArray();
+[
+ 2
+]
+```
+
+A route planner example, tthe diameter of the graph.
+This considers the actual distances.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_DIAMETER("
+........> +"'routeplanner', {weight : 'distance'})"
+........> ).toArray();
+[
+ 800
+]
+```
+
+A route planner example, the diameter of the graph regarding only
+outbound pathes.
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("routeplanner");
+arangosh> db._query("RETURN GRAPH_DIAMETER("
+........> + "'routeplanner', {direction : 'outbound', weight : 'distance'})"
+........> ).toArray();
+[
+ 850
+]
+```
+
+
+
+
diff --git a/Documentation/Books/Users/Foxx/FoxxRepository.mdpp b/Documentation/Books/Users/Foxx/FoxxRepository.mdpp
index 818b05d93e..a0b2b3d893 100644
--- a/Documentation/Books/Users/Foxx/FoxxRepository.mdpp
+++ b/Documentation/Books/Users/Foxx/FoxxRepository.mdpp
@@ -146,6 +146,7 @@ attributes are required though):
* *license*: Short form of the license (MIT, GPL...)
* *name*: Name of the application (Meta information)
* *repository*: An object with information about where you can find the repository: *type* and *url*
+* *rootElement*: Do you want to have a root element in the requests bodies? Default is false.
* *setup*: Path to a setup script
* *teardown*: Path to a teardown script
* *thumbnail*: Path to a thumbnail that represents the application (Meta information)
@@ -528,4 +529,4 @@ When the TemplateMiddleware is included, you will have access to the render func
### Render
@copydetails JSF_foxx_TemplateMiddleware_response_render
--->
\ No newline at end of file
+-->
diff --git a/Documentation/Books/Users/General-Graphs/GeneralGraphFunctions.mdpp b/Documentation/Books/Users/General-Graphs/GeneralGraphFunctions.mdpp
index 1b6f83973d..01793a6c5a 100644
--- a/Documentation/Books/Users/General-Graphs/GeneralGraphFunctions.mdpp
+++ b/Documentation/Books/Users/General-Graphs/GeneralGraphFunctions.mdpp
@@ -78,7 +78,23 @@ alternative call:
_key: "123"
};
```
+!SUBSECTION Orphan Collections
+Each graph has an orphan collection. It consists of arbitrary many vertex collection (type *document*), that are not
+used in an edge definition of the graph. If the graph is extended with an edge definition, which is part of the orphan
+collection, it will be removed from the orphan collection automatically.
+
+!SUBSUBSECTION Add
+
+
+
+!SUBSUBSECTION Read
+
+
+
+!SUBSUBSECTION Remove
+
+
!SUBSECTION Read a graph
diff --git a/Installation/ARM/rc.arangodb b/Installation/ARM/rc.arangodb
index c48eaa7941..ed3afc8494 100644
--- a/Installation/ARM/rc.arangodb
+++ b/Installation/ARM/rc.arangodb
@@ -39,11 +39,11 @@ start () {
fi
if [ "$1" = "--upgrade" ]; then
- $DAEMON -c $CONF --uid arangodb --gid arangodb $@
+ $DAEMON -c $CONF --uid arangodb --gid arangodb --no-server $@
RETVAL=$?
log_end_msg $RETVAL
else
- $DAEMON -c $CONF --uid arangodb --gid arangodb --check-version
+ $DAEMON -c $CONF --uid arangodb --gid arangodb --no-server --check-version
RETVAL=$?
if test $RETVAL -eq 0; then
diff --git a/arangod/RestServer/ArangoServer.cpp b/arangod/RestServer/ArangoServer.cpp
index 04d6b2a7ca..752303515e 100644
--- a/arangod/RestServer/ArangoServer.cpp
+++ b/arangod/RestServer/ArangoServer.cpp
@@ -721,6 +721,27 @@ int ArangoServer::startupServer () {
if (_applicationServer->programOptions().has("no-server")) {
startServer = false;
}
+
+ // check version
+ bool checkVersion = false;
+
+ if (_applicationServer->programOptions().has("check-version")) {
+ checkVersion = true;
+ }
+
+ // run upgrade script
+ bool performUpgrade = false;
+
+ if (_applicationServer->programOptions().has("upgrade")) {
+ performUpgrade = true;
+ }
+
+ // skip an upgrade even if VERSION is missing
+ bool skipUpgrade = false;
+
+ if (_applicationServer->programOptions().has("no-upgrade")) {
+ skipUpgrade = true;
+ }
// special treatment for the write-ahead log
// the log must exist before all other server operations can start
@@ -747,7 +768,7 @@ int ArangoServer::startupServer () {
LOG_WARNING("no shutdown info found. scanning datafiles for last tick...");
}
- openDatabases(iterateMarkersOnOpen);
+ openDatabases(checkVersion, performUpgrade, iterateMarkersOnOpen);
if (! wal::LogfileManager::instance()->open()) {
LOG_FATAL_AND_EXIT("Unable to finish WAL recovery procedure");
@@ -781,18 +802,6 @@ int ArangoServer::startupServer () {
_applicationV8->setVocbase(vocbase);
_applicationV8->setConcurrency(concurrency);
- bool performUpgrade = false;
-
- if (_applicationServer->programOptions().has("upgrade")) {
- performUpgrade = true;
- }
-
- // skip an upgrade even if VERSION is missing
- bool skipUpgrade = false;
-
- if (_applicationServer->programOptions().has("no-upgrade")) {
- skipUpgrade = true;
- }
// .............................................................................
// prepare everything
@@ -818,7 +827,7 @@ int ArangoServer::startupServer () {
_applicationServer->prepare2();
// run version check
- if (_applicationServer->programOptions().has("check-version")) {
+ if (checkVersion) {
_applicationV8->runUpgradeCheck();
}
@@ -1065,7 +1074,9 @@ int ArangoServer::runScript (TRI_vocbase_t* vocbase) {
/// @brief opens all databases
////////////////////////////////////////////////////////////////////////////////
-void ArangoServer::openDatabases (bool iterateMarkersOnOpen) {
+void ArangoServer::openDatabases (bool checkVersion,
+ bool performUpgrade,
+ bool iterateMarkersOnOpen) {
TRI_vocbase_defaults_t defaults;
// override with command-line options
@@ -1093,10 +1104,13 @@ void ArangoServer::openDatabases (bool iterateMarkersOnOpen) {
LOG_FATAL_AND_EXIT("cannot create server instance: out of memory");
}
- bool const isUpgrade = _applicationServer->programOptions().has("upgrade");
- res = TRI_StartServer(_server, isUpgrade);
+ res = TRI_StartServer(_server, checkVersion, performUpgrade);
if (res != TRI_ERROR_NO_ERROR) {
+ if (checkVersion && res == TRI_ERROR_ARANGO_EMPTY_DATADIR) {
+ TRI_EXIT_FUNCTION(EXIT_SUCCESS, NULL);
+ }
+
LOG_FATAL_AND_EXIT("cannot start server: %s", TRI_errno_string(res));
}
diff --git a/arangod/RestServer/ArangoServer.h b/arangod/RestServer/ArangoServer.h
index 4899124825..a3c0f42463 100644
--- a/arangod/RestServer/ArangoServer.h
+++ b/arangod/RestServer/ArangoServer.h
@@ -154,7 +154,9 @@ namespace triagens {
/// @brief opens all system databases
////////////////////////////////////////////////////////////////////////////////
- void openDatabases (bool);
+ void openDatabases (bool,
+ bool,
+ bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief closes all database
diff --git a/arangod/VocBase/server.cpp b/arangod/VocBase/server.cpp
index b6861f790b..796d3f0be8 100644
--- a/arangod/VocBase/server.cpp
+++ b/arangod/VocBase/server.cpp
@@ -300,12 +300,16 @@ static int WriteServerId (char const* filename) {
/// @brief read / create the server id on startup
////////////////////////////////////////////////////////////////////////////////
-static int DetermineServerId (TRI_server_t* server) {
+static int DetermineServerId (TRI_server_t* server, bool checkVersion) {
int res;
res = ReadServerId(server->_serverIdFilename);
if (res == TRI_ERROR_FILE_NOT_FOUND) {
+ if (checkVersion) {
+ return TRI_ERROR_ARANGO_EMPTY_DATADIR;
+ }
+
// id file does not yet exist. now create it
res = GenerateServerId();
@@ -1274,7 +1278,8 @@ static int Move14AlphaDatabases (TRI_server_t* server) {
////////////////////////////////////////////////////////////////////////////////
static int InitDatabases (TRI_server_t* server,
- bool isUpgrade) {
+ bool checkVersion,
+ bool performUpgrade) {
TRI_ASSERT(server != nullptr);
@@ -1287,7 +1292,7 @@ static int InitDatabases (TRI_server_t* server,
if (names._length == 0) {
char* name;
- if (! isUpgrade && HasOldCollections(server)) {
+ if (! performUpgrade && HasOldCollections(server)) {
LOG_ERROR("no databases found. Please start the server with the --upgrade option");
return TRI_ERROR_ARANGO_DATADIR_INVALID;
@@ -1305,7 +1310,7 @@ static int InitDatabases (TRI_server_t* server,
}
}
- if (res == TRI_ERROR_NO_ERROR && isUpgrade) {
+ if (res == TRI_ERROR_NO_ERROR && performUpgrade) {
char const* systemName;
TRI_ASSERT(names._length > 0);
@@ -1649,7 +1654,10 @@ TRI_server_id_t TRI_GetIdServer () {
////////////////////////////////////////////////////////////////////////////////
int TRI_StartServer (TRI_server_t* server,
- bool isUpgrade) {
+ bool checkVersion,
+ bool performUpgrade) {
+ int res;
+
if (! TRI_IsDirectory(server->_basePath)) {
LOG_ERROR("database path '%s' is not a directory",
server->_basePath);
@@ -1669,7 +1677,7 @@ int TRI_StartServer (TRI_server_t* server,
// check that the database is not locked and lock it
// .............................................................................
- int res = TRI_VerifyLockFile(server->_lockFilename);
+ res = TRI_VerifyLockFile(server->_lockFilename);
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("database is locked, please check the lock file '%s'",
@@ -1696,7 +1704,11 @@ int TRI_StartServer (TRI_server_t* server,
// read the server id
// .............................................................................
- res = DetermineServerId(server);
+ res = DetermineServerId(server, checkVersion);
+
+ if (res == TRI_ERROR_ARANGO_EMPTY_DATADIR) {
+ return res;
+ }
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("reading/creating server file failed: %s",
@@ -1733,7 +1745,11 @@ int TRI_StartServer (TRI_server_t* server,
// perform an eventual migration of the databases.
// .............................................................................
- res = InitDatabases(server, isUpgrade);
+ res = InitDatabases(server, checkVersion, performUpgrade);
+
+ if (res == TRI_ERROR_ARANGO_EMPTY_DATADIR) {
+ return res;
+ }
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("unable to initialise databases: %s",
@@ -1748,7 +1764,7 @@ int TRI_StartServer (TRI_server_t* server,
if (server->_appPath != nullptr &&
strlen(server->_appPath) > 0 &&
! TRI_IsDirectory(server->_appPath)) {
- if (! isUpgrade) {
+ if (! performUpgrade) {
LOG_ERROR("specified --javascript.app-path directory '%s' does not exist. "
"Please start again with --upgrade option to create it.",
server->_appPath);
@@ -1768,7 +1784,7 @@ int TRI_StartServer (TRI_server_t* server,
if (server->_devAppPath != nullptr &&
strlen(server->_devAppPath) > 0 &&
! TRI_IsDirectory(server->_devAppPath)) {
- if (! isUpgrade) {
+ if (! performUpgrade) {
LOG_ERROR("specified --javascript.dev-app-path directory '%s' does not exist. "
"Please start again with --upgrade option to create it.",
server->_devAppPath);
@@ -1818,7 +1834,7 @@ int TRI_StartServer (TRI_server_t* server,
// .............................................................................
// scan all databases
- res = OpenDatabases(server, isUpgrade);
+ res = OpenDatabases(server, performUpgrade);
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("could not iterate over all databases: %s",
@@ -2500,6 +2516,10 @@ bool TRI_MSync (int fd,
return true;
}
+// -----------------------------------------------------------------------------
+// --SECTION-- END-OF-FILE
+// -----------------------------------------------------------------------------
+
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
diff --git a/arangod/VocBase/server.h b/arangod/VocBase/server.h
index dab6a80792..90b74f1790 100644
--- a/arangod/VocBase/server.h
+++ b/arangod/VocBase/server.h
@@ -144,7 +144,8 @@ TRI_server_id_t TRI_GetIdServer (void);
////////////////////////////////////////////////////////////////////////////////
int TRI_StartServer (TRI_server_t*,
- bool);
+ bool checkVersion,
+ bool performUpgrade);
////////////////////////////////////////////////////////////////////////////////
/// @brief stop the server
diff --git a/js/Makefile.files b/js/Makefile.files
index 84eaba480f..4ed81958f0 100644
--- a/js/Makefile.files
+++ b/js/Makefile.files
@@ -15,7 +15,9 @@ JAVASCRIPT_BROWSER = \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/arango-query-cursor.js \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/arango-statement.js \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/arangosh.js \
+ js/apps/system/aardvark/frontend/js/modules/org/arangodb/general-graph.js \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/graph.js \
+ js/apps/system/aardvark/frontend/js/modules/org/arangodb/graph-blueprint.js \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/simple-query.js \
\
js/apps/system/aardvark/frontend/js/modules/org/arangodb-common.js \
@@ -31,6 +33,7 @@ JAVASCRIPT_BROWSER = \
js/apps/system/aardvark/frontend/js/bootstrap/errors.js \
js/apps/system/aardvark/frontend/js/bootstrap/monkeypatches.js \
js/apps/system/aardvark/frontend/js/bootstrap/module-internal.js \
+ js/apps/system/aardvark/frontend/js/bootstrap/module-console.js \
\
js/apps/system/aardvark/frontend/js/client/client.js \
js/apps/system/aardvark/frontend/js/client/bootstrap/module-internal.js
diff --git a/js/apps/system/aardvark/frontend/js/bootstrap/errors.js b/js/apps/system/aardvark/frontend/js/bootstrap/errors.js
index 324b9bd9e2..49167af3a6 100644
--- a/js/apps/system/aardvark/frontend/js/bootstrap/errors.js
+++ b/js/apps/system/aardvark/frontend/js/bootstrap/errors.js
@@ -104,6 +104,7 @@
"ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING" : { "code" : 1234, "message" : "index insertion warning - attribute missing in document" },
"ERROR_ARANGO_INDEX_CREATION_FAILED" : { "code" : 1235, "message" : "index creation failed" },
"ERROR_ARANGO_DATAFILE_FULL" : { "code" : 1300, "message" : "datafile full" },
+ "ERROR_ARANGO_EMPTY_DATADIR" : { "code" : 1301, "message" : "server database directory is empty" },
"ERROR_REPLICATION_NO_RESPONSE" : { "code" : 1400, "message" : "no response" },
"ERROR_REPLICATION_INVALID_RESPONSE" : { "code" : 1401, "message" : "invalid response" },
"ERROR_REPLICATION_MASTER_ERROR" : { "code" : 1402, "message" : "master error" },
@@ -206,13 +207,17 @@
"ERROR_GRAPH_COULD_NOT_CHANGE_EDGE" : { "code" : 1908, "message" : "could not change edge" },
"ERROR_GRAPH_TOO_MANY_ITERATIONS" : { "code" : 1909, "message" : "too many iterations" },
"ERROR_GRAPH_INVALID_FILTER_RESULT" : { "code" : 1910, "message" : "invalid filter result" },
- "ERROR_GRAPH_COLLECTION_MULTI_USE" : { "code" : 1920, "message" : "an edge collection may only be used once in one edge definition of a graph." },
- "ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS" : { "code" : 1921, "message" : " is already used by another graph in a different edge definition." },
- "ERROR_GRAPH_CREATE_MISSING_NAME" : { "code" : 1922, "message" : "a graph name is required to create a graph." },
- "ERROR_GRAPH_CREATE_MISSING_EDGE_DEFINITION" : { "code" : 1923, "message" : "at least one edge definition is required to create a graph." },
- "ERROR_GRAPH_EDGE_COLLECTION_NOT_USED" : { "code" : 1924, "message" : "The edge collection is not used in the edge definitions." },
- "ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
- "ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
+ "ERROR_GRAPH_COLLECTION_MULTI_USE" : { "code" : 1920, "message" : "multi use of edge collection in edge def" },
+ "ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS" : { "code" : 1921, "message" : "edge collection already used in edge def" },
+ "ERROR_GRAPH_CREATE_MISSING_NAME" : { "code" : 1922, "message" : "missing graph name" },
+ "ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION" : { "code" : 1923, "message" : "malformed edge def" },
+ "ERROR_GRAPH_NOT_FOUND" : { "code" : 1924, "message" : "graph not found" },
+ "ERROR_GRAPH_DUPLICATE" : { "code" : 1925, "message" : "graph already exists" },
+ "ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST" : { "code" : 1926, "message" : "collection does not exist" },
+ "ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX" : { "code" : 1927, "message" : "not a vertex collection" },
+ "ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION" : { "code" : 1928, "message" : "not in orphan collection" },
+ "ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
+ "ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
"SIMPLE_CLIENT_UNKNOWN_ERROR" : { "code" : 2000, "message" : "unknown client error" },
"SIMPLE_CLIENT_COULD_NOT_CONNECT" : { "code" : 2001, "message" : "could not connect to server" },
"SIMPLE_CLIENT_COULD_NOT_WRITE" : { "code" : 2002, "message" : "could not write to server" },
@@ -222,7 +227,6 @@
"ERROR_ARANGO_INDEX_BITARRAY_INSERT_ITEM_UNSUPPORTED_VALUE" : { "code" : 3413, "message" : "bitarray index insert failure - document attribute value unsupported in index" },
"ERROR_ARANGO_INDEX_BITARRAY_CREATION_FAILURE_DUPLICATE_ATTRIBUTES" : { "code" : 3415, "message" : "bitarray index creation failure - one or more index attributes are duplicated." },
"ERROR_ARANGO_INDEX_BITARRAY_CREATION_FAILURE_DUPLICATE_VALUES" : { "code" : 3417, "message" : "bitarray index creation failure - one or more index attribute values are duplicated." },
- "ERROR_APP_ALREADY_EXISTS" : { "code": 4000, "message": "App is already installed" },
"RESULT_KEY_EXISTS" : { "code" : 10000, "message" : "element not inserted into structure, because key already exists" },
"RESULT_ELEMENT_EXISTS" : { "code" : 10001, "message" : "element not inserted into structure, because it already exists" },
"RESULT_KEY_NOT_FOUND" : { "code" : 10002, "message" : "key not found in structure" },
diff --git a/js/apps/system/aardvark/frontend/js/bootstrap/module-console.js b/js/apps/system/aardvark/frontend/js/bootstrap/module-console.js
new file mode 100644
index 0000000000..c31023e380
--- /dev/null
+++ b/js/apps/system/aardvark/frontend/js/bootstrap/module-console.js
@@ -0,0 +1,431 @@
+/*jslint indent: 2, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, sloppy: true */
+/*global require, SYS_GETLINE, SYS_LOG, jqconsole */
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief module "console"
+///
+/// @file
+///
+/// DISCLAIMER
+///
+/// Copyright 2004-2013 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 Dr. Frank Celler
+/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany
+////////////////////////////////////////////////////////////////////////////////
+
+(function () {
+ // cannot use strict here as we are going to delete globals
+
+ var exports = require("console");
+
+ var sprintf = require("internal").sprintf;
+ var inspect = require("internal").inspect;
+
+// -----------------------------------------------------------------------------
+// --SECTION-- Module "console"
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// --SECTION-- private variables
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief group level
+////////////////////////////////////////////////////////////////////////////////
+
+ var groupLevel = "";
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief timers
+////////////////////////////////////////////////////////////////////////////////
+
+ var timers = { };
+
+// -----------------------------------------------------------------------------
+// --SECTION-- private functions
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief internal logging
+////////////////////////////////////////////////////////////////////////////////
+
+ var log;
+
+ try {
+ // this will work when we are in arangod but not in the browser / web interface
+ log = SYS_LOG;
+ delete SYS_LOG;
+ }
+ catch (err) {
+ // this will work in the web interface
+ log = function (level, message) {
+ if (jqconsole) {
+ jqconsole.Write(message + "\n", 'jssuccess');
+ }
+ };
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief internal logging with group level
+////////////////////////////////////////////////////////////////////////////////
+
+ function logGroup (level, msg) {
+ 'use strict';
+
+ log(level, groupLevel + msg);
+ }
+
+// -----------------------------------------------------------------------------
+// --SECTION-- public functions
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief assert
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.assert = function (condition) {
+ 'use strict';
+
+ if (condition) {
+ return;
+ }
+
+ var args = Array.prototype.slice.call(arguments, 1);
+ var msg;
+
+ try {
+ msg = sprintf.apply(sprintf, args);
+ }
+ catch (err) {
+ msg = err + ": " + args;
+ }
+
+ logGroup("error", msg);
+
+ require('assert').ok(condition, msg);
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief debug
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.debug = function () {
+ 'use strict';
+
+ var msg;
+
+ try {
+ msg = sprintf.apply(sprintf, arguments);
+ }
+ catch (err) {
+ msg = err + ": " + arguments;
+ }
+
+ logGroup("debug", msg);
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief debugLines
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.debugLines = function () {
+ 'use strict';
+
+ var msg;
+
+ try {
+ msg = sprintf.apply(sprintf, arguments);
+ }
+ catch (err) {
+ msg = err + ": " + arguments;
+ }
+
+ var a = msg.split("\n");
+ var i;
+
+ for (i = 0; i < a.length; ++i) {
+ logGroup("debug", a[i]);
+ }
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief dir
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.dir = function (object) {
+ 'use strict';
+
+ logGroup("info", inspect(object));
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief error
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.error = function () {
+ 'use strict';
+
+ var msg;
+
+ try {
+ msg = sprintf.apply(sprintf, arguments);
+ }
+ catch (err) {
+ msg = err + ": " + arguments;
+ }
+
+ logGroup("error", msg);
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief errorLines
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.errorLines = function () {
+ 'use strict';
+
+ var msg;
+
+ try {
+ msg = sprintf.apply(sprintf, arguments);
+ }
+ catch (err) {
+ msg = err + ": " + arguments;
+ }
+
+ var a = msg.split("\n");
+ var i;
+
+ for (i = 0; i < a.length; ++i) {
+ logGroup("error", a[i]);
+ }
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief getline
+////////////////////////////////////////////////////////////////////////////////
+
+ if (typeof SYS_GETLINE !== "undefined") {
+ exports.getline = SYS_GETLINE;
+ delete SYS_GETLINE;
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief group
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.group = function () {
+ 'use strict';
+
+ var msg;
+
+ try {
+ msg = sprintf.apply(sprintf, arguments);
+ }
+ catch (err) {
+ msg = err + ": " + arguments;
+ }
+
+ groupLevel = groupLevel + " ";
+ logGroup("info", msg);
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief groupCollapsed
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.groupCollapsed = function () {
+ 'use strict';
+
+ var msg;
+
+ try {
+ msg = sprintf.apply(sprintf, arguments);
+ }
+ catch (err) {
+ msg = err + ": " + arguments;
+ }
+
+ logGroup("info", msg);
+ groupLevel = groupLevel + " ";
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief groupEnd
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.groupEnd = function () {
+ 'use strict';
+
+ groupLevel = groupLevel.substr(2);
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief info
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.info = function () {
+ 'use strict';
+
+ var msg;
+
+ try {
+ msg = sprintf.apply(sprintf, arguments);
+ }
+ catch (err) {
+ msg = err + ": " + arguments;
+ }
+
+ logGroup("info", msg);
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief infoLines
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.infoLines = function () {
+ 'use strict';
+
+ var msg;
+
+ try {
+ msg = sprintf.apply(sprintf, arguments);
+ }
+ catch (err) {
+ msg = err + ": " + arguments;
+ }
+
+ var a = msg.split("\n");
+ var i;
+
+ for (i = 0; i < a.length; ++i) {
+ logGroup("info", a[i]);
+ }
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief log
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.log = exports.info;
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief logLines
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.logLines = exports.infoLines;
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief time
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.time = function (label) {
+ 'use strict';
+
+ if (typeof label !== 'string') {
+ throw new Error('label must be a string');
+ }
+
+ timers[label] = Date.now();
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief timeEnd
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.timeEnd = function(label) {
+ 'use strict';
+
+ var time = timers[label];
+
+ if (! time) {
+ throw new Error('No such label: ' + label);
+ }
+
+ var duration = Date.now() - time;
+
+ delete timers[label];
+
+ logGroup('%s: %dms', label, duration);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief trace
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.trace = function () {
+ var err = new Error();
+ err.name = 'trace';
+ err.message = sprintf.apply(sprintf, arguments);
+ Error.captureStackTrace(err, exports.trace);
+ logGroup("info", err.stack);
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief warn
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.warn = function () {
+ 'use strict';
+
+ var msg;
+
+ try {
+ msg = sprintf.apply(sprintf, arguments);
+ }
+ catch (err) {
+ msg = err + ": " + arguments;
+ }
+
+ logGroup("warning", msg);
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief warnLines
+////////////////////////////////////////////////////////////////////////////////
+
+ exports.warnLines = function () {
+ 'use strict';
+
+ var msg;
+
+ try {
+ msg = sprintf.apply(sprintf, arguments);
+ }
+ catch (err) {
+ msg = err + ": " + arguments;
+ }
+
+ var a = msg.split("\n");
+ var i;
+
+ for (i = 0; i < a.length; ++i) {
+ logGroup("warning", a[i]);
+ }
+ };
+
+}());
+
+// -----------------------------------------------------------------------------
+// --SECTION-- END-OF-FILE
+// -----------------------------------------------------------------------------
+
+// Local Variables:
+// mode: outline-minor
+// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
+// End:
diff --git a/js/apps/system/aardvark/frontend/js/client/bootstrap/module-internal.js b/js/apps/system/aardvark/frontend/js/client/bootstrap/module-internal.js
index 4150e8c275..e845ee0f69 100644
--- a/js/apps/system/aardvark/frontend/js/client/bootstrap/module-internal.js
+++ b/js/apps/system/aardvark/frontend/js/client/bootstrap/module-internal.js
@@ -1,5 +1,5 @@
/*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true, white: true, plusplus: true, nonpropdel: true */
-/*global require, ArangoConnection, print, SYS_ARANGO */
+/*global require, ArangoConnection, print, SYS_ARANGO, window */
////////////////////////////////////////////////////////////////////////////////
/// @brief module "internal"
@@ -300,6 +300,32 @@
internal.output(level, ": ", msg, "\n");
};
+////////////////////////////////////////////////////////////////////////////////
+/// @brief sprintf wrapper
+////////////////////////////////////////////////////////////////////////////////
+
+ try {
+ if (window) {
+ internal.sprintf = function (format) {
+ var n = arguments.length;
+ if (n === 0) {
+ return "";
+ }
+ if (n <= 1) {
+ return String(format);
+ }
+
+ var i = 0;
+
+ return format.replace(/%[dfs]/, function (match) {
+ return String(arguments[++i]);
+ });
+ };
+ }
+ }
+ catch (err) {
+ }
+
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
diff --git a/js/apps/system/aardvark/frontend/js/modules/org/arangodb/general-graph.js b/js/apps/system/aardvark/frontend/js/modules/org/arangodb/general-graph.js
new file mode 100644
index 0000000000..9ca319f715
--- /dev/null
+++ b/js/apps/system/aardvark/frontend/js/modules/org/arangodb/general-graph.js
@@ -0,0 +1,2863 @@
+module.define("org/arangodb/general-graph", function(exports, module) {
+/*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true, white: true, plusplus: true */
+/*global require, exports, Graph, arguments */
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Graph functionality
+///
+/// @file
+///
+/// DISCLAIMER
+///
+/// Copyright 2010-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 triAGENS GmbH, Cologne, Germany
+///
+/// @author Florian Bartels, Michael Hackstein, Guido Schwab
+/// @author Copyright 2011-2014, triAGENS GmbH, Cologne, Germany
+////////////////////////////////////////////////////////////////////////////////
+
+
+var arangodb = require("org/arangodb"),
+ internal = require("internal"),
+ ArangoCollection = arangodb.ArangoCollection,
+ ArangoError = arangodb.ArangoError,
+ db = arangodb.db,
+ errors = arangodb.errors,
+ _ = require("underscore");
+
+
+// -----------------------------------------------------------------------------
+// --SECTION-- module "org/arangodb/general-graph"
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// --SECTION-- private functions
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief transform a string into an array.
+////////////////////////////////////////////////////////////////////////////////
+
+
+var stringToArray = function (x) {
+ if (typeof x === "string") {
+ return [x];
+ }
+ return _.clone(x);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief checks if a parameter is not defined, an empty string or an empty
+// array
+////////////////////////////////////////////////////////////////////////////////
+
+
+var isValidCollectionsParameter = function (x) {
+ if (!x) {
+ return false;
+ }
+ if (Array.isArray(x) && x.length === 0) {
+ return false;
+ }
+ if (typeof x !== "string" && !Array.isArray(x)) {
+ return false;
+ }
+ return true;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief find or create a collection by name
+////////////////////////////////////////////////////////////////////////////////
+
+var findOrCreateCollectionByName = function (name, type, noCreate) {
+ var col = db._collection(name),
+ res = false;
+ if (col === null && !noCreate) {
+ if (type === ArangoCollection.TYPE_DOCUMENT) {
+ col = db._create(name);
+ } else {
+ col = db._createEdgeCollection(name);
+ }
+ res = true;
+ } else if (!(col instanceof ArangoCollection)) {
+ throw "<" + name + "> must be an ArangoCollection ";
+ }
+ return res;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief find or create a collection by name
+////////////////////////////////////////////////////////////////////////////////
+
+var findOrCreateCollectionsByEdgeDefinitions = function (edgeDefinitions, noCreate) {
+ var vertexCollections = {},
+ edgeCollections = {};
+ edgeDefinitions.forEach(function (e) {
+ e.from.concat(e.to).forEach(function (v) {
+ findOrCreateCollectionByName(v, ArangoCollection.TYPE_DOCUMENT, noCreate);
+ vertexCollections[v] = db[v];
+ });
+ findOrCreateCollectionByName(e.collection, ArangoCollection.TYPE_EDGE, noCreate);
+ edgeCollections[e.collection] = db[e.collection];
+ });
+ return [
+ vertexCollections,
+ edgeCollections
+ ];
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief internal function to get graphs collection
+////////////////////////////////////////////////////////////////////////////////
+
+var getGraphCollection = function() {
+ var gCol = db._graphs;
+ if (gCol === null || gCol === undefined) {
+ throw "_graphs collection does not exist.";
+ }
+ return gCol;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief internal function to print edge definitions in _PRINT
+////////////////////////////////////////////////////////////////////////////////
+
+var printEdgeDefinitions = function(defs) {
+ return _.map(defs, function(d) {
+ var out = d.collection;
+ out += ": [";
+ out += d.from.join(", ");
+ out += "] -> [";
+ out += d.to.join(", ");
+ out += "]";
+ return out;
+ });
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief internal function to wrap arango collections for overwrite
+////////////////////////////////////////////////////////////////////////////////
+
+var wrapCollection = function(col) {
+ var wrapper = {};
+ _.each(_.functions(col), function(func) {
+ wrapper[func] = function() {
+ return col[func].apply(col, arguments);
+ };
+ });
+ return wrapper;
+};
+
+
+var transformExample = function(example) {
+ if (example === undefined) {
+ return {};
+ }
+ if (typeof example === "string") {
+ return {_id: example};
+ }
+ if (typeof example === "object") {
+ if (Array.isArray(example)) {
+ return _.map(example, function(e) {
+ if (typeof e === "string") {
+ return {_id: e};
+ }
+ return e;
+ });
+ }
+ return example;
+ }
+ throw "Invalid example type. Has to be String, Array or Object";
+};
+
+var checkAllowsRestriction = function(colList, rest, msg) {
+ var unknown = [];
+ _.each(rest, function(r) {
+ if (!colList[r]) {
+ unknown.push(r);
+ }
+ });
+ if (unknown.length > 0) {
+ var err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_BAD_PARAMETER.code;
+ err.errorMessage = msg + ": "
+ + unknown.join(" and ")
+ + " are not known to the graph";
+ throw err;
+ }
+ return true;
+};
+
+
+// -----------------------------------------------------------------------------
+// --SECTION-- module "org/arangodb/general-graph"
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// --SECTION-- Fluent AQL Interface
+// -----------------------------------------------------------------------------
+
+var AQLStatement = function(query, type) {
+ this.query = query;
+ if (type) {
+ this.type = type;
+ }
+};
+
+AQLStatement.prototype.printQuery = function() {
+ return this.query;
+};
+
+AQLStatement.prototype.isPathQuery = function() {
+ return this.type === "path";
+};
+
+AQLStatement.prototype.isPathVerticesQuery = function() {
+ return this.type === "pathVertices";
+};
+
+AQLStatement.prototype.isPathEdgesQuery = function() {
+ return this.type === "pathEdges";
+};
+
+AQLStatement.prototype.isEdgeQuery = function() {
+ return this.type === "edge";
+};
+
+AQLStatement.prototype.isVertexQuery = function() {
+ return this.type === "vertex";
+};
+
+AQLStatement.prototype.isNeighborQuery = function() {
+ return this.type === "neighbor";
+};
+
+AQLStatement.prototype.allowsRestrict = function() {
+ return this.isEdgeQuery()
+ || this.isVertexQuery()
+ || this.isNeighborQuery();
+};
+
+// -----------------------------------------------------------------------------
+// --SECTION-- AQL Generator for fluent interface
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Starting point of the fluent interface.
+///
+/// Only for internal use.
+////////////////////////////////////////////////////////////////////////////////
+
+var AQLGenerator = function(graph) {
+ this.stack = [];
+ this.callStack = [];
+ this.bindVars = {
+ "graphName": graph.__name
+ };
+ this.graph = graph;
+ this.cursor = null;
+ this.lastVar = "";
+ this._path = [];
+ this._pathVertices = [];
+ this._pathEdges = [];
+ this._getPath = false;
+};
+
+AQLGenerator.prototype._addToPrint = function(name) {
+ var args = Array.prototype.slice.call(arguments);
+ args.shift(); // The Name
+ var stackEntry = {};
+ stackEntry.name = name;
+ if (args.length > 0 && args[0] !== undefined) {
+ stackEntry.params = args;
+ } else {
+ stackEntry.params = [];
+ }
+ this.callStack.push(stackEntry);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Print the call stack of this query
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype._PRINT = function(context) {
+ context.output = "[ GraphAQL ";
+ context.output += this.graph.__name;
+ _.each(this.callStack, function(call) {
+ if(context.prettyPrint) {
+ context.output += "\n";
+ }
+ context.output += ".";
+ context.output += call.name;
+ context.output += "(";
+ var i = 0;
+ for(i = 0; i < call.params.length; ++i) {
+ if (i > 0) {
+ context.output += ", ";
+ }
+ internal.printRecursive(call.params[i], context);
+ }
+ context.output += ")";
+ });
+ context.output += " ] ";
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Dispose and reset the current cursor of the query
+///
+/// Only for internal use.
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype._clearCursor = function() {
+ if (this.cursor) {
+ this.cursor.dispose();
+ this.cursor = null;
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Execute the query and keep the cursor
+///
+/// Only for internal use.
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype._createCursor = function() {
+ if (!this.cursor) {
+ this.cursor = this.execute();
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief General edge query, takes direction as parameter
+///
+/// This will create the general AQL statement to load edges
+/// connected to the vertices selected in the step before.
+/// Will also bind the options into bindVars.
+///
+/// Only for internal use, user gets different functions for directions
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype._edges = function(edgeExample, options) {
+ this._clearCursor();
+ this.options = options || {};
+ var ex = transformExample(edgeExample);
+ var edgeName = "edges_" + this.stack.length;
+ var query = "FOR " + edgeName
+ + ' IN GRAPH_EDGES(@graphName';
+ if (!this.getLastVar()) {
+ query += ',{}';
+ } else {
+ query += ',' + this.getLastVar();
+ }
+ query += ',@options_'
+ + this.stack.length + ')';
+ if (!Array.isArray(ex)) {
+ ex = [ex];
+ }
+ this.options.edgeExamples = ex;
+ this.bindVars["options_" + this.stack.length] = this.options;
+ var stmt = new AQLStatement(query, "edge");
+ this.stack.push(stmt);
+ this.lastVar = edgeName;
+ this._path.push(edgeName);
+ this._pathEdges.push(edgeName);
+ return this;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_edges
+/// Select all edges for the vertices selected before.
+///
+/// `graph-query.edges(examples)`
+///
+/// Creates an AQL statement to select all edges for each of the vertices selected
+/// in the step before.
+/// This will include *inbound* as well as *outbound* edges.
+/// The resulting set of edges can be filtered by defining one or more *examples*.
+///
+/// *examples* can have the following values:
+///
+/// * Empty, there is no matching executed all edges are valid.
+/// * A string, only the edge having this value as it's id is returned.
+/// * An example object, defining a set of attributes.
+/// Only edges having these attributes are matched.
+/// * A list containing example objects and/or strings.
+/// All edges matching at least one of the elements in the list are returned.
+///
+/// @EXAMPLES
+///
+/// To request unfiltered edges:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLEdgesUnfiltered}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices([{name: "Alice"}, {name: "Bob"}]);
+/// query.edges().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered edges by a single example:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLEdgesFilteredSingle}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices([{name: "Alice"}, {name: "Bob"}]);
+/// query.edges({type: "married"}).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered edges by multiple examples:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLEdgesFilteredMultiple}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices([{name: "Alice"}, {name: "Bob"}]);
+/// query.edges([{type: "married"}, {type: "friend"}]).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.edges = function(example) {
+ this._addToPrint("edges", example);
+ return this._edges(example, {direction: "any"});
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_outEdges
+/// Select all outbound edges for the vertices selected before.
+///
+/// `graph-query.outEdges(examples)`
+///
+/// Creates an AQL statement to select all *outbound* edges for each of the vertices selected
+/// in the step before.
+/// The resulting set of edges can be filtered by defining one or more *examples*.
+///
+/// *examples* can have the following values:
+///
+/// * Empty, there is no matching executed all edges are valid.
+/// * A string, only the edge having this value as it's id is returned.
+/// * An example object, defining a set of attributes.
+/// Only edges having these attributes are matched.
+/// * A list containing example objects and/or strings.
+/// All edges matching at least one of the elements in the list are returned.
+///
+/// @EXAMPLES
+///
+/// To request unfiltered outbound edges:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLOutEdgesUnfiltered}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices([{name: "Alice"}, {name: "Bob"}]);
+/// query.outEdges().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered outbound edges by a single example:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLOutEdgesFilteredSingle}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices([{name: "Alice"}, {name: "Bob"}]);
+/// query.outEdges({type: "married"}).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered outbound edges by multiple examples:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLOutEdgesFilteredMultiple}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices([{name: "Alice"}, {name: "Bob"}]);
+/// query.outEdges([{type: "married"}, {type: "friend"}]).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.outEdges = function(example) {
+ this._addToPrint("outEdges", example);
+ return this._edges(example, {direction: "outbound"});
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_inEdges
+/// Select all inbound edges for the vertices selected before.
+///
+/// `graph-query.inEdges(examples)`
+///
+/// Creates an AQL statement to select all *inbound* edges for each of the vertices selected
+/// in the step before.
+/// The resulting set of edges can be filtered by defining one or more *examples*.
+///
+/// *examples* can have the following values:
+///
+/// * Empty, there is no matching executed all edges are valid.
+/// * A string, only the edge having this value as it's id is returned.
+/// * An example object, defining a set of attributes.
+/// Only edges having these attributes are matched.
+/// * A list containing example objects and/or strings.
+/// All edges matching at least one of the elements in the list are returned.
+///
+/// @EXAMPLES
+///
+/// To request unfiltered inbound edges:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLInEdgesUnfiltered}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices([{name: "Alice"}, {name: "Bob"}]);
+/// query.inEdges().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered inbound edges by a single example:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLInEdgesFilteredSingle}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices([{name: "Alice"}, {name: "Bob"}]);
+/// query.inEdges({type: "married"}).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered inbound edges by multiple examples:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLInEdgesFilteredMultiple}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices([{name: "Alice"}, {name: "Bob"}]);
+/// query.inEdges([{type: "married"}, {type: "friend"}]).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.inEdges = function(example) {
+ this._addToPrint("inEdges", example);
+ return this._edges(example, {direction: "inbound"});
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief General vertex query, takes direction as parameter
+///
+/// This will create the general AQL statement to load vertices
+/// connected to the edges selected in the step before.
+/// Will also bind the options into bindVars.
+///
+/// Only for internal use, user gets different functions for directions
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype._vertices = function(example, options) {
+ this._clearCursor();
+ this.options = options || {};
+ var ex = transformExample(example);
+ var vertexName = "vertices_" + this.stack.length;
+ var query = "FOR " + vertexName
+ + " IN GRAPH_VERTICES(@graphName,@vertexExample_"
+ + this.stack.length + ',@options_'
+ + this.stack.length + ')';
+ this.bindVars["vertexExample_" + this.stack.length] = ex;
+ this.bindVars["options_" + this.stack.length] = this.options;
+ var stmt = new AQLStatement(query, "vertex");
+ this.stack.push(stmt);
+ this.lastVar = vertexName;
+ this._path.push(vertexName);
+ this._pathVertices.push(vertexName);
+ return this;
+
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_vertices
+/// Select all vertices connected to the edges selected before.
+///
+/// `graph-query.vertices(examples)`
+///
+/// Creates an AQL statement to select all vertices for each of the edges selected
+/// in the step before.
+/// This includes all vertices contained in *_from* as well as *_to* attribute of the edges.
+/// The resulting set of vertices can be filtered by defining one or more *examples*.
+///
+/// *examples* can have the following values:
+///
+/// * Empty, there is no matching executed all vertices are valid.
+/// * A string, only the vertex having this value as it's id is returned.
+/// * An example object, defining a set of attributes.
+/// Only vertices having these attributes are matched.
+/// * A list containing example objects and/or strings.
+/// All vertices matching at least one of the elements in the list are returned.
+///
+/// @EXAMPLES
+///
+/// To request unfiltered vertices:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLVerticesUnfiltered}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.vertices().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered vertices by a single example:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLVerticesFilteredSingle}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.vertices({name: "Alice"}).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered vertices by multiple examples:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLVerticesFilteredMultiple}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.vertices([{name: "Alice"}, {name: "Charly"}]).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.vertices = function(example) {
+ this._addToPrint("vertices", example);
+ if (!this.getLastVar()) {
+ return this._vertices(example);
+ }
+ var edgeVar = this.getLastVar();
+ this._vertices(example);
+ var vertexVar = this.getLastVar();
+ var query = "FILTER " + edgeVar
+ + "._from == " + vertexVar
+ + "._id || " + edgeVar
+ + "._to == " + vertexVar
+ + "._id";
+ var stmt = new AQLStatement(query);
+ this.stack.push(stmt);
+ return this;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_fromVertices
+/// Select all vertices where the edges selected before start.
+///
+/// `graph-query.vertices(examples)`
+///
+/// Creates an AQL statement to select the set of vertices where the edges selected
+/// in the step before start at.
+/// This includes all vertices contained in *_from* attribute of the edges.
+/// The resulting set of vertices can be filtered by defining one or more *examples*.
+///
+/// *examples* can have the following values:
+///
+/// * Empty, there is no matching executed all vertices are valid.
+/// * A string, only the vertex having this value as it's id is returned.
+/// * An example object, defining a set of attributes.
+/// Only vertices having these attributes are matched.
+/// * A list containing example objects and/or strings.
+/// All vertices matching at least one of the elements in the list are returned.
+///
+/// @EXAMPLES
+///
+/// To request unfiltered starting vertices:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLFromVerticesUnfiltered}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.fromVertices().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered starting vertices by a single example:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLFromVerticesFilteredSingle}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.fromVertices({name: "Alice"}).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered starting vertices by multiple examples:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLFromVerticesFilteredMultiple}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.fromVertices([{name: "Alice"}, {name: "Charly"}]).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.fromVertices = function(example) {
+ this._addToPrint("fromVertices", example);
+ if (!this.getLastVar()) {
+ return this._vertices(example);
+ }
+ var edgeVar = this.getLastVar();
+ this._vertices(example);
+ var vertexVar = this.getLastVar();
+ var query = "FILTER " + edgeVar
+ + "._from == " + vertexVar
+ + "._id";
+ var stmt = new AQLStatement(query);
+ this.stack.push(stmt);
+ return this;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_toVertices
+/// Select all vertices targeted by the edges selected before.
+///
+/// `graph-query.vertices(examples)`
+///
+/// Creates an AQL statement to select the set of vertices where the edges selected
+/// in the step before end in.
+/// This includes all vertices contained in *_to* attribute of the edges.
+/// The resulting set of vertices can be filtered by defining one or more *examples*.
+///
+/// *examples* can have the following values:
+///
+/// * Empty, there is no matching executed all vertices are valid.
+/// * A string, only the vertex having this value as it's id is returned.
+/// * An example object, defining a set of attributes.
+/// Only vertices having these attributes are matched.
+/// * A list containing example objects and/or strings.
+/// All vertices matching at least one of the elements in the list are returned.
+///
+/// @EXAMPLES
+///
+/// To request unfiltered starting vertices:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLToVerticesUnfiltered}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.toVertices().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered starting vertices by a single example:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLToVerticesFilteredSingle}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.toVertices({name: "Alice"}).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered starting vertices by multiple examples:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLToVerticesFilteredMultiple}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.toVertices([{name: "Alice"}, {name: "Charly"}]).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.toVertices = function(example) {
+ this._addToPrint("toVertices", example);
+ if (!this.getLastVar()) {
+ return this._vertices(example);
+ }
+ var edgeVar = this.getLastVar();
+ this._vertices(example);
+ var vertexVar = this.getLastVar();
+ var query = "FILTER " + edgeVar
+ + "._to == " + vertexVar
+ + "._id";
+ var stmt = new AQLStatement(query);
+ this.stack.push(stmt);
+ return this;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Get the variable holding the last result
+///
+/// Only for internal use.
+/// The return statement of the AQL query has to return
+/// this value.
+/// Also chaining has to use this variable to restrict
+/// queries in the next step to only values from this set.
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.getLastVar = function() {
+ if (this.lastVar === "") {
+ return false;
+ }
+ return this.lastVar;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_path
+/// The result of the query is the path to all elements.
+///
+/// By defaut the result of the generated AQL query is the set of elements passing the last matches.
+/// So having a `vertices()` query as the last step the result will be set of vertices.
+/// Using `path()` as the last action before requesting the result
+/// will modify the result such that the path required to find the set vertices is returned.
+///
+/// @EXAMPLES
+///
+/// Request the iteratively explored path using vertices and edges:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLPathSimple}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices({name: "Alice"});
+/// query.outEdges().toVertices().path().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// When requesting neighbors the path to these neighbors is expanded:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLPathNeighbors}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices({name: "Alice"});
+/// query.neighbors().path().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.path = function() {
+ this._clearCursor();
+ var statement = new AQLStatement("", "path");
+ this.stack.push(statement);
+ return this;
+};
+
+AQLGenerator.prototype.pathVertices = function() {
+ this._clearCursor();
+ var statement = new AQLStatement("", "pathVertices");
+ this.stack.push(statement);
+ return this;
+};
+
+AQLGenerator.prototype.pathEdges = function() {
+ this._clearCursor();
+ var statement = new AQLStatement("", "pathEdges");
+ this.stack.push(statement);
+ return this;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_neighbors
+/// Select all neighbors of the vertices selected in the step before.
+///
+/// `graph-query.neighbors(examples)`
+///
+/// Creates an AQL statement to select all neighbors for each of the vertices selected
+/// in the step before.
+/// The resulting set of vertices can be filtered by defining one or more *examples*.
+///
+/// *examples* can have the following values:
+///
+/// * Empty, there is no matching executed all vertices are valid.
+/// * A string, only the vertex having this value as it's id is returned.
+/// * An example object, defining a set of attributes.
+/// Only vertices having these attributes are matched.
+/// * A list containing example objects and/or strings.
+/// All vertices matching at least one of the elements in the list are returned.
+///
+/// @EXAMPLES
+///
+/// To request unfiltered neighbors:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLNeighborsUnfiltered}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices({name: "Alice"});
+/// query.neighbors().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered neighbors by a single example:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLNeighborsFilteredSingle}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices({name: "Alice"});
+/// query.neighbors({name: "Bob"}).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered neighbors by multiple examples:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLNeighborsFilteredMultiple}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.vertices([{name: "Bob"}, {name: "Charly"}]).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.neighbors = function(vertexExample, options) {
+ this._addToPrint("neighbors", vertexExample, options);
+ var ex = transformExample(vertexExample);
+ var resultName = "neighbors_" + this.stack.length;
+ var query = "FOR " + resultName
+ + " IN GRAPH_NEIGHBORS(@graphName,"
+ + this.getLastVar()
+ + ',@options_'
+ + this.stack.length + ')';
+ var opts;
+ if (options) {
+ opts = _.clone(options);
+ } else {
+ opts = {};
+ }
+ opts.neighborExamples = ex;
+ this.bindVars["options_" + this.stack.length] = opts;
+ var stmt = new AQLStatement(query, "neighbor");
+ this.stack.push(stmt);
+ this.lastVar = resultName + ".vertex";
+ this._path.push(resultName + ".path");
+ this._pathVertices.push("SLICE(" + resultName + ".path.vertices, 1)");
+ this._pathEdges.push(resultName + ".path.edges");
+ return this;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Get the last statement that can be restricted to collections
+///
+/// Only for internal use.
+/// This returnes the last statement that can be restricted to
+/// specific collections.
+/// Required to allow a chaining of `restrict` after `filter` for instance.
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype._getLastRestrictableStatementInfo = function() {
+ var i = this.stack.length - 1;
+ while (!this.stack[i].allowsRestrict()) {
+ i--;
+ }
+ return {
+ statement: this.stack[i],
+ options: this.bindVars["options_" + i]
+ };
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_restrict
+/// Restricts the last statement in the chain to return
+/// only elements of a specified set of collections
+///
+/// `graph-query.restrict(restrictions)`
+///
+/// By default all collections in the graph are searched for matching elements
+/// whenever vertices and edges are requested.
+/// Using *restrict* after such a statement allows to restrict the search
+/// to a specific set of collections within the graph.
+/// Restriction is only applied to this one part of the query.
+/// It does not effect earlier or later statements.
+///
+/// *restrictions* can have the following values:
+///
+/// * A string defining the name of one specific collection in the graph.
+/// Only elements from this collection are used for matching
+/// * A list of strings defining a set of collection names.
+/// Elements from all collections in this set are used for matching
+///
+/// @EXAMPLES
+///
+/// Request all directly connected vertices unrestricted:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLUnrestricted}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices({name: "Alice"});
+/// query.edges().vertices().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// Apply a restriction to the directly connected vertices:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLRestricted}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices({name: "Alice"});
+/// query.edges().vertices().restrict("female").toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// Restriction of a query is only valid for collections known to the graph:
+//
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLRestricted}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices({name: "Alice"});
+/// query.edges().vertices().restrict(["female", "male", "products"]).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.restrict = function(restrictions) {
+ this._addToPrint("restrict", restrictions);
+ this._clearCursor();
+ var rest = stringToArray(restrictions);
+ var lastQueryInfo = this._getLastRestrictableStatementInfo();
+ var lastQuery = lastQueryInfo.statement;
+ var opts = lastQueryInfo.options;
+ var restricts;
+ if (lastQuery.isEdgeQuery()) {
+ checkAllowsRestriction(
+ this.graph.__edgeCollections,
+ rest,
+ "edge collections"
+ );
+ restricts = opts.edgeCollectionRestriction || [];
+ opts.edgeCollectionRestriction = restricts.concat(restrictions);
+ } else if (lastQuery.isVertexQuery() || lastQuery.isNeighborQuery()) {
+ checkAllowsRestriction(
+ this.graph.__vertexCollections,
+ rest,
+ "vertex collections"
+ );
+ restricts = opts.vertexCollectionRestriction || [];
+ opts.vertexCollectionRestriction = restricts.concat(restrictions);
+ }
+ return this;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_filter
+/// Filter the result of the query
+///
+/// `graph-query.filter(examples)`
+///
+/// This can be used to further specfiy the expected result of the query.
+/// The result set is reduced to the set of elements that matches the given *examples*.
+///
+/// *examples* can have the following values:
+///
+/// * A string, only the elements having this value as it's id is returned.
+/// * An example object, defining a set of attributes.
+/// Only elements having these attributes are matched.
+/// * A list containing example objects and/or strings.
+/// All elements matching at least one of the elements in the list are returned.
+///
+/// @EXAMPLES
+///
+/// Request vertices unfiltered:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLUnfilteredVertices}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.toVertices().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// Request vertices filtered:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLFilteredVertices}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.toVertices().filter({name: "Alice"}).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// Request edges unfiltered:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLUnfilteredEdges}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.toVertices().outEdges().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// Request edges filtered:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLFilteredEdges}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._edges({type: "married"});
+/// query.toVertices().outEdges().filter({type: "married"}).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.filter = function(example) {
+ this._addToPrint("filter", example);
+ this._clearCursor();
+ var ex = [];
+ if (Object.prototype.toString.call(example) !== "[object Array]") {
+ if (Object.prototype.toString.call(example) !== "[object Object]") {
+ throw "The example has to be an Object, or an Array";
+ }
+ ex = [example];
+ } else {
+ ex = example;
+ }
+ var query = "FILTER MATCHES(" + this.getLastVar() + "," + JSON.stringify(ex) + ")";
+ this.stack.push(new AQLStatement(query));
+ return this;
+};
+
+AQLGenerator.prototype.printQuery = function() {
+ return this.stack.map(function(stmt) {
+ return stmt.printQuery();
+ }).join(" ");
+};
+
+AQLGenerator.prototype.execute = function() {
+ this._clearCursor();
+ var query = this.printQuery();
+ var bindVars = this.bindVars;
+ if (this.stack[this.stack.length-1].isPathQuery()) {
+ query += " RETURN [" + this._path + "]";
+ } else if (this.stack[this.stack.length-1].isPathVerticesQuery()) {
+ query += " RETURN FLATTEN([" + this._pathVertices + "])";
+ } else if (this.stack[this.stack.length-1].isPathEdgesQuery()) {
+ query += " RETURN FLATTEN([" + this._pathEdges + "])";
+ } else {
+ query += " RETURN " + this.getLastVar();
+ }
+ return db._query(query, bindVars, {count: true});
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_toArray
+/// Returns an array containing the complete result.
+///
+/// `graph-query.toArray()`
+///
+/// This function executes the generated query and returns the
+/// entire result as one array.
+/// ToArray does not return the generated query anymore and
+/// hence can only be the endpoint of a query.
+/// However keeping a reference to the query before
+/// executing allows to chain further statements to it.
+///
+/// @EXAMPLES
+///
+/// To collect the entire result of a query toArray can be used:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLToArray}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices();
+/// query.toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.toArray = function() {
+ this._createCursor();
+ return this.cursor.toArray();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_count
+/// Returns the number of returned elements if the query is executed.
+///
+/// `graph-query.count()`
+///
+/// This function determines the amount of elements to be expected within the result of the query.
+/// It can be used at the beginning of execution of the query
+/// before using *next()* or in between *next()* calls.
+/// The query object maintains a cursor of the query for you.
+/// *count()* does not change the cursor position.
+///
+/// @EXAMPLES
+///
+/// To count the number of matched elements:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLCount}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices();
+/// query.count();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+//
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.count = function() {
+ this._createCursor();
+ return this.cursor.count();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_hasNext
+/// Checks if the query has further results.
+///
+/// `graph-query.neighbors(examples)`
+///
+/// The generated statement maintains a cursor for you.
+/// If this cursor is already present *hasNext()* will
+/// use this cursors position to determine if there are
+/// further results available.
+/// If the query has not yet been executed *hasNext()*
+/// will execute it and create the cursor for you.
+///
+/// @EXAMPLES
+///
+/// Start query execution with hasNext:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLHasNext}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices();
+/// query.hasNext();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// Iterate over the result as long as it has more elements:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLHasNextIteration}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.hasNext = function() {
+ this._createCursor();
+ return this.cursor.hasNext();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_fluent_aql_next
+/// Request the next element in the result.
+///
+/// `graph-query.next()`
+///
+/// The generated statement maintains a cursor for you.
+/// If this cursor is already present *next()* will
+/// use this cursors position to deliver the next result.
+/// Also the cursor position will be moved by one.
+/// If the query has not yet been executed *next()*
+/// will execute it and create the cursor for you.
+/// It will throw an error of your query has no further results.
+///
+/// @EXAMPLES
+///
+/// Request some elements with next:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLNext}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices();
+/// query.next();
+/// query.next();
+/// query.next();
+/// query.next();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// The cursor is recreated if the query is changed:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphFluentAQLNextRecreate}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// var query = g._vertices();
+/// query.next();
+/// query.edges();
+/// query.next();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+////////////////////////////////////////////////////////////////////////////////
+
+AQLGenerator.prototype.next = function() {
+ this._createCursor();
+ return this.cursor.next();
+};
+
+// -----------------------------------------------------------------------------
+// --SECTION-- public functions
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_undirectedRelationDefinition
+///
+/// `general-graph._undirectedRelationDefinition(relationName, vertexCollections)`
+/// *Define an undirected relation.*
+///
+/// Defines an undirected relation with the name *relationName* using the
+/// list of *vertexCollections*. This relation allows the user to store
+/// edges in any direction between any pair of vertices within the
+/// *vertexCollections*.
+///
+/// @EXAMPLES
+///
+/// To define simple relation with only one vertex collection:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphUndirectedRelationDefinition1}
+/// var graph = require("org/arangodb/general-graph");
+/// graph._undirectedRelationDefinition("friend", "user");
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To define a relation between several vertex collections:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphUndirectedRelationDefinition2}
+/// var graph = require("org/arangodb/general-graph");
+/// graph._undirectedRelationDefinition("marriage", ["female", "male"]);
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+
+var _undirectedRelationDefinition = function (relationName, vertexCollections) {
+
+ if (arguments.length < 2) {
+ throw "method _undirectedRelationDefinition expects 2 arguments";
+ }
+
+ if (typeof relationName !== "string" || relationName === "") {
+ throw " must be a not empty string";
+ }
+
+ if (!isValidCollectionsParameter(vertexCollections)) {
+ throw " must be a not empty string or array";
+ }
+
+ return {
+ collection: relationName,
+ from: stringToArray(vertexCollections),
+ to: stringToArray(vertexCollections)
+ };
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// Define an directed relation.
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_directedRelationDefinition
+///
+/// `general-graph._directedRelationDefinition(relationName, fromVertexCollections, toVertexCollections)`
+/// *Define a directed relation.*
+///
+/// The *relationName* defines the name of this relation and references to the underlying edge collection.
+/// The *fromVertexCollections* is an Array of document collections holding the start vertices.
+/// The *toVertexCollections* is an Array of document collections holding the target vertices.
+/// Relations are only allowed in the direction from any collection in *fromVertexCollections*
+/// to any collection in *toVertexCollections*.
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphDirectedRelationDefinition}
+/// var graph = require("org/arangodb/general-graph");
+/// graph._directedRelationDefinition("has_bought", ["Customer", "Company"], ["Groceries", "Electronics"]);
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+
+var _directedRelationDefinition = function (
+ relationName, fromVertexCollections, toVertexCollections) {
+
+ if (arguments.length < 3) {
+ throw "method _directedRelationDefinition expects 3 arguments";
+ }
+
+ if (typeof relationName !== "string" || relationName === "") {
+ throw " must be a not empty string";
+ }
+
+ if (!isValidCollectionsParameter(fromVertexCollections)) {
+ throw " must be a not empty string or array";
+ }
+
+ if (!isValidCollectionsParameter(toVertexCollections)) {
+ throw " must be a not empty string or array";
+ }
+
+ return {
+ collection: relationName,
+ from: stringToArray(fromVertexCollections),
+ to: stringToArray(toVertexCollections)
+ };
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief create a list of edge definitions
+////////////////////////////////////////////////////////////////////////////////
+
+
+var _edgeDefinitions = function () {
+
+ var res = [], args = arguments;
+ Object.keys(args).forEach(function (x) {
+ res.push(args[x]);
+ });
+
+ return res;
+
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief extend a list of edge definitions
+////////////////////////////////////////////////////////////////////////////////
+
+
+var _extendEdgeDefinitions = function (edgeDefinition) {
+
+ var args = arguments, i = 0;
+
+ Object.keys(args).forEach(function (x) {
+ i++;
+ if (i === 1) {return;}
+ edgeDefinition.push(args[x]);
+ });
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief create a new graph
+////////////////////////////////////////////////////////////////////////////////
+
+
+var _create = function (graphName, edgeDefinitions) {
+
+ var gdb = getGraphCollection(),
+ err,
+ graphAlreadyExists = true,
+ collections;
+ if (!graphName) {
+ err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_CREATE_MISSING_NAME.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_CREATE_MISSING_NAME.message;
+ throw err;
+ }
+ edgeDefinitions = edgeDefinitions || [];
+ if (!Array.isArray(edgeDefinitions)) {
+ err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION.message;
+ throw err;
+ }
+ //check, if a collection is already used in a different edgeDefinition
+ var tmpCollections = [];
+ var tmpEdgeDefinitions = {};
+ edgeDefinitions.forEach(
+ function(edgeDefinition) {
+ var col = edgeDefinition.collection;
+ if (tmpCollections.indexOf(col) !== -1) {
+ 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;
+ }
+ tmpCollections.push(col);
+ tmpEdgeDefinitions[col] = edgeDefinition;
+ }
+ );
+ gdb.toArray().forEach(
+ function(singleGraph) {
+ var sGEDs = singleGraph.edgeDefinitions;
+ sGEDs.forEach(
+ function(sGED) {
+ var col = sGED.collection;
+ if (tmpCollections.indexOf(col) !== -1) {
+ if (JSON.stringify(sGED) !== JSON.stringify(tmpEdgeDefinitions[col])) {
+ 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;
+ }
+ }
+ }
+ );
+ }
+ );
+
+ try {
+ var g = gdb.document(graphName);
+ } catch (e) {
+ if (e.errorNum !== errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code) {
+ throw e;
+ }
+ graphAlreadyExists = false;
+ }
+
+ if (graphAlreadyExists) {
+ err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_DUPLICATE.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_DUPLICATE.message;
+ throw err;
+ }
+
+ collections = findOrCreateCollectionsByEdgeDefinitions(edgeDefinitions, false);
+
+ gdb.save({
+ 'edgeDefinitions' : edgeDefinitions,
+ '_key' : graphName
+ });
+
+ return new Graph(graphName, edgeDefinitions, collections[0], collections[1]);
+
+};
+
+var createHiddenProperty = function(obj, name, value) {
+ Object.defineProperty(obj, name, {
+ enumerable: false,
+ writable: true
+ });
+ obj[name] = value;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief constructor.
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_vertex_collection_save
+/// Creates and saves a new vertex in collection *vertexCollectionName*
+///
+/// `general-graph.vertexCollectionName.save(data)`
+///
+/// *data*: json - data of vertex
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphVertexCollectionSave}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g.male.save({name: "Floyd", _key: "floyd"});
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_vertex_collection_replace
+/// Replaces the data of a vertex in collection *vertexCollectionName*
+///
+/// `general-graph.vertexCollectionName.replace(vertexId, data, options)`
+///
+/// *vertexId*: string - id of the vertex
+/// *data*: json - data of vertex
+/// *options*: json - (optional) - see collection documentation
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphVertexCollectionReplace}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g.male.save({neym: "Jon", _key: "john"});
+/// g.male.replace("male/john", {name: "John"});
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_vertex_collection_update
+/// Updates the data of a vertex in collection *vertexCollectionName*
+///
+/// `general-graph.vertexCollectionName.update(vertexId, data, options)`
+///
+/// *vertexId*: string - id of the vertex
+/// *data*: json - data of vertex
+/// *options*: json - (optional) - see collection documentation
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphVertexCollectionUpdate}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g.female.save({name: "Lynda", _key: "linda"});
+/// g.female.update({name: "Linda", _key: "linda"});
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_vertex_collection_remove
+/// Removes a vertex in collection *vertexCollectionName*
+///
+/// `general-graph.vertexCollectionName.remove(vertexId, options)`
+///
+/// Additionally removes all ingoing and outgoing edges of the vertex recursively
+/// (see [edge remove](#edge.remove)).
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphVertexCollectionRemove}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g.male.save({name: "Kermit", _key: "kermit"});
+/// db._exists("male/kermit")
+/// g.male.remove("male/kermit")
+/// db._exists("male/kermit")
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_edge_collection_save
+/// Creates and saves a new edge from vertex *from* to vertex *to* in
+/// collection *edgeCollectionName*
+///
+/// `general-graph.edgeCollectionName.save(from, to, data)`
+///
+/// *from*: string - id of outgoing vertex
+/// *to*: string - of ingoing vertex
+/// *data*: json - data of edge
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphEdgeCollectionSave1}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g.relation.save("male/bob", "female/alice", {type: "married", _key: "bobAndAlice"});
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// If the collections of *from* and *to* are not defined in an edgeDefinition of the graph,
+/// the edge will not be stored.
+///
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphEdgeCollectionSave2}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g.relation.save("relation/aliceAndBob", "female/alice", {type: "married", _key: "bobAndAlice"});
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_edge_collection_replace
+/// Replaces the data of an edge in collection *edgeCollectionName*
+///
+/// `general-graph.edgeCollectionName.replace(edgeId, data, options)`
+///
+/// *edgeId*: string - id of the edge
+/// *data*: json - data of edge
+/// *options*: json - (optional) - see collection documentation
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphEdgeCollectionReplace}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g.relation.save("female/alice", "female/diana", {typo: "nose", _key: "aliceAndDiana"});
+/// g.relation.replace("relation/aliceAndDiana", {type: "knows"});
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_edge_collection_update
+/// Updates the data of an edge in collection *edgeCollectionName*
+///
+/// `general-graph.edgeCollectionName.update(edgeId, data, options)`
+///
+/// *edgeId*: string - id of the edge
+/// *data*: json - data of edge
+/// *options*: json - (optional) - see collection documentation
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphEdgeCollectionUpdate}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g.relation.save("female/alice", "female/diana", {type: "knows", _key: "aliceAndDiana"});
+/// g.relation.update("relation/aliceAndDiana", {type: "quarrelled", _key: "aliceAndDiana"});
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_edge_collection_remove
+/// Removes an edge in collection *edgeCollectionName*
+///
+/// `general-graph.edgeCollectionName.remove(edgeId, options)`
+///
+/// If this edge is used as a vertex by another edge, the other edge will be removed (recursively).
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphEdgeCollectionRemove}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g.relation.save("female/alice", "female/diana", {_key: "aliceAndDiana"});
+/// db._exists("relation/aliceAndDiana")
+/// g.relation.remove("relation/aliceAndDiana")
+/// db._exists("relation/aliceAndDiana")
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+var Graph = function(graphName, edgeDefinitions, vertexCollections, edgeCollections) {
+ var self = this;
+ // Create Hidden Properties
+ createHiddenProperty(this, "__name", graphName);
+ createHiddenProperty(this, "__vertexCollections", vertexCollections);
+ createHiddenProperty(this, "__edgeCollections", edgeCollections);
+ createHiddenProperty(this, "__edgeDefinitions", edgeDefinitions);
+ createHiddenProperty(this, "__idsToRemove", []);
+ createHiddenProperty(this, "__collectionsToLock", []);
+ createHiddenProperty(this, "__orphanCollections", []);
+
+ // fills this.__idsToRemove and this.__collectionsToLock
+ var removeEdge = function (edgeId, options) {
+ options = options || {};
+ var edgeCollection = edgeId.split("/")[0];
+ var graphs = getGraphCollection().toArray();
+ self.__idsToRemove.push(edgeId);
+ self.__collectionsToLock.push(edgeCollection);
+ graphs.forEach(
+ function(graph) {
+ var edgeDefinitions = graph.edgeDefinitions;
+ if (graph.edgeDefinitions) {
+ edgeDefinitions.forEach(
+ function(edgeDefinition) {
+ var from = edgeDefinition.from;
+ var to = edgeDefinition.to;
+ var collection = edgeDefinition.collection;
+ // if collection of edge to be deleted is in from or to
+ if (from.indexOf(edgeCollection) !== -1 || to.indexOf(edgeCollection) !== -1) {
+ //search all edges of the graph
+ var edges = db[collection].toArray();
+ edges.forEach(
+ function (edge) {
+ // if from is
+ if(self.__idsToRemove.indexOf(edge._id) === -1) {
+ if (edge._from === edgeId || edge._to === edgeId) {
+ removeEdge(edge._id, options);
+ }
+ }
+ }
+ );
+ }
+ }
+ );
+ }
+ }
+ );
+ return;
+ };
+
+
+ _.each(vertexCollections, function(obj, key) {
+ var result;
+ var wrap = wrapCollection(obj);
+ var old_remove = wrap.remove;
+ wrap.remove = function(vertexId, options) {
+ //delete all edges using the vertex in all graphs
+ var graphs = getGraphCollection().toArray();
+ var vertexCollectionName = vertexId.split("/")[0];
+ self.__collectionsToLock.push(vertexCollectionName);
+ graphs.forEach(
+ function(graph) {
+ var edgeDefinitions = graph.edgeDefinitions;
+ if (graph.edgeDefinitions) {
+ edgeDefinitions.forEach(
+ function(edgeDefinition) {
+ var from = edgeDefinition.from;
+ var to = edgeDefinition.to;
+ var collection = edgeDefinition.collection;
+ if (from.indexOf(vertexCollectionName) !== -1
+ || to.indexOf(vertexCollectionName) !== -1
+ ) {
+ var edges = db._collection(collection).toArray();
+ edges.forEach(
+ function(edge) {
+ if (edge._from === vertexId || edge._to === vertexId) {
+ removeEdge(edge._id, options);
+ }
+ }
+ );
+ }
+ }
+ );
+ }
+ }
+ );
+
+ try {
+ db._executeTransaction({
+ collections: {
+ write: self.__collectionsToLock
+ },
+ action: function (params) {
+ var db = require("internal").db;
+ params.ids.forEach(
+ function(edgeId) {
+ if (params.options) {
+ db._remove(edgeId, params.options);
+ } else {
+ db._remove(edgeId);
+ }
+ }
+ );
+ if (params.options) {
+ db._remove(params.vertexId, params.options);
+ } else {
+ db._remove(params.vertexId);
+ }
+ },
+ params: {
+ ids: self.__idsToRemove,
+ options: options,
+ vertexId: vertexId
+ }
+ });
+ result = true;
+ } catch (e) {
+ result = false;
+ }
+ self.__idsToRemove = [];
+ self.__collectionsToLock = [];
+
+ return result;
+ };
+
+ self[key] = wrap;
+ });
+
+ _.each(edgeCollections, function(obj, key) {
+ var wrap = wrapCollection(obj);
+ // save
+ var old_save = wrap.save;
+ wrap.save = function(from, to, data) {
+ //check, if edge is allowed
+ edgeDefinitions.forEach(
+ function(edgeDefinition) {
+ if (edgeDefinition.collection === key) {
+ var fromCollection = from.split("/")[0];
+ var toCollection = to.split("/")[0];
+ if (! _.contains(edgeDefinition.from, fromCollection)
+ || ! _.contains(edgeDefinition.to, toCollection)) {
+ throw "Edge is not allowed between " + from + " and " + to + ".";
+ }
+ }
+ }
+ );
+ return old_save(from, to, data);
+ };
+
+ // remove
+ wrap.remove = function(edgeId, options) {
+ var result;
+ //if _key make _id (only on 1st call)
+ if (edgeId.indexOf("/") === -1) {
+ edgeId = key + "/" + edgeId;
+ }
+ removeEdge(edgeId, options);
+
+ try {
+ db._executeTransaction({
+ collections: {
+ write: self.__collectionsToLock
+ },
+ action: function (params) {
+ var db = require("internal").db;
+ params.ids.forEach(
+ function(edgeId) {
+ if (params.options) {
+ db._remove(edgeId, params.options);
+ } else {
+ db._remove(edgeId);
+ }
+ }
+ );
+ },
+ params: {
+ ids: self.__idsToRemove,
+ options: options
+ }
+ });
+ result = true;
+ } catch (e) {
+ result = false;
+ }
+ self.__idsToRemove = [];
+ self.__collectionsToLock = [];
+ return result;
+ };
+
+ self[key] = wrap;
+ });
+};
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief load a graph.
+////////////////////////////////////////////////////////////////////////////////
+
+var _graph = function(graphName) {
+
+ var gdb = getGraphCollection(),
+ g, collections;
+
+ try {
+ g = gdb.document(graphName);
+ }
+ catch (e) {
+ if (e.errorNum !== errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code) {
+ throw e;
+ }
+ var err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_NOT_FOUND.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_NOT_FOUND.message;
+ throw err;
+ }
+
+ collections = findOrCreateCollectionsByEdgeDefinitions(g.edgeDefinitions, true);
+
+ return new Graph(graphName, g.edgeDefinitions, collections[0], collections[1]);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief check if a graph exists.
+////////////////////////////////////////////////////////////////////////////////
+
+var _exists = function(graphId) {
+ var gCol = getGraphCollection();
+ return gCol.exists(graphId);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Helper for dropping collections of a graph.
+////////////////////////////////////////////////////////////////////////////////
+
+var checkIfMayBeDropped = function(colName, graphName, graphs) {
+ var result = true;
+ graphs.forEach(
+ function(graph) {
+ if (graph._key === graphName) {
+ return;
+ }
+ var edgeDefinitions = graph.edgeDefinitions;
+ if (graph.edgeDefinitions) {
+ edgeDefinitions.forEach(
+ function(edgeDefinition) {
+ var from = edgeDefinition.from;
+ var to = edgeDefinition.to;
+ var collection = edgeDefinition.collection;
+ if (collection === colName
+ || from.indexOf(colName) !== -1
+ || to.indexOf(colName) !== -1
+ ) {
+ result = false;
+ }
+ }
+ );
+ }
+ var orphanCollections = graph.orphanCollections;
+ if (orphanCollections) {
+ if (orphanCollections.indexOf(colName) !== -1) {
+ return false;
+ }
+ }
+ }
+ );
+
+ return result;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief drop a graph.
+////////////////////////////////////////////////////////////////////////////////
+
+var _drop = function(graphId, dropCollections) {
+
+ var gdb = getGraphCollection();
+
+ if (!gdb.exists(graphId)) {
+ var err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_NOT_FOUND.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_NOT_FOUND.message;
+ throw err;
+ }
+
+ if (dropCollections !== false) {
+ var graph = gdb.document(graphId);
+ var edgeDefinitions = graph.edgeDefinitions;
+ edgeDefinitions.forEach(
+ function(edgeDefinition) {
+ var from = edgeDefinition.from;
+ var to = edgeDefinition.to;
+ var collection = edgeDefinition.collection;
+ var graphs = getGraphCollection().toArray();
+ if (checkIfMayBeDropped(collection, graph._key, graphs)) {
+ db._drop(collection);
+ }
+ from.forEach(
+ function(col) {
+ if (checkIfMayBeDropped(col, graph._key, graphs)) {
+ db._drop(col);
+ }
+ }
+ );
+ to.forEach(
+ function(col) {
+ if (checkIfMayBeDropped(col, graph._key, graphs)) {
+ db._drop(col);
+ }
+ }
+ );
+ }
+ );
+ }
+
+ gdb.remove(graphId);
+ return true;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief return all edge collections of the graph.
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._edgeCollections = function() {
+ return _.values(this.__edgeCollections);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief return all vertex collections of the graph.
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._vertexCollections = function() {
+ return _.values(this.__vertexCollections);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief _EDGES(vertexId).
+////////////////////////////////////////////////////////////////////////////////
+
+// might be needed from AQL itself
+Graph.prototype._EDGES = function(vertexId) {
+ if (vertexId.indexOf("/") === -1) {
+ throw vertexId + " is not a valid id";
+ }
+ var collection = vertexId.split("/")[0];
+ if (!db._collection(collection)) {
+ throw collection + " does not exist.";
+ }
+
+ var edgeCollections = this._edgeCollections();
+ var result = [];
+
+ edgeCollections.forEach(
+ function(edgeCollection) {
+ result = result.concat(edgeCollection.edges(vertexId));
+ }
+ );
+ return result;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief INEDGES(vertexId).
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._INEDGES = function(vertexId) {
+ if (vertexId.indexOf("/") === -1) {
+ throw vertexId + " is not a valid id";
+ }
+ var collection = vertexId.split("/")[0];
+ if (!db._collection(collection)) {
+ throw collection + " does not exist.";
+ }
+
+ var edgeCollections = this._edgeCollections();
+ var result = [];
+
+
+ edgeCollections.forEach(
+ function(edgeCollection) {
+ result = result.concat(edgeCollection.inEdges(vertexId));
+ }
+ );
+ return result;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief outEdges(vertexId).
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._OUTEDGES = function(vertexId) {
+ if (vertexId.indexOf("/") === -1) {
+ throw vertexId + " is not a valid id";
+ }
+ var collection = vertexId.split("/")[0];
+ if (!db._collection(collection)) {
+ throw collection + " does not exist.";
+ }
+
+ var edgeCollections = this._edgeCollections();
+ var result = [];
+
+
+ edgeCollections.forEach(
+ function(edgeCollection) {
+ result = result.concat(edgeCollection.outEdges(vertexId));
+ }
+ );
+ return result;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_edges
+/// Select some edges from the graph.
+///
+/// `graph.edges(examples)`
+///
+/// Creates an AQL statement to select a subset of the edges stored in the graph.
+/// This is one of the entry points for the fluent AQL interface.
+/// It will return a mutable AQL statement which can be further refined, using the
+/// functions described below.
+/// The resulting set of edges can be filtered by defining one or more *examples*.
+///
+/// *examples* can have the following values:
+///
+/// * Empty, there is no matching executed all edges are valid.
+/// * A string, only the edge having this value as it's id is returned.
+/// * An example object, defining a set of attributes.
+/// Only edges having these attributes are matched.
+/// * A list containing example objects and/or strings.
+/// All edges matching at least one of the elements in the list are returned.
+///
+/// @EXAMPLES
+///
+/// In the examples the *toArray* function is used to print the result.
+/// The description of this module can be found below.
+///
+/// To request unfiltered edges:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphEdgesUnfiltered}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g._edges().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered edges:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphEdgesFiltered}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g._edges({type: "married"}).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._edges = function(edgeExample) {
+ var AQLStmt = new AQLGenerator(this);
+ // If no direction is specified all edges are duplicated.
+ // => For initial requests a direction has to be set
+ return AQLStmt.outEdges(edgeExample);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_vertices
+/// Select some vertices from the graph.
+///
+/// `graph.vertices(examples)`
+///
+/// Creates an AQL statement to select a subset of the vertices stored in the graph.
+/// This is one of the entry points for the fluent AQL interface.
+/// It will return a mutable AQL statement which can be further refined, using the
+/// functions described below.
+/// The resulting set of edges can be filtered by defining one or more *examples*.
+///
+/// *examples* can have the following values:
+///
+/// * Empty, there is no matching executed all vertices are valid.
+/// * A string, only the vertex having this value as it's id is returned.
+/// * An example object, defining a set of attributes.
+/// Only vertices having these attributes are matched.
+/// * A list containing example objects and/or strings.
+/// All vertices matching at least one of the elements in the list are returned.
+///
+/// @EXAMPLES
+///
+/// In the examples the *toArray* function is used to print the result.
+/// The description of this module can be found below.
+///
+/// To request unfiltered vertices:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphVerticesUnfiltered}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g._vertices().toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// To request filtered vertices:
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphVerticesFiltered}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g._vertices([{name: "Alice"}, {name: "Bob"}]).toArray();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._vertices = function(example) {
+ var AQLStmt = new AQLGenerator(this);
+ return AQLStmt.vertices(example);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_getFromVertex
+/// Get the vertex of an edge defined as *_from*
+///
+/// `general-graph._getFromVertex(edgeId)`
+///
+/// Returns the vertex defined with the attribute *_from* of the edge with *edgeId* as its *_id*.
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphGetFromVertex}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g._getFromVertex("relation/aliceAndBob")
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._getFromVertex = function(edgeId) {
+ var edgeCollection = this._getEdgeCollectionByName(edgeId.split("/")[0]);
+ var document = edgeCollection.document(edgeId);
+ if (document) {
+ var vertexId = document._from;
+ var vertexCollection = this._getVertexCollectionByName(vertexId.split("/")[0]);
+ return vertexCollection.document(vertexId);
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph_getToVertex
+/// Get the vertex of an edge defined as *_to*
+///
+/// `general-graph._getToVertex(edgeId)`
+///
+/// Returns the vertex defined with the attribute *_to* of the edge with *edgeId* as its *_id*.
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphGetToVertex}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var g = examples.loadGraph("social");
+/// g._getToVertex("relation/aliceAndBob")
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._getToVertex = function(edgeId) {
+ var edgeCollection = this._getEdgeCollectionByName(edgeId.split("/")[0]);
+ var document = edgeCollection.document(edgeId);
+ if (document) {
+ var vertexId = document._to;
+ var vertexCollection = this._getVertexCollectionByName(vertexId.split("/")[0]);
+ return vertexCollection.document(vertexId);
+ }
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief get edge collection by name.
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._getEdgeCollectionByName = function(name) {
+ if (this.__edgeCollections[name]) {
+ return this.__edgeCollections[name];
+ }
+ throw "Collection " + name + " does not exist in graph.";
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief get vertex collection by name.
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._getVertexCollectionByName = function(name) {
+ if (this.__vertexCollections[name]) {
+ return this.__vertexCollections[name];
+ }
+ throw "Collection " + name + " does not exist in graph.";
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief get common neighbors of two vertices in the graph.
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._listCommonNeighbors = function(vertex1Example, vertex2Example, optionsVertex1, optionsVertex2) {
+
+ var ex1 = transformExample(vertex1Example);
+ var ex2 = transformExample(vertex2Example);
+ var query = "FOR e"
+ + " IN GRAPH_COMMON_NEIGHBORS(@graphName"
+ + ',@ex1'
+ + ',@ex2'
+ + ',@options1'
+ + ',@options2'
+ + ') SORT ATTRIBUTES(e)[0] RETURN e';
+ optionsVertex1 = optionsVertex1 || {};
+ optionsVertex2 = optionsVertex2 || {};
+ var bindVars = {
+ "graphName": this.__name,
+ "options1": optionsVertex1,
+ "options2": optionsVertex2,
+ "ex1": ex1,
+ "ex2": ex2
+ };
+ return db._query(query, bindVars, {count: true}).toArray();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief get amount of common neighbors of two vertices in the graph.
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._amountCommonNeighbors = function(vertex1Example, vertex2Example, optionsVertex1, optionsVertex2) {
+ var ex1 = transformExample(vertex1Example);
+ var ex2 = transformExample(vertex2Example);
+ var query = "FOR e"
+ + " IN GRAPH_COMMON_NEIGHBORS(@graphName"
+ + ',@ex1'
+ + ',@ex2'
+ + ',@options1'
+ + ',@options2'
+ + ') FOR a in ATTRIBUTES(e) FOR b in ATTRIBUTES(e[a]) '
+ + 'SORT ATTRIBUTES(e)[0] RETURN [a, b, LENGTH(e[a][b]) ]';
+ optionsVertex1 = optionsVertex1 || {};
+ optionsVertex2 = optionsVertex2 || {};
+ var bindVars = {
+ "graphName": this.__name,
+ "options1": optionsVertex1,
+ "options2": optionsVertex2,
+ "ex1": ex1,
+ "ex2": ex2
+ };
+ var result = db._query(query, bindVars, {count: true}).toArray(),
+ tmp = {}, tmp2={}, returnHash = [];
+ result.forEach(function (r) {
+ if (!tmp[r[0]]) {
+ tmp[r[0]] = [];
+ }
+ tmp2 = {};
+ tmp2[r[1]] = r[2];
+ tmp[r[0]].push(tmp2);
+ });
+ Object.keys(tmp).forEach(function(w) {
+ tmp2 = {};
+ tmp2[w] = tmp[w];
+ returnHash.push(tmp2);
+ });
+ return returnHash;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief get common properties of two vertices in the graph.
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._listCommonProperties = function(vertex1Example, vertex2Example, options) {
+
+ var ex1 = transformExample(vertex1Example);
+ var ex2 = transformExample(vertex2Example);
+ var query = "FOR e"
+ + " IN GRAPH_COMMON_PROPERTIES(@graphName"
+ + ',@ex1'
+ + ',@ex2'
+ + ',@options'
+ + ') SORT ATTRIBUTES(e)[0] RETURN e';
+ options = options || {};
+ var bindVars = {
+ "graphName": this.__name,
+ "options": options,
+ "ex1": ex1,
+ "ex2": ex2
+ };
+ return db._query(query, bindVars, {count: true}).toArray();
+
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief get amount of common properties of two vertices in the graph.
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._amountCommonProperties = function(vertex1Example, vertex2Example, options) {
+ var ex1 = transformExample(vertex1Example);
+ var ex2 = transformExample(vertex2Example);
+ var query = "FOR e"
+ + " IN GRAPH_COMMON_PROPERTIES(@graphName"
+ + ',@ex1'
+ + ',@ex2'
+ + ',@options'
+ + ') FOR a in ATTRIBUTES(e) SORT ATTRIBUTES(e)[0] RETURN [ ATTRIBUTES(e)[0], LENGTH(e[a]) ]';
+ options = options || {};
+ var bindVars = {
+ "graphName": this.__name,
+ "options": options,
+ "ex1": ex1,
+ "ex2": ex2
+ };
+ var result = db._query(query, bindVars, {count: true}).toArray(), returnHash = [];
+ result.forEach(function (r) {
+ var tmp = {};
+ tmp[r[0]] = r[1];
+ returnHash.push(tmp);
+ });
+ return returnHash;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph__extendEdgeDefinitions
+/// Extends the edge definitions of a graph. If the edge collection of the edge definition
+/// to add is already used in the graph or used in a different graph with different from
+/// an to collections an error is thrown.
+///
+/// `general-graph._extendEdgeDefinitions(edgeDefinition)`
+///
+/// *edgeDefinition* - [string] : the edge definition to extend the graph
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__extendEdgeDefinitions}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var ed2 = examples._directedRelationDefinition("myEC2", ["myVC1"], ["myVC3"]);
+/// var g = examples._create("myGraph", [ed1]);
+/// g._extendEdgeDefinitions(ed2);
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._extendEdgeDefinitions = function(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);
+ this.__edgeCollections[edgeDefinition.collection] = db[edgeDefinition.collection];
+ edgeDefinition.from.forEach(
+ function(vc) {
+ if (self.__vertexCollections[vc] === undefined) {
+ self.__vertexCollections[vc] = db[vc];
+ }
+ }
+ );
+ edgeDefinition.to.forEach(
+ function(vc) {
+ if (self.__vertexCollections[vc] === undefined) {
+ self.__vertexCollections[vc] = db[vc];
+ }
+ }
+ );
+
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph__editEdgeDefinition
+/// Edits the edge definitions of a graph. The edge definition used as argument will
+/// replace the existing edge definition the corresponding edge definition in graphs
+/// edge definitions. Other graphs with the same edge definition will be modified, too.
+///
+/// `general-graph._editEdgeDefinition(edgeDefinition, dropCollections)`
+///
+/// *edgeDefinition* - [string] : the edge definition to replace the existing edge
+/// definition with the same attribut *collection*.
+/// *dropCollections* - bool : True, all collections that are not used anymore in any
+/// graph will be removed. Default: true.
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__editEdgeDefinition}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var ed2 = examples._directedRelationDefinition("myEC1", ["myVC2"], ["myVC3"]);
+/// var g = examples._create("myGraph", [ed1, ed2]);
+/// g._editEdgeDefinition(ed2, true);
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+Graph.prototype._editEdgeDefinitions = function(edgeDefinition, dropCollections) {
+ var self = this;
+ var dropCandidates;
+ var currentEdgeDefinition = {};
+
+
+ //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;
+ }
+
+ //change definition for ALL graphs
+ var graphs = getGraphCollection().toArray();
+ graphs.forEach(
+ function(graph) {
+ var eDs = graph.edgeDefinitions;
+ eDs.forEach(
+ function(eD, id) {
+ if(eD.collection === edgeDefinition.collection) {
+ currentEdgeDefinition.from = eD.from;
+ currentEdgeDefinition.to = eD.to;
+ eDs[id].from = edgeDefinition.from;
+ eDs[id].to = edgeDefinition.to;
+ db._graphs.update(graph._key, {edgeDefinitions: eDs});
+ if (graph._key === self.__name) {
+ self.__edgeDefinitions[id].from = edgeDefinition.from;
+ self.__edgeDefinitions[id].to = edgeDefinition.to;
+ }
+ }
+ }
+ );
+ }
+ );
+
+ findOrCreateCollectionsByEdgeDefinitions([edgeDefinition]);
+
+ if (dropCollections !== false) {
+ graphs = getGraphCollection().toArray();
+ //eval collection to be dropped
+ dropCandidates = currentEdgeDefinition.from;
+ currentEdgeDefinition.to.forEach(
+ function (col) {
+ if (dropCandidates.indexOf(col) === -1) {
+ dropCandidates.push(col);
+ }
+ }
+ );
+ dropCandidates.forEach(
+ function(dc) {
+ if (checkIfMayBeDropped(dc, null, graphs)) {
+ db._drop(dc);
+ }
+ }
+ );
+ }
+
+
+ //push "new" collections into vertexCollections
+ edgeDefinition.from.forEach(
+ function(vc) {
+ if (self.__vertexCollections[vc] === undefined) {
+ self.__vertexCollections[vc] = db[vc];
+ }
+ }
+ );
+ edgeDefinition.to.forEach(
+ function(vc) {
+ if (self.__vertexCollections[vc] === undefined) {
+ self.__vertexCollections[vc] = db[vc];
+ }
+ }
+ );
+
+ //remove "old" collections from vertexCollections
+ dropCandidates.forEach(
+ function(dropCanditate) {
+ var drop = true;
+ self.__edgeDefinitions.forEach(
+ function(eD) {
+ eD.from.forEach(
+ function(vC) {
+ if (vC === dropCanditate) {
+ drop = false;
+ }
+ }
+ );
+ }
+ );
+ if (drop) {
+ delete self.__vertexCollections[dropCanditate];
+ }
+ }
+ );
+
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph__deleteEdgeDefinition
+/// Deletes an edge definition defined by the edge collection of a graph. If the
+/// collections defined in the edge definition (collection, from, to) are not used
+/// in another graph, they will be removed.
+///
+/// `general-graph._deleteEdgeDefinition(edgeCollectionName, dropCollections)`
+///
+/// *edgeCollectionName* - string : name of edge collection defined in *collection* of the edge
+/// definition.
+/// *dropCollections* - bool : True, all collections are removed, if not used in another edge
+/// definition (including other graphs). Default: true.
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__deleteEdgeDefinition}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var ed2 = examples._directedRelationDefinition("myEC2", ["myVC1"], ["myVC3"]);
+/// var g = examples._create("myGraph", [ed1, ed2]);
+/// g._deleteEdgeDefinition("myEC1", true);
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._deleteEdgeDefinition = function(edgeCollection, dropCollections) {
+ var edgeDefinitions = this.__edgeDefinitions,
+ vertexCollections = [],
+ definitionFound = false,
+ index;
+
+ edgeDefinitions.forEach(
+ function(edgeDefinition, idx) {
+ if (edgeDefinition.collection === edgeCollection) {
+ definitionFound = true;
+ if (dropCollections !== false) {
+ //get all vertex collections
+ var vertexCols = edgeDefinition.from.concat(edgeDefinition.to);
+ vertexCols.forEach(
+ function(vertexCol) {
+ if (vertexCollections.indexOf(vertexCol) === -1) {
+ vertexCollections.push(vertexCol);
+ }
+ }
+ );
+ }
+ }
+ }
+ );
+ if (definitionFound) {
+ edgeDefinitions.splice(index, 1);
+ this.__edgeDefinitions = edgeDefinitions;
+ db._graphs.update(this.__name, {edgeDefinitions: this.__edgeDefinitions});
+ }
+ if (dropCollections !== false) {
+ if (checkIfMayBeDropped(edgeCollection, this.__name, getGraphCollection().toArray())) {
+ db._drop(edgeCollection);
+ }
+ vertexCollections.forEach(
+ function(vC) {
+ if (checkIfMayBeDropped(vC, this.__name, getGraphCollection().toArray())) {
+ db._drop(vC);
+ }
+ }
+ );
+
+ }
+
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph__addOrphanCollection
+/// Adds a vertex collection to the set of orphan collections of the graph. If the
+/// collection does not exist, it will be created.
+///
+/// `general-graph._addOrphanCollection(orphanCollectionName, createCollection)`
+///
+/// *orphanCollectionName* - string : name of vertex collection.
+/// *createCollection* - bool : if true the collection will be created if it does not exist. Default: true.
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__addOrphanCollection}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var g = examples._create("myGraph", [ed1, ed2]);
+/// g._addOrphanCollection("myVC3", true);
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._addOrphanCollection = function(vertexCollection, createCollection) {
+ //check edgeCollection
+ var ec = db._collection(vertexCollection);
+ var err;
+ if (ec === null) {
+ if (createCollection !== false) {
+ db._create(vertexCollection);
+ } else {
+ err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code;
+ err.errorMessage = vertexCollection + 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;
+ }
+
+ this.__orphanCollections.push(vertexCollection);
+ db._graphs.update(this.__name, {orphanCollections: this.__orphanCollections});
+
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph__getOrphanCollections
+/// Returns all vertex collections of the graph, that are not used in an edge definition.
+///
+/// `general-graph._getOrphanCollections()`
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__getOrphanCollections}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var g = examples._create("myGraph", [ed1]);
+/// g._addOrphanCollection("myVC3, true);
+/// g._getOrphanCollections();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._getOrphanCollections = function() {
+ return this.__orphanCollections;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph__removeOrphanCollection
+/// Removes an orphan collection from the graph and deletes the collection, if it is not
+/// used in any graph.
+///
+/// `general-graph._removeOrphanCollection()`
+///
+/// *orphanCollectionName* - string : name of vertex collection.
+/// *dropCollection* - bool : if true the collection will be dropped if it is not used in any graph.
+/// Default: true.
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__getOrphanCollections}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var g = examples._create("myGraph", [ed1]);
+/// g._addOrphanCollection("myVC3, true);
+/// g._addOrphanCollection("myVC4, true);
+/// g._getOrphanCollections();
+/// g._removeOrphanCollection("myVC3");
+/// g._getOrphanCollections();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._removeOrphanCollection = function(orphanCollectionName, dropCollection) {
+ var err;
+ if (db._collection(orphanCollectionName) === null) {
+ err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message;
+ throw err;
+ }
+ var index = this.__orphanCollections.indexOf(orphanCollectionName);
+ if (index === -1) {
+ err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.message;
+ throw err;
+ }
+ this.__orphanCollections.splice(index, 1);
+
+ if (dropCollection !== false) {
+ var graphs = getGraphCollection().toArray();
+ if (checkIfMayBeDropped(orphanCollectionName, null, graphs)) {
+ db._drop(orphanCollectionName);
+ }
+ }
+};
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief print basic information for the graph
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._PRINT = function(context) {
+ var name = this.__name;
+ var edgeDefs = printEdgeDefinitions(this.__edgeDefinitions);
+ context.output += "[ Graph ";
+ context.output += name;
+ context.output += " EdgeDefinitions: ";
+ internal.printRecursive(edgeDefs, context);
+ context.output += " ]";
+};
+
+// -----------------------------------------------------------------------------
+// --SECTION-- MODULE EXPORTS
+// -----------------------------------------------------------------------------
+
+exports._undirectedRelationDefinition = _undirectedRelationDefinition;
+exports._directedRelationDefinition = _directedRelationDefinition;
+exports._graph = _graph;
+exports._edgeDefinitions = _edgeDefinitions;
+exports._extendEdgeDefinitions = _extendEdgeDefinitions;
+exports._create = _create;
+exports._drop = _drop;
+exports._exists = _exists;
+
+// -----------------------------------------------------------------------------
+// --SECTION-- END-OF-FILE
+// -----------------------------------------------------------------------------
+
+// Local Variables:
+// mode: outline-minor
+// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
+// End:
+});
diff --git a/js/apps/system/aardvark/frontend/js/modules/org/arangodb/graph-blueprint.js b/js/apps/system/aardvark/frontend/js/modules/org/arangodb/graph-blueprint.js
new file mode 100644
index 0000000000..b1e27e7da7
--- /dev/null
+++ b/js/apps/system/aardvark/frontend/js/modules/org/arangodb/graph-blueprint.js
@@ -0,0 +1,432 @@
+module.define("org/arangodb/graph-blueprint", function(exports, module) {
+/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
+/*global require, exports */
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Graph functionality
+///
+/// @file
+///
+/// DISCLAIMER
+///
+/// Copyright 2010-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 Dr. Frank Celler, Lucas Dohmen
+/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
+////////////////////////////////////////////////////////////////////////////////
+
+var arangodb = require("org/arangodb"),
+ is = require("org/arangodb/is"),
+ common = require("org/arangodb/graph-common"),
+ Edge = common.Edge,
+ Graph = common.Graph,
+ Vertex = common.Vertex,
+ GraphArray = common.GraphArray,
+ Iterator = common.Iterator,
+ GraphAPI = require ("org/arangodb/api/graph").GraphAPI;
+
+
+// -----------------------------------------------------------------------------
+// --SECTION-- public methods
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @addtogroup ArangoGraph
+/// @{
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief changes a property of an edge
+////////////////////////////////////////////////////////////////////////////////
+
+Edge.prototype.setProperty = function (name, value) {
+ var results,
+ update = this._properties;
+
+ update[name] = value;
+ this._graph.emptyCachedPredecessors();
+
+ results = GraphAPI.putEdge(this._graph._properties._key, this._properties._key, update);
+
+ this._properties = results.edge;
+
+ return name;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @}
+////////////////////////////////////////////////////////////////////////////////
+
+// -----------------------------------------------------------------------------
+// --SECTION-- Vertex
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// --SECTION-- constructors and destructors
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @addtogroup ArangoGraph
+/// @{
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief constructs a new vertex object
+////////////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// @}
+////////////////////////////////////////////////////////////////////////////////
+
+// -----------------------------------------------------------------------------
+// --SECTION-- public methods
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @addtogroup ArangoGraph
+/// @{
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief inbound and outbound edges
+////////////////////////////////////////////////////////////////////////////////
+
+Vertex.prototype.edges = function (direction, labels) {
+ var edge,
+ edges = new GraphArray(),
+ cursor;
+
+ cursor = GraphAPI.postEdges(this._graph._vertices._database, this._graph._properties._key, this, {
+ filter : { direction : direction, labels: labels }
+ });
+
+ while (cursor.hasNext()) {
+ edge = new Edge(this._graph, cursor.next());
+ edges.push(edge);
+ }
+
+ return edges;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief inbound edges with given label
+////////////////////////////////////////////////////////////////////////////////
+
+Vertex.prototype.getInEdges = function () {
+ var labels = Array.prototype.slice.call(arguments);
+ return this.edges("in", labels);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief outbound edges with given label
+////////////////////////////////////////////////////////////////////////////////
+
+Vertex.prototype.getOutEdges = function () {
+ var labels = Array.prototype.slice.call(arguments);
+ return this.edges("out", labels);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief in- or outbound edges with given label
+////////////////////////////////////////////////////////////////////////////////
+
+Vertex.prototype.getEdges = function () {
+ var labels = Array.prototype.slice.call(arguments);
+ return this.edges("any", labels);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief inbound edges
+////////////////////////////////////////////////////////////////////////////////
+
+Vertex.prototype.inbound = function () {
+ return this.getInEdges();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief outbound edges
+////////////////////////////////////////////////////////////////////////////////
+
+Vertex.prototype.outbound = function () {
+ return this.getOutEdges();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief changes a property of a vertex
+////////////////////////////////////////////////////////////////////////////////
+
+Vertex.prototype.setProperty = function (name, value) {
+ var results,
+ update = this._properties;
+
+ update[name] = value;
+
+ results = GraphAPI.putVertex(this._graph._properties._key, this._properties._key, update);
+
+ this._properties = results.vertex;
+
+ return name;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @}
+////////////////////////////////////////////////////////////////////////////////
+
+// -----------------------------------------------------------------------------
+// --SECTION-- constructors and destructors
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @addtogroup ArangoGraph
+/// @{
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief constructs a new graph object
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype.initialize = function (name, vertices, edges) {
+ var results;
+
+ if (is.notExisty(vertices) && is.notExisty(edges)) {
+ results = GraphAPI.getGraph(name);
+ } else {
+ if (typeof vertices === 'object' && typeof vertices.name === 'function') {
+ vertices = vertices.name();
+ }
+ if (typeof edges === 'object' && typeof edges.name === 'function') {
+ edges = edges.name();
+ }
+
+ results = GraphAPI.postGraph({
+ _key: name,
+ vertices: vertices,
+ edges: edges
+ });
+ }
+
+ this._properties = results.graph;
+ this._vertices = arangodb.db._collection(this._properties.edgeDefinitions[0].from[0]);
+ this._edges = arangodb.db._collection(this._properties.edgeDefinitions[0].collection);
+
+ // and dictionary for vertices and edges
+ this._verticesCache = {};
+ this._edgesCache = {};
+
+ // and store the cashes
+ this.predecessors = {};
+ this.distances = {};
+
+ return this;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @}
+////////////////////////////////////////////////////////////////////////////////
+
+// -----------------------------------------------------------------------------
+// --SECTION-- public methods
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @addtogroup ArangoGraph
+/// @{
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief return all graphs
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.getAll = function () {
+ return GraphAPI.getAllGraphs();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief static delete method
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.drop = function (name) {
+ GraphAPI.deleteGraph(name);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief drops the graph, the vertices, and the edges
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype.drop = function () {
+ GraphAPI.deleteGraph(this._properties._key);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief saves an edge to the graph
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._saveEdge = function(id, out_vertex_id, in_vertex_id, params) {
+ var results;
+
+ this.emptyCachedPredecessors();
+
+ params._key = id;
+ params._from = out_vertex_id;
+ params._to = in_vertex_id;
+
+ results = GraphAPI.postEdge(this._properties._key, params);
+ return new Edge(this, results.edge);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief saves a vertex to the graph
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._saveVertex = function (id, params) {
+ var results;
+
+ if (is.existy(id)) {
+ params._key = id;
+ }
+
+ results = GraphAPI.postVertex(this._properties._key, params);
+ return new Vertex(this, results.vertex);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief replace a vertex in the graph
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._replaceVertex = function (id, data) {
+ GraphAPI.putVertex(this._properties._key, id, data);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief replace an edge in the graph
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._replaceEdge = function (id, data) {
+ GraphAPI.putEdge(this._properties._key, id, data);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief returns a vertex given its id
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype.getVertex = function (id) {
+ var results = GraphAPI.getVertex(this._properties._key, id);
+
+ if (is.notExisty(results)) {
+ return null;
+ }
+
+ return new Vertex(this, results.vertex);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief returns an iterator for all vertices
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype.getVertices = function () {
+ var cursor = GraphAPI.getVertices(this._vertices._database, this._properties._key, {}),
+ graph = this,
+ wrapper = function(object) {
+ return new Vertex(graph, object);
+ };
+
+ return new Iterator(wrapper, cursor, "[vertex iterator]");
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief returns an edge given its id
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype.getEdge = function (id) {
+ var results = GraphAPI.getEdge(this._properties._key, id);
+
+ if (is.notExisty(results)) {
+ return null;
+ }
+
+ return new Edge(this, results.edge);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief returns an iterator for all edges
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype.getEdges = function () {
+ var cursor = GraphAPI.getEdges(this._vertices._database, this._properties._key, {}),
+ graph = this,
+ wrapper = function(object) {
+ return new Edge(graph, object);
+ };
+ return new Iterator(wrapper, cursor, "[edge iterator]");
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief removes a vertex and all in- or out-bound edges
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype.removeVertex = function (vertex) {
+ this.emptyCachedPredecessors();
+ GraphAPI.deleteVertex(this._properties._key, vertex._properties._key);
+ vertex._properties = undefined;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief removes an edge
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype.removeEdge = function (edge) {
+ this.emptyCachedPredecessors();
+ GraphAPI.deleteEdge(this._properties._key, edge._properties._key);
+ this._edgesCache[edge._properties._id] = undefined;
+ edge._properties = undefined;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @}
+////////////////////////////////////////////////////////////////////////////////
+
+// -----------------------------------------------------------------------------
+// --SECTION-- MODULE EXPORTS
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @addtogroup ArangoGraph
+/// @{
+////////////////////////////////////////////////////////////////////////////////
+
+exports.Edge = Edge;
+exports.Graph = Graph;
+exports.Vertex = Vertex;
+exports.GraphArray = GraphArray;
+
+
+require("org/arangodb/graph/algorithms-common");
+
+////////////////////////////////////////////////////////////////////////////////
+/// @}
+////////////////////////////////////////////////////////////////////////////////
+
+// -----------------------------------------------------------------------------
+// --SECTION-- END-OF-FILE
+// -----------------------------------------------------------------------------
+
+// Local Variables:
+// mode: outline-minor
+// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
+// End:
+});
diff --git a/js/apps/system/aardvark/index.html b/js/apps/system/aardvark/index.html
index 8c0946bc6c..9df14073fb 100644
--- a/js/apps/system/aardvark/index.html
+++ b/js/apps/system/aardvark/index.html
@@ -5,7 +5,7 @@
ArangoDB Web Interface
-
+
diff --git a/js/apps/system/aardvark/manifest.json b/js/apps/system/aardvark/manifest.json
index 7284407d12..f910eda002 100644
--- a/js/apps/system/aardvark/manifest.json
+++ b/js/apps/system/aardvark/manifest.json
@@ -102,6 +102,7 @@
"frontend/js/bootstrap/module-internal.js",
"frontend/js/client/bootstrap/module-internal.js",
"frontend/js/client/client.js",
+ "frontend/js/bootstrap/module-console.js",
"frontend/js/models/arangoCollectionModel.js",
"frontend/js/models/arangoDatabase.js",
"frontend/js/models/arangoDocument.js",
diff --git a/js/client/bootstrap/module-internal.js b/js/client/bootstrap/module-internal.js
index 4150e8c275..e845ee0f69 100644
--- a/js/client/bootstrap/module-internal.js
+++ b/js/client/bootstrap/module-internal.js
@@ -1,5 +1,5 @@
/*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true, white: true, plusplus: true, nonpropdel: true */
-/*global require, ArangoConnection, print, SYS_ARANGO */
+/*global require, ArangoConnection, print, SYS_ARANGO, window */
////////////////////////////////////////////////////////////////////////////////
/// @brief module "internal"
@@ -300,6 +300,32 @@
internal.output(level, ": ", msg, "\n");
};
+////////////////////////////////////////////////////////////////////////////////
+/// @brief sprintf wrapper
+////////////////////////////////////////////////////////////////////////////////
+
+ try {
+ if (window) {
+ internal.sprintf = function (format) {
+ var n = arguments.length;
+ if (n === 0) {
+ return "";
+ }
+ if (n <= 1) {
+ return String(format);
+ }
+
+ var i = 0;
+
+ return format.replace(/%[dfs]/, function (match) {
+ return String(arguments[++i]);
+ });
+ };
+ }
+ }
+ catch (err) {
+ }
+
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
diff --git a/js/common/bootstrap/errors.js b/js/common/bootstrap/errors.js
index 1fb6732900..49167af3a6 100644
--- a/js/common/bootstrap/errors.js
+++ b/js/common/bootstrap/errors.js
@@ -104,6 +104,7 @@
"ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING" : { "code" : 1234, "message" : "index insertion warning - attribute missing in document" },
"ERROR_ARANGO_INDEX_CREATION_FAILED" : { "code" : 1235, "message" : "index creation failed" },
"ERROR_ARANGO_DATAFILE_FULL" : { "code" : 1300, "message" : "datafile full" },
+ "ERROR_ARANGO_EMPTY_DATADIR" : { "code" : 1301, "message" : "server database directory is empty" },
"ERROR_REPLICATION_NO_RESPONSE" : { "code" : 1400, "message" : "no response" },
"ERROR_REPLICATION_INVALID_RESPONSE" : { "code" : 1401, "message" : "invalid response" },
"ERROR_REPLICATION_MASTER_ERROR" : { "code" : 1402, "message" : "master error" },
@@ -169,8 +170,6 @@
"ERROR_QUERY_GEO_INDEX_MISSING" : { "code" : 1570, "message" : "no suitable geo index found for geo restriction on '%s'" },
"ERROR_QUERY_FULLTEXT_INDEX_MISSING" : { "code" : 1571, "message" : "no suitable fulltext index found for fulltext query on '%s'" },
"ERROR_QUERY_INVALID_DATE_VALUE" : { "code" : 1572, "message" : "invalid date value" },
- "ERROR_QUERY_MULTI_MODIFY" : { "code" : 1573, "message" : "multi-modify query" },
- "ERROR_QUERY_MODIFY_IN_SUBQUERY" : { "code" : 1574, "message" : "modify in subquery" },
"ERROR_QUERY_FUNCTION_INVALID_NAME" : { "code" : 1580, "message" : "invalid user function name" },
"ERROR_QUERY_FUNCTION_INVALID_CODE" : { "code" : 1581, "message" : "invalid user function code" },
"ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function '%s()' not found" },
@@ -179,7 +178,6 @@
"ERROR_TRANSACTION_NESTED" : { "code" : 1651, "message" : "nested transactions detected" },
"ERROR_TRANSACTION_UNREGISTERED_COLLECTION" : { "code" : 1652, "message" : "unregistered collection used in transaction" },
"ERROR_TRANSACTION_DISALLOWED_OPERATION" : { "code" : 1653, "message" : "disallowed operation inside transaction" },
- "ERROR_TRANSACTION_ABORTED" : { "code" : 1654, "message" : "transaction aborted" },
"ERROR_USER_INVALID_NAME" : { "code" : 1700, "message" : "invalid user name" },
"ERROR_USER_INVALID_PASSWORD" : { "code" : 1701, "message" : "invalid password" },
"ERROR_USER_DUPLICATE" : { "code" : 1702, "message" : "duplicate user" },
@@ -209,6 +207,15 @@
"ERROR_GRAPH_COULD_NOT_CHANGE_EDGE" : { "code" : 1908, "message" : "could not change edge" },
"ERROR_GRAPH_TOO_MANY_ITERATIONS" : { "code" : 1909, "message" : "too many iterations" },
"ERROR_GRAPH_INVALID_FILTER_RESULT" : { "code" : 1910, "message" : "invalid filter result" },
+ "ERROR_GRAPH_COLLECTION_MULTI_USE" : { "code" : 1920, "message" : "multi use of edge collection in edge def" },
+ "ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS" : { "code" : 1921, "message" : "edge collection already used in edge def" },
+ "ERROR_GRAPH_CREATE_MISSING_NAME" : { "code" : 1922, "message" : "missing graph name" },
+ "ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION" : { "code" : 1923, "message" : "malformed edge def" },
+ "ERROR_GRAPH_NOT_FOUND" : { "code" : 1924, "message" : "graph not found" },
+ "ERROR_GRAPH_DUPLICATE" : { "code" : 1925, "message" : "graph already exists" },
+ "ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST" : { "code" : 1926, "message" : "collection does not exist" },
+ "ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX" : { "code" : 1927, "message" : "not a vertex collection" },
+ "ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION" : { "code" : 1928, "message" : "not in orphan collection" },
"ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
"SIMPLE_CLIENT_UNKNOWN_ERROR" : { "code" : 2000, "message" : "unknown client error" },
diff --git a/js/common/bootstrap/module-console.js b/js/common/bootstrap/module-console.js
index 90e12d3b7b..c31023e380 100644
--- a/js/common/bootstrap/module-console.js
+++ b/js/common/bootstrap/module-console.js
@@ -1,5 +1,5 @@
/*jslint indent: 2, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, sloppy: true */
-/*global require, SYS_GETLINE, SYS_LOG */
+/*global require, SYS_GETLINE, SYS_LOG, jqconsole */
////////////////////////////////////////////////////////////////////////////////
/// @brief module "console"
@@ -64,8 +64,21 @@
/// @brief internal logging
////////////////////////////////////////////////////////////////////////////////
- var log = SYS_LOG;
- delete SYS_LOG;
+ var log;
+
+ try {
+ // this will work when we are in arangod but not in the browser / web interface
+ log = SYS_LOG;
+ delete SYS_LOG;
+ }
+ catch (err) {
+ // this will work in the web interface
+ log = function (level, message) {
+ if (jqconsole) {
+ jqconsole.Write(message + "\n", 'jssuccess');
+ }
+ };
+ }
////////////////////////////////////////////////////////////////////////////////
/// @brief internal logging with group level
diff --git a/js/common/modules/org/arangodb/general-graph.js b/js/common/modules/org/arangodb/general-graph.js
index 4525d9e87e..c5c3ba3223 100644
--- a/js/common/modules/org/arangodb/general-graph.js
+++ b/js/common/modules/org/arangodb/general-graph.js
@@ -1709,6 +1709,7 @@ var Graph = function(graphName, edgeDefinitions, vertexCollections, edgeCollecti
createHiddenProperty(this, "__edgeDefinitions", edgeDefinitions);
createHiddenProperty(this, "__idsToRemove", []);
createHiddenProperty(this, "__collectionsToLock", []);
+ createHiddenProperty(this, "__orphanCollections", []);
// fills this.__idsToRemove and this.__collectionsToLock
var removeEdge = function (edgeId, options) {
@@ -1957,6 +1958,12 @@ var checkIfMayBeDropped = function(colName, graphName, graphs) {
}
);
}
+ var orphanCollections = graph.orphanCollections;
+ if (orphanCollections) {
+ if (orphanCollections.indexOf(colName) !== -1) {
+ return false;
+ }
+ }
}
);
@@ -2557,6 +2564,7 @@ Graph.prototype._editEdgeDefinitions = function(edgeDefinition, dropCollections)
findOrCreateCollectionsByEdgeDefinitions([edgeDefinition]);
if (dropCollections !== false) {
+ graphs = getGraphCollection().toArray();
//eval collection to be dropped
dropCandidates = currentEdgeDefinition.from;
currentEdgeDefinition.to.forEach(
@@ -2689,31 +2697,129 @@ Graph.prototype._deleteEdgeDefinition = function(edgeCollection, dropCollections
};
////////////////////////////////////////////////////////////////////////////////
-/// @startDocuBlock JSF_general_graph__addVertexCollection
-/// Adds a vertex collection to the graph. If the collection does not exist, it will be created.
+/// @startDocuBlock JSF_general_graph__addOrphanCollection
+/// Adds a vertex collection to the set of orphan collections of the graph. If the
+/// collection does not exist, it will be created.
///
-/// `general-graph._addVertexCollection(vertexCollectionName, createCollection)`
+/// `general-graph._addOrphanCollection(orphanCollectionName, createCollection)`
///
-/// *vertexCollectionName* - string : name of vertex collection.
+/// *orphanCollectionName* - string : name of vertex collection.
/// *createCollection* - bool : if true the collection will be created if it does not exist. Default: true.
///
/// @EXAMPLES
///
-/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__addeleteVertexCollection}
+/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__addOrphanCollection}
/// var examples = require("org/arangodb/graph-examples/example-graph.js");
/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
/// var g = examples._create("myGraph", [ed1, ed2]);
-/// g._addVertexCollection("myVC3", true);
+/// g._addOrphanCollection("myVC3", true);
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// @endDocuBlock
///
////////////////////////////////////////////////////////////////////////////////
-Graph.prototype._addVertexCollection = function(edgeCollection, dropCollections) {
+Graph.prototype._addOrphanCollection = function(vertexCollection, createCollection) {
+ //check edgeCollection
+ var ec = db._collection(vertexCollection);
+ var err;
+ if (ec === null) {
+ if (createCollection !== false) {
+ db._create(vertexCollection);
+ } else {
+ err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code;
+ err.errorMessage = vertexCollection + 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;
+ }
+
+ this.__orphanCollections.push(vertexCollection);
+ db._graphs.update(this.__name, {orphanCollections: this.__orphanCollections});
};
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph__getOrphanCollections
+/// Returns all vertex collections of the graph, that are not used in an edge definition.
+///
+/// `general-graph._getOrphanCollections()`
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__getOrphanCollections}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var g = examples._create("myGraph", [ed1]);
+/// g._addOrphanCollection("myVC3, true);
+/// g._getOrphanCollections();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._getOrphanCollections = function() {
+ return this.__orphanCollections;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @startDocuBlock JSF_general_graph__removeOrphanCollection
+/// Removes an orphan collection from the graph and deletes the collection, if it is not
+/// used in any graph.
+///
+/// `general-graph._removeOrphanCollection()`
+///
+/// *orphanCollectionName* - string : name of vertex collection.
+/// *dropCollection* - bool : if true the collection will be dropped if it is not used in any graph.
+/// Default: true.
+///
+/// @EXAMPLES
+///
+/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__getOrphanCollections}
+/// var examples = require("org/arangodb/graph-examples/example-graph.js");
+/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var g = examples._create("myGraph", [ed1]);
+/// g._addOrphanCollection("myVC3, true);
+/// g._addOrphanCollection("myVC4, true);
+/// g._getOrphanCollections();
+/// g._removeOrphanCollection("myVC3");
+/// g._getOrphanCollections();
+/// @END_EXAMPLE_ARANGOSH_OUTPUT
+///
+/// @endDocuBlock
+///
+////////////////////////////////////////////////////////////////////////////////
+
+Graph.prototype._removeOrphanCollection = function(orphanCollectionName, dropCollection) {
+ var err;
+ if (db._collection(orphanCollectionName) === null) {
+ err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message;
+ throw err;
+ }
+ var index = this.__orphanCollections.indexOf(orphanCollectionName);
+ if (index === -1) {
+ err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.message;
+ throw err;
+ }
+ this.__orphanCollections.splice(index, 1);
+
+ if (dropCollection !== false) {
+ var graphs = getGraphCollection().toArray();
+ if (checkIfMayBeDropped(orphanCollectionName, null, graphs)) {
+ db._drop(orphanCollectionName);
+ }
+ }
+};
diff --git a/js/common/tests/shell-general-graph.js b/js/common/tests/shell-general-graph.js
index 4d459318c0..033d79ad46 100644
--- a/js/common/tests/shell-general-graph.js
+++ b/js/common/tests/shell-general-graph.js
@@ -307,7 +307,7 @@ function GeneralGraphCreationSuite() {
);
fail();
} catch (err) {
- assertEqual(err.errorMessage, "a graph name is required to create a graph.");
+ assertEqual(err.errorMessage, ERRORS.ERROR_GRAPH_CREATE_MISSING_NAME.message);
}
},
@@ -2497,6 +2497,118 @@ function GeneralGraphCommonNeighborsSuite() {
};
}
+function OrphanCollectionSuite() {
+ var prefix = "UnitTestGraphVertexCollection",
+ g1,
+ g2,
+ gN1 = prefix + "Graph1",
+ gN2 = prefix + "Graph2",
+ eC1 = prefix + "EdgeCollection1",
+ eC2 = prefix + "EdgeCollection2",
+ vC1 = prefix + "VertexCollection1",
+ vC2 = prefix + "VertexCollection2",
+ vC3 = prefix + "VertexCollection3",
+ vC4 = prefix + "VertexCollection4",
+ vC5 = prefix + "VertexCollection5";
+
+ return {
+
+ setUp : function() {
+ try {
+ arangodb.db._collection("_graphs").remove(gN1);
+ } catch (ignore) {
+ }
+ try {
+ arangodb.db._collection("_graphs").remove(gN2);
+ } catch (ignore) {
+ }
+ g1 = graph._create(
+ gN1,
+ graph._edgeDefinitions(
+ graph._directedRelationDefinition(
+ eC1, [vC1], [vC1, vC2]
+ )
+ )
+ );
+ g2 = graph._create(
+ gN2,
+ graph._edgeDefinitions(
+ graph._directedRelationDefinition(
+ eC2, [vC3], [vC1]
+ )
+ )
+ );
+ },
+
+ tearDown : function() {
+ graph._drop(gN1);
+ graph._drop(gN2);
+ try {db[vC1].drop()} catch (e) {}
+ try {db[vC4].drop()} catch (e) {}
+ },
+
+ test_getOrphanCollection: function() {
+ assertEqual(g1._getOrphanCollections(), []);
+ },
+
+ test_addOrphanCollection1: function() {
+ g1._addOrphanCollection(vC1, false);
+ assertEqual(g1._getOrphanCollections(), [vC1]);
+ },
+
+ test_addOrphanCollection2: function() {
+ try {
+ g1._addOrphanCollection(vC4, false);
+ } catch (e) {
+ assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code);
+ assertEqual(e.errorMessage, vC4 + ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message);
+ }
+ assertTrue(db._collection(vC4) === null);
+ assertEqual(g1._getOrphanCollections(), []);
+ },
+
+ test_addOrphanCollection3: function() {
+ try {
+ g1._addOrphanCollection(eC1, false);
+ } catch (e) {
+ assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.code);
+ assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.message);
+ }
+ assertTrue(db._collection(vC4) === null);
+ assertEqual(g1._getOrphanCollections(), []);
+ },
+
+ test_removeOrphanCollection1: function() {
+ var name = "completelyNonsenseNameForACollectionBLUBBBBB"
+ try {
+ g1._removeOrphanCollection(name);
+ } catch (e) {
+ assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code);
+ assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message);
+ }
+ },
+
+ test_removeOrphanCollection2: function() {
+ g1._addOrphanCollection(vC4, true);
+ g1._addOrphanCollection(vC5, true);
+ assertEqual(g1._getOrphanCollections(), [vC4, vC5]);
+ g1._removeOrphanCollection(vC4, false);
+ assertEqual(g1._getOrphanCollections(), [vC5]);
+ try {
+ g1._removeOrphanCollection(vC4);
+ } catch (e) {
+ assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.code);
+ assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.message);
+ }
+ }
+
+
+ };
+
+
+
+}
+
// -----------------------------------------------------------------------------
// --SECTION-- main
@@ -2511,7 +2623,7 @@ jsunity.run(GeneralGraphAQLQueriesSuite);
jsunity.run(EdgesAndVerticesSuite);
jsunity.run(GeneralGraphCreationSuite);
jsunity.run(ChainedFluentAQLResultsSuite);
-//jsunity.run(VertexCollectionChainedFluentAQLResultsSuite);
+jsunity.run(OrphanCollectionSuite);
return jsunity.done();
diff --git a/js/server/modules/org/arangodb/ahuacatl.js b/js/server/modules/org/arangodb/ahuacatl.js
index ac91d46e11..a99a95d66e 100644
--- a/js/server/modules/org/arangodb/ahuacatl.js
+++ b/js/server/modules/org/arangodb/ahuacatl.js
@@ -5130,7 +5130,7 @@ function IS_EXAMPLE_SET (example) {
/// @startDocuBlock JSF_ahuacatl_general_graph_shortest_paths
///
/// `GRAPH_SHORTEST_PATH (graphName, startVertexExample, endVertexExample, options)`
-/// *The GRAPH\_SHORTEST\_PATH function returns all paths of a graph.*
+/// *The GRAPH\_SHORTEST\_PATH function returns all shortest paths of a graph.*
///
/// This function determines all shortest paths in a graph identified by *graphName*.
/// The function accepts an id, an example, a list of examples
@@ -5138,7 +5138,7 @@ function IS_EXAMPLE_SET (example) {
/// start and end vertex. If one wants to calls this function to receive nearly all
/// shortest paths for a graph the
/// option *algorithm* should be set to *Floyd-Warshall* to increase performance.
-/// If no algorithm is given in the options the function chooses the appropriate
+/// If no algorithm is provided in the options the function chooses the appropriate
/// one (either *Floyd-Warshall* or *Dijsktra*) according to its parameters.
/// The length of a path is by default the amount of edges from one start vertex to
/// an end vertex. The option weight allows the user to define an edge attribute
@@ -5384,6 +5384,7 @@ function GRAPH_TRAVERSAL_TREE (vertexCollection,
/// *The GRAPH\_DISTANCE\_TO function returns all paths and there distance within a graph.*
///
/// This function is a wrapper of [GRAPH\_SHORTEST\_PATH](#SUBSECTION GRAPH_SHORTEST_PATH).
+/// It does not return the actual path but only the distance between two vertices.
///
////////////////////////////////////////////////////////////////////////////////
function GENERAL_GRAPH_DISTANCE_TO (graphName,
@@ -5689,7 +5690,7 @@ function GENERAL_GRAPH_NEIGHBORS (graphName,
}
////////////////////////////////////////////////////////////////////////////////
-/// @startDocuBlock JSF_ahuacatl_general_graph_neighbors
+/// @startDocuBlock JSF_ahuacatl_general_graph_edges
///
/// `GRAPH_EDGES (graphName, vertexExample, options)`
/// *The GRAPH\_EDGES function returns all edges of vertices.*
@@ -5919,28 +5920,27 @@ function TRANSFER_GENERAL_GRAPH_NEIGHBORS_RESULT (result) {
///
/// @EXAMPLES
///
-/// A route planner example, all neighbors of locations with a distance of
-/// either 700 or 600.:
+/// A route planner example, all common neighbors of capitals.
///
/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphVertices1}
/// ~ var db = require("internal").db;
/// var examples = require("org/arangodb/graph-examples/example-graph.js");
/// var g = examples.loadGraph("routeplanner");
/// |db._query("FOR e IN GRAPH_COMMON_NEIGHBORS("
-/// |+"'routeplanner', {}) RETURN e"
+/// |+"'routeplanner', {isCapital : true}, {isCapital : true}) RETURN e"
/// ).toArray();
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
-/// A route planner example, all outbound neighbors of munich with a maximal
-/// depth of 2 :
+/// A route planner example, all common outbound neighbors of munich with any other location
+/// which have a maximal depth of 2 :
///
/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphVertices2}
/// ~ var db = require("internal").db;
/// var examples = require("org/arangodb/graph-examples/example-graph.js");
/// var g = examples.loadGraph("routeplanner");
/// |db._query("FOR e IN GRAPH_COMMON_NEIGHBORS("
-/// |+"'routeplanner', {}, {direction : 'any', vertexCollectionRestriction" +
-/// |" : 'city'}) RETURN e"
+/// |+"'routeplanner', 'city/Munich', {}, {direction : 'outbound', maxDepth : 2}, "+
+/// | "{direction : 'outbound', maxDepth : 2}) RETURN e"
/// ).toArray();
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
@@ -6149,7 +6149,7 @@ function GENERAL_GRAPH_COMMON_PROPERTIES (
///
/// `GRAPH_ABSOLUTE_ECCENTRICITY (graphName, vertexExample, options)`
/// *The GRAPH\_ABSOLUTE\_ECCENTRICITY function returns the
-/// [eccentricity](http://en.wikipedia.org/wiki/Distance_(graph_theory))
+/// [eccentricity](http://en.wikipedia.org/wiki/Distance_%28graph_theory%29)
/// of the vertices defined by the examples.
///
/// The function accepts an id, an example, a list of examples or even an empty
@@ -6260,7 +6260,7 @@ function GENERAL_GRAPH_ABSOLUTE_ECCENTRICITY (graphName, vertexExample, options)
///
/// `GRAPH_ECCENTRICITY (graphName, options)`
/// *The GRAPH\_ECCENTRICITY function returns the normalized
-/// [eccentricity](http://en.wikipedia.org/wiki/Distance_(graph_theory))
+/// [eccentricity](http://en.wikipedia.org/wiki/Distance_%28graph_theory%29)
/// of the graphs vertices
///
/// * String *graphName* : The name of the graph.
@@ -6737,7 +6737,7 @@ function GENERAL_GRAPH_BETWEENNESS (graphName, options) {
///
/// `GRAPH_RADIUS (graphName, options)`
/// *The GRAPH\_RADIUS function returns the
-/// [radius](http://en.wikipedia.org/wiki/Eccentricity_(graph_theory))
+/// [radius](http://en.wikipedia.org/wiki/Eccentricity_%28graph_theory%29)
/// of a graph.
///
/// * String *graphName* : The name of the graph.
@@ -6829,7 +6829,7 @@ function GENERAL_GRAPH_RADIUS (graphName, options) {
///
/// `GRAPH_DIAMETER (graphName, options)`
/// *The GRAPH\_DIAMETER function returns the
-/// [diameter](http://en.wikipedia.org/wiki/Eccentricity_(graph_theory))
+/// [diameter](http://en.wikipedia.org/wiki/Eccentricity_%28graph_theory%29)
/// of a graph.
///
/// * String *graphName* : The name of the graph.
diff --git a/js/server/modules/org/arangodb/database-version.js b/js/server/modules/org/arangodb/database-version.js
index d6b47b8030..f7fb45ae46 100644
--- a/js/server/modules/org/arangodb/database-version.js
+++ b/js/server/modules/org/arangodb/database-version.js
@@ -30,10 +30,9 @@
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
-var internal = require("internal");
var cluster = require("org/arangodb/cluster");
var fs = require("fs");
-var db = internal.db;
+var db = require("org/arangodb").db;
var console = require("console");
// -----------------------------------------------------------------------------
@@ -124,7 +123,7 @@ exports.databaseVersion = function () {
}
// path to the VERSION file
- var versionFile = internal.db._path() + "/VERSION";
+ var versionFile = db._path() + "/VERSION";
var lastVersion = null;
// VERSION file exists, read its contents
@@ -152,11 +151,11 @@ exports.databaseVersion = function () {
}
// extract server version
- var currentServerVersion = internal.db._version().match(/^(\d+\.\d+).*$/);
+ var currentServerVersion = db._version().match(/^(\d+\.\d+).*$/);
// server version is invalid for some reason
if (! currentServerVersion) {
- logger.error("Unexpected ArangoDB server version: " + internal.db._version());
+ logger.error("Unexpected ArangoDB server version: " + db._version());
return { result: exports.NO_SERVER_VERSION };
}
diff --git a/js/server/modules/org/arangodb/foxx.js b/js/server/modules/org/arangodb/foxx.js
index 7cd00006a2..6562c8a9c8 100644
--- a/js/server/modules/org/arangodb/foxx.js
+++ b/js/server/modules/org/arangodb/foxx.js
@@ -30,11 +30,16 @@
var Controller = require("org/arangodb/foxx/controller").Controller,
Model = require("org/arangodb/foxx/model").Model,
- Repository = require("org/arangodb/foxx/repository").Repository;
+ Repository = require("org/arangodb/foxx/repository").Repository,
+ manager = require("org/arangodb/foxx/manager"),
+ arangodb = require("org/arangodb");
exports.Controller = Controller;
exports.Model = Model;
exports.Repository = Repository;
+exports.requireApp = function(path) {
+ return manager.mountedApp(arangodb.normalizeURL('/' + path));
+};
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
diff --git a/js/server/modules/org/arangodb/foxx/controller.js b/js/server/modules/org/arangodb/foxx/controller.js
index 85728e3c5b..597c8821ce 100644
--- a/js/server/modules/org/arangodb/foxx/controller.js
+++ b/js/server/modules/org/arangodb/foxx/controller.js
@@ -115,6 +115,12 @@ Controller = function (context, options) {
context.foxxes.push(this);
+ if (is.existy(context.manifest.rootElement)) {
+ this.rootElement =context.manifest.rootElement;
+ } else {
+ this.rootElement = false;
+ }
+
this.applicationContext = context;
};
@@ -123,22 +129,8 @@ extend(Controller.prototype, {
collection: function (name) {
'use strict';
- var collection, cname, prefix;
- prefix = this.collectionPrefix;
-
- if (prefix === "") {
- cname = name;
- } else {
- cname = prefix + "_" + name;
- }
- cname = cname.replace(/[^a-zA-Z0-9]/g, '_').replace(/(^_+|_+$)/g, '').substr(0, 64);
-
- collection = db._collection(cname);
-
- if (!collection) {
- throw new Error("collection with name '" + cname + "' does not exist.");
- }
- return collection;
+ require('console').log('Controller#collection is deprecated, use appContext#collection instead');
+ return this.applicationContext.collection(name);
},
////////////////////////////////////////////////////////////////////////////////
@@ -156,7 +148,7 @@ extend(Controller.prototype, {
handleRequest: function (method, route, callback) {
'use strict';
var newRoute = internal.constructRoute(method, route, callback),
- requestContext = new RequestContext(this.allRoutes, this.models, newRoute),
+ requestContext = new RequestContext(this.allRoutes, this.models, newRoute, this.rootElement),
summary;
this.routingInfo.routes.push(newRoute);
@@ -294,7 +286,7 @@ extend(Controller.prototype, {
///
/// This handles requests from the HTTP verb `delete`. See above for the
/// arguments you can give.
-///
+///
/// @warning Do not forget that `delete` is a reserved word in JavaScript and
/// therefore needs to be called as app['delete']. There is also an alias `del`
/// for this very reason.
diff --git a/js/server/modules/org/arangodb/foxx/manager.js b/js/server/modules/org/arangodb/foxx/manager.js
index 12f896918b..75a3172d47 100644
--- a/js/server/modules/org/arangodb/foxx/manager.js
+++ b/js/server/modules/org/arangodb/foxx/manager.js
@@ -102,7 +102,7 @@ function checkManifest (filename, mf) {
// add a default (empty) description
mf.description = "";
}
-
+
if (mf.hasOwnProperty("apps")) {
console.warn("Manifest '%s' still contains the deprecated 'apps' attribute. " +
"Please change the attribute name to 'controllers'.", filename);
@@ -121,7 +121,7 @@ function checkManifest (filename, mf) {
"assets": [ false, "object" ],
"author": [ false, "string" ],
"contributors": [ false, "array" ],
- "controllers": [ true, "object" ],
+ "controllers": [ false, "object" ],
"defaultDocument": [ false, "string" ],
"description": [ true, "string" ],
"engines": [ false, "object" ],
@@ -136,6 +136,7 @@ function checkManifest (filename, mf) {
"teardown": [ false, "string" ],
"thumbnail": [ false, "string" ],
"version": [ true, "string" ],
+ "rootElement": [ false, "boolean" ],
"exports": [ false, "object" ]
};
@@ -148,8 +149,8 @@ function checkManifest (filename, mf) {
var actualType = Array.isArray(mf[att]) ? "array" : typeof(mf[att]);
if (actualType !== expectedType) {
- console.error("Manifest '%s' uses an invalid data type (%s) for %s attribute '%s'",
- filename,
+ console.error("Manifest '%s' uses an invalid data type (%s) for %s attribute '%s'",
+ filename,
actualType,
expectedType,
att);
@@ -160,8 +161,8 @@ function checkManifest (filename, mf) {
// attribute not present in manifest
if (expected[att][0]) {
// required attribute
- console.error("Manifest '%s' does not provide required attribute '%s'",
- filename,
+ console.error("Manifest '%s' does not provide required attribute '%s'",
+ filename,
att);
failed = true;
@@ -169,7 +170,7 @@ function checkManifest (filename, mf) {
}
}
}
-
+
if (failed) {
throw new Error("Manifest '%s' is invalid/incompatible. Please check the error logs.");
}
@@ -178,8 +179,8 @@ function checkManifest (filename, mf) {
for (att in mf) {
if (mf.hasOwnProperty(att)) {
if (! expected.hasOwnProperty(att)) {
- console.warn("Manifest '%s' contains an unknown attribute '%s'",
- filename,
+ console.warn("Manifest '%s' contains an unknown attribute '%s'",
+ filename,
att);
}
}
@@ -208,6 +209,10 @@ function extendContext (context, app, root) {
return replaced;
};
+ context.collection = function (name) {
+ return arangodb.db._collection(this.collectionName(name));
+ };
+
context.path = function (name) {
return fs.join(root, app._path, name);
};
@@ -279,7 +284,7 @@ function buildAssetContent (app, assets, basePath) {
var excludeFile = function (name) {
var parts = name.split('/');
-
+
if (parts.length > 0) {
var last = parts[parts.length - 1];
@@ -303,8 +308,8 @@ function buildAssetContent (app, assets, basePath) {
if (match !== null) {
m = fs.listTree(fs.join(basePath, match[1]));
-
- // files are sorted in file-system order.
+
+ // files are sorted in file-system order.
// this makes the order non-portable
// we'll be sorting the files now using JS sort
// so the order is more consistent across multiple platforms
@@ -312,7 +317,7 @@ function buildAssetContent (app, assets, basePath) {
for (i = 0; i < m.length; ++i) {
var filename = fs.join(basePath, match[1], m[i]);
-
+
if (! excludeFile(m[i])) {
if (fs.isFile(filename)) {
files.push(filename);
@@ -322,7 +327,7 @@ function buildAssetContent (app, assets, basePath) {
}
else {
match = reAll.exec(asset);
-
+
if (match !== null) {
throw new Error("Not implemented");
}
@@ -367,7 +372,7 @@ function buildFileAsset (app, path, basePath, asset) {
type = asset.contentType;
}
- // path contains a dot, derive content type from path
+ // path contains a dot, derive content type from path
else if (path.match(/\.[a-zA-Z0-9]+$/)) {
type = arangodb.guessContentType(path);
}
@@ -399,7 +404,7 @@ function buildDevelopmentAssetRoute (app, path, basePath, asset) {
return {
url: { match: path },
- action: {
+ action: {
callback: function (req, res) {
var c = buildFileAsset(app, path, basePath, asset);
@@ -495,7 +500,7 @@ function installAssets (app, routes) {
function executeAppScript (app, name, mount, prefix) {
var desc = app._manifest;
-
+
if (! desc) {
throw new Error("Invalid application manifest, app " + arangodb.inspect(app));
}
@@ -527,6 +532,7 @@ function executeAppScript (app, name, mount, prefix) {
appContext.isDevelopment = devel;
appContext.isProduction = ! devel;
+ appContext.manifest = app._manifest;
extendContext(appContext, app, root);
@@ -557,10 +563,10 @@ function teardownApp (app, mount, prefix) {
function upsertAalAppEntry (manifest, thumbnail, path) {
var aal = getStorage();
- var doc = aal.firstExample({
- type: "app",
- name: manifest.name,
- version: manifest.version
+ var doc = aal.firstExample({
+ type: "app",
+ name: manifest.name,
+ version: manifest.version
});
if (doc === null) {
@@ -610,7 +616,7 @@ function mountAalApp (app, mount, options) {
var find = aal.firstExample({ type: "mount", mount: mount, active: true });
if (find !== null) {
- throw new Error("Cannot use mount path '" + mount + "', already used by '"
+ throw new Error("Cannot use mount path '" + mount + "', already used by '"
+ find.app + "' (" + find._key + ")");
}
@@ -747,6 +753,8 @@ function routingAalApp (app, mount, options) {
appContextTempl.isDevelopment = devel;
appContextTempl.isProduction = ! devel;
+ appContextTempl.manifest = app._manifest;
+
var appContext;
var file;
@@ -815,13 +823,13 @@ function routingAalApp (app, mount, options) {
for (j = 0; j < rt.length; ++j) {
route = rt[j];
-
+
if (route.hasOwnProperty("url")) {
route.url.match = arangodb.normalizeURL(p + "/" + route.url.match);
}
route.context = i;
-
+
routes[key].push(route);
}
}
@@ -910,16 +918,16 @@ function scanDirectory (path) {
exports.scanAppDirectory = function () {
'use strict';
-
+
var aal = getStorage();
// remove all loaded apps first
aal.removeByExample({ type: "app" });
// now re-scan, starting with system apps
- scanDirectory(module.systemAppPath());
+ scanDirectory(module.systemAppPath());
// now scan database-specific apps
- scanDirectory(module.appPath());
+ scanDirectory(module.appPath());
};
////////////////////////////////////////////////////////////////////////////////
@@ -1214,7 +1222,7 @@ exports.devSetup = function (filename) {
var root = module.devAppPath();
var m = fs.join(root, filename, "manifest.json");
-
+
if (fs.exists(m)) {
try {
var mf = JSON.parse(fs.read(m));
@@ -1262,7 +1270,7 @@ exports.devTeardown = function (filename) {
var root = module.devAppPath();
var m = fs.join(root, filename, "manifest.json");
-
+
if (fs.exists(m)) {
try {
var mf = JSON.parse(fs.read(m));
@@ -1296,7 +1304,7 @@ exports.devTeardown = function (filename) {
exports.appRoutes = function () {
'use strict';
-
+
var aal = getStorage();
return arangodb.db._executeTransaction({
@@ -1327,7 +1335,7 @@ exports.appRoutes = function () {
var r = routingAalApp(app, mount, options);
if (r === null) {
- throw new Error("Cannot compute the routing table for Foxx application '"
+ throw new Error("Cannot compute the routing table for Foxx application '"
+ app._id + "', check the log file for errors!");
}
@@ -1367,7 +1375,7 @@ exports.developmentRoutes = function () {
if (fs.exists(m)) {
try {
var mf = JSON.parse(fs.read(m));
-
+
checkManifest(m, mf);
var appId = "dev:" + mf.name + ":" + files[j];
@@ -1387,7 +1395,7 @@ exports.developmentRoutes = function () {
var r = routingAalApp(app, mount, options);
if (r === null) {
- throw new Error("Cannot compute the routing table for Foxx application '"
+ throw new Error("Cannot compute the routing table for Foxx application '"
+ app._id + "', check the log file for errors!");
}
diff --git a/js/server/modules/org/arangodb/foxx/request_context.js b/js/server/modules/org/arangodb/foxx/request_context.js
index 07d081f957..9e0bac5c50 100644
--- a/js/server/modules/org/arangodb/foxx/request_context.js
+++ b/js/server/modules/org/arangodb/foxx/request_context.js
@@ -40,14 +40,46 @@ var RequestContext,
createBodyParamBubbleWrap,
addCheck;
-createBodyParamBubbleWrap = function (handler, paramName, Proto) {
+var elementExtractFactory = function(paramName, rootElement) {
+ var extractElement;
+
+ if (rootElement) {
+ extractElement = function (req) {
+ return req.body()[paramName];
+ };
+ } else {
+ extractElement = function (req) {
+ return req.body();
+ };
+ }
+
+ return extractElement;
+};
+
+var bubbleWrapFactory = function (handler, paramName, Proto, extractElement, multiple) {
'use strict';
+ if (multiple) {
+ Proto = Proto[0];
+ }
+
return function (req, res) {
- req.parameters[paramName] = new Proto(req.body());
+ if (multiple) {
+ req.parameters[paramName] = _.map(extractElement(req), function (raw) {
+ return new Proto(raw);
+ });
+ } else {
+ req.parameters[paramName] = new Proto(extractElement(req));
+ }
handler(req, res);
};
};
+createBodyParamBubbleWrap = function (handler, paramName, Proto, rootElement) {
+ 'use strict';
+ var extractElement = elementExtractFactory(paramName, rootElement);
+ return bubbleWrapFactory(handler, paramName, Proto, extractElement, is.array(Proto));
+};
+
createErrorBubbleWrap = function (handler, errorClass, code, reason, errorHandler) {
'use strict';
if (is.notExisty(errorHandler)) {
@@ -137,14 +169,15 @@ extend(SwaggerDocs.prototype, {
/// Used for documenting and constraining the routes.
////////////////////////////////////////////////////////////////////////////////
-RequestContext = function (executionBuffer, models, route) {
+RequestContext = function (executionBuffer, models, route, rootElement) {
'use strict';
this.route = route;
this.typeToRegex = {
"int": "/[0-9]+/",
"integer": "/[0-9]+/",
- "string": "/.+/"
+ "string": "/[^/]+/"
};
+ this.rootElement = rootElement;
this.docs = new SwaggerDocs(this.route.docs, models);
this.docs.addNickname(route.docs.httpMethod, route.url.match);
@@ -249,14 +282,30 @@ extend(RequestContext.prototype, {
/// This will initialize a `Model` with the data and provide it to you via the
/// params as `paramName`.
/// For information about how to annotate your models, see the Model section.
+/// If you provide the Model in an array, the response will take multiple models
+/// instead of one.
+///
+/// If you wrap the provided model in an array, the body param is always an array
+/// and accordingly the return value of the `params` for the body call will also
+/// return an array of models.
+///
+/// The behavior of `bodyParam` changes depending on the `rootElement` option
+/// set in the manifest. If it is set to true, it is expected that the body is an
+/// object with a key of the same name as the `paramName` argument.
+/// The value of this object is either a single object or in the case of a multi
+/// element an array of objects.
////////////////////////////////////////////////////////////////////////////////
bodyParam: function (paramName, description, Proto) {
'use strict';
var handler = this.route.action.callback;
- this.docs.addBodyParam(paramName, description, Proto.toJSONSchema(paramName));
- this.route.action.callback = createBodyParamBubbleWrap(handler, paramName, Proto);
+ if (is.array(Proto)) {
+ this.docs.addBodyParam(paramName, description, Proto[0].toJSONSchema(paramName));
+ } else {
+ this.docs.addBodyParam(paramName, description, Proto.toJSONSchema(paramName));
+ }
+ this.route.action.callback = createBodyParamBubbleWrap(handler, paramName, Proto, this.rootElement);
return this;
},
diff --git a/js/server/tests/shell-foxx.js b/js/server/tests/shell-foxx.js
index af9972371c..0eacee735a 100644
--- a/js/server/tests/shell-foxx.js
+++ b/js/server/tests/shell-foxx.js
@@ -3,7 +3,9 @@ require("internal").flushModuleCache();
var jsunity = require("jsunity"),
FoxxController = require("org/arangodb/foxx").Controller,
db = require("org/arangodb").db,
+ _ = require("underscore"),
fakeContext,
+ fakeContextWithRootElement,
stub_and_mock = require("org/arangodb/stub_and_mock"),
stub = stub_and_mock.stub,
allow = stub_and_mock.allow,
@@ -13,6 +15,21 @@ fakeContext = {
prefix: "",
foxxes: [],
comments: [],
+ manifest: {
+ rootElement: false
+ },
+ clearComments: function () {},
+ comment: function () {},
+ collectionName: function () {}
+};
+
+fakeContextWithRootElement = {
+ prefix: "",
+ foxxes: [],
+ comments: [],
+ manifest: {
+ rootElement: true
+ },
clearComments: function () {},
comment: function () {},
collectionName: function () {}
@@ -283,7 +300,7 @@ function DocumentationAndConstraintsSpec () {
assertEqual(routes.length, 1);
- assertEqual(routes[0].url.constraint.foxx, "/.+/");
+ assertEqual(routes[0].url.constraint.foxx, "/[^/]+/");
assertEqual(routes[0].docs.parameters[0].paramType, "path");
assertEqual(routes[0].docs.parameters[0].name, "foxx");
assertEqual(routes[0].docs.parameters[0].description, "Kind of Foxx");
@@ -309,7 +326,7 @@ function DocumentationAndConstraintsSpec () {
assertEqual(routes.length, 1);
- assertEqual(routes[0].url.constraint.foxxParam, "/.+/");
+ assertEqual(routes[0].url.constraint.foxxParam, "/[^/]+/");
assertEqual(routes[0].docs.parameters[0].paramType, "path");
assertEqual(routes[0].docs.parameters[0].name, "foxxParam");
assertEqual(routes[0].docs.parameters[0].description, "Kind of Foxx");
@@ -362,6 +379,27 @@ function DocumentationAndConstraintsSpec () {
assertEqual(routes[0].docs.parameters[0].dataType, jsonSchema.id);
},
+ testAddBodyParamWithMultipleItems: function () {
+ var paramName = stub(),
+ description = stub(),
+ ModelPrototype = stub(),
+ jsonSchema = { id: 'a', required: [], properties: {} };
+
+ allow(ModelPrototype)
+ .toReceive("toJSONSchema")
+ .andReturn(jsonSchema);
+
+ app.get('/foxx', function () {
+ //nothing
+ }).bodyParam(paramName, description, [ModelPrototype]);
+
+ assertEqual(routes.length, 1);
+ assertEqual(routes[0].docs.parameters[0].name, paramName);
+ assertEqual(routes[0].docs.parameters[0].paramType, "body");
+ assertEqual(routes[0].docs.parameters[0].description, description);
+ assertEqual(routes[0].docs.parameters[0].dataType, jsonSchema.id);
+ },
+
testDefineBodyParamAddsJSONSchemaToModels: function () {
var paramName = stub(),
description = stub(),
@@ -406,6 +444,34 @@ function DocumentationAndConstraintsSpec () {
ModelPrototype.assertIsSatisfied();
},
+ testSetParamForBodyParamWithMultipleItems: function () {
+ var req = { parameters: {} },
+ res = {},
+ paramName = stub(),
+ description = stub(),
+ rawElement = stub(),
+ requestBody = [rawElement],
+ ModelPrototype = stub(),
+ jsonSchemaId = stub(),
+ called = false;
+
+ allow(req)
+ .toReceive("body")
+ .andReturn(requestBody);
+
+ ModelPrototype = mockConstructor(rawElement);
+ ModelPrototype.toJSONSchema = function () { return { id: jsonSchemaId }; };
+
+ app.get('/foxx', function (providedReq) {
+ called = (providedReq.parameters[paramName][0] instanceof ModelPrototype);
+ }).bodyParam(paramName, description, [ModelPrototype]);
+
+ routes[0].action.callback(req, res);
+
+ assertTrue(called);
+ ModelPrototype.assertIsSatisfied();
+ },
+
testDocumentationForErrorResponse: function () {
var CustomErrorClass = function () {};
@@ -639,36 +705,6 @@ function CommentDrivenDocumentationSpec () {
};
}
-function HelperFunctionSpec () {
- var app;
-
- return {
- setUp: function () {
- fakeContext.collectionPrefix = "fancy";
- app = new FoxxController(fakeContext);
- },
-
- testGetACollection: function () {
- db._create("fancy_pants");
-
- assertEqual(app.collection("pants"), db._collection("fancy_pants"));
- },
-
- testGetACollectionThatDoesNotExist: function () {
- var err;
- db._drop("fancy_pants");
-
- try {
- app.collection("pants");
- } catch(e) {
- err = e;
- }
-
- assertEqual(err.message, "collection with name 'fancy_pants' does not exist.");
- }
- };
-}
-
function SetupAuthorization () {
var app;
@@ -767,12 +803,79 @@ function SetupAuthorization () {
};
}
+function FoxxControllerWithRootElement () {
+ var app;
+
+ return {
+ setUp: function () {
+ app = new FoxxController(fakeContextWithRootElement);
+ routes = app.routingInfo.routes;
+ },
+
+ testBodyParamWithOneElement: function () {
+ var req = { parameters: {} },
+ res = {},
+ paramName = 'myBodyParam',
+ description = stub(),
+ rawElement = stub(),
+ requestBody = { myBodyParam: rawElement },
+ ModelPrototype = stub(),
+ jsonSchemaId = stub(),
+ called = false;
+
+ allow(req)
+ .toReceive("body")
+ .andReturn(requestBody);
+
+ ModelPrototype = mockConstructor(rawElement);
+ ModelPrototype.toJSONSchema = function () { return { id: jsonSchemaId }; };
+
+ app.get('/foxx', function (providedReq) {
+ called = (providedReq.parameters[paramName] instanceof ModelPrototype);
+ }).bodyParam(paramName, description, ModelPrototype);
+
+ routes[0].action.callback(req, res);
+
+ assertTrue(called);
+ ModelPrototype.assertIsSatisfied();
+ },
+
+ testBodyParamWithMultipleElement: function () {
+ var req = { parameters: {} },
+ res = {},
+ paramName = 'myBodyParam',
+ description = stub(),
+ rawElement = stub(),
+ requestBody = { myBodyParam: [rawElement] },
+ ModelPrototype = stub(),
+ jsonSchemaId = stub(),
+ called = false;
+
+ allow(req)
+ .toReceive("body")
+ .andReturn(requestBody);
+
+ ModelPrototype = mockConstructor(rawElement);
+ ModelPrototype.toJSONSchema = function () { return { id: jsonSchemaId }; };
+
+ app.get('/foxx', function (providedReq) {
+ called = (providedReq.parameters[paramName][0] instanceof ModelPrototype);
+ }).bodyParam(paramName, description, [ModelPrototype]);
+
+ routes[0].action.callback(req, res);
+
+ assertTrue(called);
+ ModelPrototype.assertIsSatisfied();
+ }
+ };
+}
+
jsunity.run(CreateFoxxControllerSpec);
jsunity.run(SetRoutesFoxxControllerSpec);
jsunity.run(DocumentationAndConstraintsSpec);
jsunity.run(AddMiddlewareFoxxControllerSpec);
jsunity.run(CommentDrivenDocumentationSpec);
-jsunity.run(HelperFunctionSpec);
jsunity.run(SetupAuthorization);
+jsunity.run(FoxxControllerWithRootElement);
return jsunity.done();
diff --git a/lib/BasicsC/errors.dat b/lib/BasicsC/errors.dat
index 815a7fd696..799da69125 100755
--- a/lib/BasicsC/errors.dat
+++ b/lib/BasicsC/errors.dat
@@ -129,6 +129,7 @@ ERROR_ARANGO_INDEX_CREATION_FAILED,1235,"index creation failed","Will be raised
################################################################################
ERROR_ARANGO_DATAFILE_FULL,1300,"datafile full","Will be raised when the datafile reaches its limit."
+ERROR_ARANGO_EMPTY_DATADIR,1301,"server database directory is empty","Will be raised when encoutering an empty server database directory."
################################################################################
## ArangoDB replication errors
@@ -289,6 +290,15 @@ ERROR_GRAPH_COULD_NOT_CREATE_EDGE,1907,"could not create edge","Will be raised w
ERROR_GRAPH_COULD_NOT_CHANGE_EDGE,1908,"could not change edge","Will be raised when the edge could not be changed."
ERROR_GRAPH_TOO_MANY_ITERATIONS,1909,"too many iterations","Will be raised when too many iterations are done in a graph traversal."
ERROR_GRAPH_INVALID_FILTER_RESULT,1910,"invalid filter result","Will be raised when an invalid filter result is returned in a graph traversal."
+ERROR_GRAPH_COLLECTION_MULTI_USE,1920,"multi use of edge collection in edge def","an edge collection may only be used once in one edge definition of a graph.",
+ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS,1921,"edge collection already used in edge def"," is already used by another graph in a different edge definition.",
+ERROR_GRAPH_CREATE_MISSING_NAME,1922,"missing graph name","a graph name is required to create a graph.",
+ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION,1923,"malformed edge def","the edge definition is malformed. It has to be an array of objects.",
+ERROR_GRAPH_NOT_FOUND,1924,"graph not found","a graph with this name could not be found.",
+ERROR_GRAPH_DUPLICATE,1925,"graph already exists","a graph with this name already exists.",
+ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST,1926,"collection does not exist"," does not exist.",
+ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX,1927,"not a vertex collection","the collection is not a vertex collection.",
+ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION,1928,"not in orphan collection","Vertex collection not in orphan collection of the graph.",
################################################################################
## Session errors
diff --git a/lib/BasicsC/voc-errors.c b/lib/BasicsC/voc-errors.c
index 2af20d4a8e..05645408dc 100644
--- a/lib/BasicsC/voc-errors.c
+++ b/lib/BasicsC/voc-errors.c
@@ -100,6 +100,7 @@ void TRI_InitialiseErrorMessages (void) {
REG_ERROR(ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING, "index insertion warning - attribute missing in document");
REG_ERROR(ERROR_ARANGO_INDEX_CREATION_FAILED, "index creation failed");
REG_ERROR(ERROR_ARANGO_DATAFILE_FULL, "datafile full");
+ REG_ERROR(ERROR_ARANGO_EMPTY_DATADIR, "server database directory is empty");
REG_ERROR(ERROR_REPLICATION_NO_RESPONSE, "no response");
REG_ERROR(ERROR_REPLICATION_INVALID_RESPONSE, "invalid response");
REG_ERROR(ERROR_REPLICATION_MASTER_ERROR, "master error");
@@ -205,6 +206,15 @@ void TRI_InitialiseErrorMessages (void) {
REG_ERROR(ERROR_GRAPH_COULD_NOT_CHANGE_EDGE, "could not change edge");
REG_ERROR(ERROR_GRAPH_TOO_MANY_ITERATIONS, "too many iterations");
REG_ERROR(ERROR_GRAPH_INVALID_FILTER_RESULT, "invalid filter result");
+ REG_ERROR(ERROR_GRAPH_COLLECTION_MULTI_USE, "multi use of edge collection in edge def");
+ REG_ERROR(ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS, "edge collection already used in edge def");
+ REG_ERROR(ERROR_GRAPH_CREATE_MISSING_NAME, "missing graph name");
+ REG_ERROR(ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION, "malformed edge def");
+ REG_ERROR(ERROR_GRAPH_NOT_FOUND, "graph not found");
+ REG_ERROR(ERROR_GRAPH_DUPLICATE, "graph already exists");
+ REG_ERROR(ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST, "collection does not exist");
+ REG_ERROR(ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX, "not a vertex collection");
+ REG_ERROR(ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION, "not in orphan collection");
REG_ERROR(ERROR_SESSION_UNKNOWN, "unknown session");
REG_ERROR(ERROR_SESSION_EXPIRED, "session expired");
REG_ERROR(SIMPLE_CLIENT_UNKNOWN_ERROR, "unknown client error");
diff --git a/lib/BasicsC/voc-errors.h b/lib/BasicsC/voc-errors.h
index 5a755d8494..7c15ad0b34 100644
--- a/lib/BasicsC/voc-errors.h
+++ b/lib/BasicsC/voc-errors.h
@@ -213,6 +213,8 @@ extern "C" {
/// Will be raised when an attempt to create an index has failed.
/// - 1300: @LIT{datafile full}
/// Will be raised when the datafile reaches its limit.
+/// - 1301: @LIT{server database directory is empty}
+/// Will be raised when encoutering an empty server database directory.
/// - 1400: @LIT{no response}
/// Will be raised when the replication applier does not receive any or an
/// incomplete response from the master.
@@ -485,6 +487,25 @@ extern "C" {
/// - 1910: @LIT{invalid filter result}
/// Will be raised when an invalid filter result is returned in a graph
/// traversal.
+/// - 1920: @LIT{multi use of edge collection in edge def}
+/// an edge collection may only be used once in one edge definition of a
+/// graph.
+/// - 1921: @LIT{edge collection already used in edge def}
+/// is already used by another graph in a different edge definition.
+/// - 1922: @LIT{missing graph name}
+/// a graph name is required to create a graph.
+/// - 1923: @LIT{malformed edge def}
+/// the edge definition is malformed. It has to be an array of objects.
+/// - 1924: @LIT{graph not found}
+/// a graph with this name could not be found.
+/// - 1925: @LIT{graph already exists}
+/// a graph with this name already exists.
+/// - 1926: @LIT{collection does not exist}
+/// does not exist.
+/// - 1927: @LIT{not a vertex collection}
+/// the collection is not a vertex collection.
+/// - 1928: @LIT{not in orphan collection}
+/// Vertex collection not in orphan collection of the graph.
/// - 1950: @LIT{unknown session}
/// Will be raised when an invalid/unknown session id is passed to the server.
/// - 1951: @LIT{session expired}
@@ -1452,6 +1473,16 @@ void TRI_InitialiseErrorMessages (void);
#define TRI_ERROR_ARANGO_DATAFILE_FULL (1300)
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1301: ERROR_ARANGO_EMPTY_DATADIR
+///
+/// server database directory is empty
+///
+/// Will be raised when encoutering an empty server database directory.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_ARANGO_EMPTY_DATADIR (1301)
+
////////////////////////////////////////////////////////////////////////////////
/// @brief 1400: ERROR_REPLICATION_NO_RESPONSE
///
@@ -2557,6 +2588,96 @@ void TRI_InitialiseErrorMessages (void);
#define TRI_ERROR_GRAPH_INVALID_FILTER_RESULT (1910)
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1920: ERROR_GRAPH_COLLECTION_MULTI_USE
+///
+/// multi use of edge collection in edge def
+///
+/// an edge collection may only be used once in one edge definition of a graph.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_GRAPH_COLLECTION_MULTI_USE (1920)
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1921: ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS
+///
+/// edge collection already used in edge def
+///
+/// is already used by another graph in a different edge definition.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS (1921)
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1922: ERROR_GRAPH_CREATE_MISSING_NAME
+///
+/// missing graph name
+///
+/// a graph name is required to create a graph.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_GRAPH_CREATE_MISSING_NAME (1922)
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1923: ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION
+///
+/// malformed edge def
+///
+/// the edge definition is malformed. It has to be an array of objects.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION (1923)
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1924: ERROR_GRAPH_NOT_FOUND
+///
+/// graph not found
+///
+/// a graph with this name could not be found.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_GRAPH_NOT_FOUND (1924)
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1925: ERROR_GRAPH_DUPLICATE
+///
+/// graph already exists
+///
+/// a graph with this name already exists.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_GRAPH_DUPLICATE (1925)
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1926: ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST
+///
+/// collection does not exist
+///
+/// does not exist.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST (1926)
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1927: ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX
+///
+/// not a vertex collection
+///
+/// the collection is not a vertex collection.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX (1927)
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1928: ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION
+///
+/// not in orphan collection
+///
+/// Vertex collection not in orphan collection of the graph.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION (1928)
+
////////////////////////////////////////////////////////////////////////////////
/// @brief 1950: ERROR_SESSION_UNKNOWN
///