diff --git a/Documentation/Books/Users/General-Graphs/GeneralGraphFunctions.mdpp b/Documentation/Books/Users/General-Graphs/GeneralGraphFunctions.mdpp
index 01793a6c5a..ea193d3c7b 100644
--- a/Documentation/Books/Users/General-Graphs/GeneralGraphFunctions.mdpp
+++ b/Documentation/Books/Users/General-Graphs/GeneralGraphFunctions.mdpp
@@ -26,12 +26,8 @@ There are different types of edge defintions:
!SUBSECTION Edge Definitions
-The edge definitions for a graph is an Array containing arbitrary many directed and/or undirected relations as defined below.
-The edge definitons array is initialised with the following call:
+
-```js
-> var edgeDefinitions = graph._edgeDefinitions(edgeDefinition1,......edgeDefinitionN);
-```
To add further edge definitions to the array one must call:
@@ -42,11 +38,87 @@ To add further edge definitions to the array one must call:
!SUBSUBSECTION Undirected Relation
-
+
+
+`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:
+
+
+```
+arangosh> var graph = require("org/arangodb/general-graph");
+arangosh> graph._undirectedRelationDefinition("friend", "user");
+{
+ "collection" : "friend",
+ "from" : [
+ "user"
+ ],
+ "to" : [
+ "user"
+ ]
+}
+```
+
+To define a relation between several vertex collections:
+
+
+```
+arangosh> var graph = require("org/arangodb/general-graph");
+arangosh> graph._undirectedRelationDefinition("marriage", ["female", "male"]);
+{
+ "collection" : "marriage",
+ "from" : [
+ "female",
+ "male"
+ ],
+ "to" : [
+ "female",
+ "male"
+ ]
+}
+```
+
!SUBSUBSECTION Directed Relation
-
+
+
+`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
+
+
+```
+arangosh> var graph = require("org/arangodb/general-graph");
+arangosh> graph._directedRelationDefinition("has_bought", ["Customer", "Company"], ["Groceries", "Electronics"]);
+{
+ "collection" : "has_bought",
+ "from" : [
+ "Customer",
+ "Company"
+ ],
+ "to" : [
+ "Groceries",
+ "Electronics"
+ ]
+}
+```
+
!SUBSUBSECTION Complete Example to create a graph
@@ -81,20 +153,74 @@ alternative call:
!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.
+used in an edge definition of the graph. If the graph is extended with an edge definition using one of the orphans,
+it will be removed from the orphan collection automatically.
!SUBSUBSECTION Add
-
+
+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
+
+
+```
+arangosh> var graph = require("org/arangodb/general-graph")
+arangosh> var ed1 = graph._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+arangosh> var g = graph._create("myGraph", [ed1, ed2]);
+ReferenceError: ed2 is not defined
+```
+
+
!SUBSUBSECTION Read
-
+
+Returns all vertex collections of the graph, that are not used in an edge definition.
+
+`general-graph._getOrphanCollections()`
+
+@EXAMPLES
+
+
+```
+arangosh> var graph = require("org/arangodb/general-graph")
+arangosh> var ed1 = graph._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+arangosh> var g = graph._create("myGraph", [ed1]);
+[ArangoError 1925: graph already exists]
+```
+
+
!SUBSUBSECTION Remove
-
+
+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
+
+
+```
+arangosh> var graph = require("org/arangodb/general-graph")
+arangosh> var ed1 = graph._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+arangosh> var g = graph._create("myGraph", [ed1]);
+[ArangoError 1925: graph already exists]
+```
+
+
!SUBSECTION Read a graph
@@ -126,47 +252,324 @@ dropCollections: bool - optional. *true* all collections of the graph will be de
!SUBSECTION Save
-
+
+Creates and saves a new vertex in collection *vertexCollectionName*
+
+`general-graph.vertexCollectionName.save(data)`
+
+*data*: json - data of vertex
+
+@EXAMPLES
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> g.male.save({name: "Floyd", _key: "floyd"});
+{
+ "error" : false,
+ "_id" : "male/floyd",
+ "_rev" : "91260521",
+ "_key" : "floyd"
+}
+```
+
+
!SUBSECTION 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
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> g.male.save({neym: "Jon", _key: "john"});
+{
+ "error" : false,
+ "_id" : "male/john",
+ "_rev" : "31360617",
+ "_key" : "john"
+}
+arangosh> g.male.replace("male/john", {name: "John"});
+{
+ "error" : false,
+ "_id" : "male/john",
+ "_rev" : "31557225",
+ "_key" : "john"
+}
+```
+
+
!SUBSECTION 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
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> g.female.save({name: "Lynda", _key: "linda"});
+{
+ "error" : false,
+ "_id" : "female/linda",
+ "_rev" : "79201897",
+ "_key" : "linda"
+}
+arangosh> g.female.update({name: "Linda", _key: "linda"});
+TypeError: Object # has no method 'split'
+```
+
+
!SUBSECTION 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
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> g.male.save({name: "Kermit", _key: "kermit"});
+{
+ "error" : false,
+ "_id" : "male/kermit",
+ "_rev" : "83068521",
+ "_key" : "kermit"
+}
+arangosh> db._exists("male/kermit")
+true
+arangosh> g.male.remove("male/kermit")
+true
+arangosh> db._exists("male/kermit")
+false
+```
+
+
!SECTION Edge
!SUBSECTION 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
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> g.relation.save("male/bob", "female/alice", {type: "married", _key: "bobAndAlice"});
+{
+ "error" : false,
+ "_id" : "relation/bobAndAlice",
+ "_rev" : "45909609",
+ "_key" : "bobAndAlice"
+}
+```
+
+If the collections of *from* and *to* are not defined in an edgeDefinition of the graph,
+the edge will not be stored.
+
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> g.relation.save("relation/aliceAndBob", "female/alice", {type: "married", _key: "bobAndAlice"});
+Edge is not allowed between relation/aliceAndBob and female/alice.
+```
+
!SUBSECTION 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
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> g.relation.save("female/alice", "female/diana", {typo: "nose", _key: "aliceAndDiana"});
+{
+ "error" : false,
+ "_id" : "relation/aliceAndDiana",
+ "_rev" : "27362921",
+ "_key" : "aliceAndDiana"
+}
+arangosh> g.relation.replace("relation/aliceAndDiana", {type: "knows"});
+{
+ "error" : false,
+ "_id" : "relation/aliceAndDiana",
+ "_rev" : "27559529",
+ "_key" : "aliceAndDiana"
+}
+```
+
+
!SUBSECTION 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
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> g.relation.save("female/alice", "female/diana", {type: "knows", _key: "aliceAndDiana"});
+{
+ "error" : false,
+ "_id" : "relation/aliceAndDiana",
+ "_rev" : "127108713",
+ "_key" : "aliceAndDiana"
+}
+arangosh> g.relation.update("relation/aliceAndDiana", {type: "quarrelled", _key: "aliceAndDiana"});
+{
+ "error" : false,
+ "_id" : "relation/aliceAndDiana",
+ "_rev" : "127305321",
+ "_key" : "aliceAndDiana"
+}
+```
+
+
!SUBSECTION 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
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> g.relation.save("female/alice", "female/diana", {_key: "aliceAndDiana"});
+{
+ "error" : false,
+ "_id" : "relation/aliceAndDiana",
+ "_rev" : "141657705",
+ "_key" : "aliceAndDiana"
+}
+arangosh> db._exists("relation/aliceAndDiana")
+true
+arangosh> g.relation.remove("relation/aliceAndDiana")
+true
+arangosh> db._exists("relation/aliceAndDiana")
+false
+```
+
+
!SECTION Vertices
!SUBSECTION Get vertex *from* of an edge
-
+
+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
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> g._getFromVertex("relation/aliceAndBob")
+{
+ "name" : "Alice",
+ "_id" : "female/alice",
+ "_rev" : "175670889",
+ "_key" : "alice"
+}
+```
+
+
!SUBSECTION Get vertex *to* of an edge
-
+
+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
+
+
+```
+arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
+arangosh> var g = examples.loadGraph("social");
+arangosh> g._getToVertex("relation/aliceAndBob")
+{
+ "name" : "Bob",
+ "_id" : "male/bob",
+ "_rev" : "40666729",
+ "_key" : "bob"
+}
+```
+
diff --git a/arangosh/ArangoShell/ArangoClient.cpp b/arangosh/ArangoShell/ArangoClient.cpp
index 2816fb1959..d905e057ac 100644
--- a/arangosh/ArangoShell/ArangoClient.cpp
+++ b/arangosh/ArangoShell/ArangoClient.cpp
@@ -307,6 +307,7 @@ void ArangoClient::parse (ProgramOptions& options,
int argc,
char* argv[],
string const& initFilename) {
+
// if options are invalid, exit directly
if (! options.parse(description, argc, argv)) {
LOG_FATAL_AND_EXIT("%s", options.lastError().c_str());
diff --git a/js/apps/system/aardvark/frontend/js/bootstrap/errors.js b/js/apps/system/aardvark/frontend/js/bootstrap/errors.js
index 49167af3a6..72b4eb39a6 100644
--- a/js/apps/system/aardvark/frontend/js/bootstrap/errors.js
+++ b/js/apps/system/aardvark/frontend/js/bootstrap/errors.js
@@ -216,6 +216,8 @@
"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_GRAPH_COLLECTION_USED_IN_EDGE_DEF" : { "code" : 1929, "message" : "collection used in edge def" },
+ "ERROR_GRAPH_EDGE_COLLECTION_NOT_USED" : { "code" : 1930, "message" : "edge collection not used in graph" },
"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/apps/system/aardvark/frontend/js/modules/org/arangodb/general-graph.js b/js/apps/system/aardvark/frontend/js/modules/org/arangodb/general-graph.js
index 6424440fec..43850f63ae 100644
--- 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
@@ -2033,7 +2033,8 @@ var checkIfMayBeDropped = function(colName, graphName, graphs) {
var _drop = function(graphId, dropCollections) {
- var gdb = getGraphCollection();
+ var gdb = getGraphCollection(),
+ graphs;
if (!gdb.exists(graphId)) {
var err = new ArangoError();
@@ -2050,7 +2051,7 @@ var _drop = function(graphId, dropCollections) {
var from = edgeDefinition.from;
var to = edgeDefinition.to;
var collection = edgeDefinition.collection;
- var graphs = getGraphCollection().toArray();
+ graphs = getGraphCollection().toArray();
if (checkIfMayBeDropped(collection, graph._key, graphs)) {
db._drop(collection);
}
@@ -2070,6 +2071,20 @@ var _drop = function(graphId, dropCollections) {
);
}
);
+ //drop orphans
+ graphs = getGraphCollection().toArray();
+ if (!graph.orphanCollections) {
+ graph.orphanCollections = [];
+ }
+ graph.orphanCollections.forEach(
+ function(oC) {
+ if (checkIfMayBeDropped(oC, graph._key, graphs)) {
+ try {
+ db._drop(oC);
+ } catch (e) {}
+ }
+ }
+ );
}
gdb.remove(graphId);
@@ -2482,9 +2497,10 @@ Graph.prototype._amountCommonProperties = function(vertex1Example, vertex2Exampl
////////////////////////////////////////////////////////////////////////////////
/// @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.
+/// Extends the edge definitions of a graph. If an orphan collection is used in this
+/// edge definitino, it will be removed from the orphenage. 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)`
///
@@ -2570,19 +2586,78 @@ Graph.prototype._extendEdgeDefinitions = function(edgeDefinition) {
};
+////////////////////////////////////////////////////////////////////////////////
+/// @brief internal function for editing edge definitions
+////////////////////////////////////////////////////////////////////////////////
+
+var changeEdgeDefinitionsForGraph = function(graph, edgeDefinition, newCollections, possibleOrphans, self) {
+
+ var oldCollections = [];
+ var graphCollections = [];
+ var graphObj = _graph(graph._key);
+ var eDs = graph.edgeDefinitions;
+
+ //replace edgeDefintion
+ eDs.forEach(
+ function(eD, id) {
+ if(eD.collection === edgeDefinition.collection) {
+ oldCollections = _.union(oldCollections, eD.from);
+ oldCollections = _.union(oldCollections, 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;
+ }
+ } else {
+ //collect all used collections
+ graphCollections = _.union(graphCollections, eD.from);
+ graphCollections = _.union(graphCollections, eD.to);
+ }
+ }
+ );
+
+
+ //remove used collection from orphanage
+ newCollections.forEach(
+ function(nc) {
+ if (graph._key === self.__name) {
+ if (self.__vertexCollections[nc] === undefined) {
+ self.__vertexCollections[nc] = db[nc];
+ }
+ try {
+ graphObj._removeOrphanCollection(nc);
+ } catch (e) {
+ }
+ }
+ }
+ );
+
+ //move unused collections to orphanage
+ possibleOrphans.forEach(
+ function(po) {
+ if (graphCollections.indexOf(po) === -1) {
+ delete graphObj.__vertexCollections[po];
+ graphObj._addOrphanCollection(po);
+ }
+ }
+ );
+};
////////////////////////////////////////////////////////////////////////////////
/// @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.
+/// replace the existing edge definition of the graph which has the same collection.
+/// Vertex Collections of the replaced edge definition, that are not used in the new
+/// definition will transform to an orphan. Orphans that are used in this new edge
+/// definition will be deleted from the list of orphans. Other graphs with the same edge
+/// definition will be modified, too.
///
-/// `general-graph._editEdgeDefinition(edgeDefinition, dropCollections)`
+/// `general-graph._editEdgeDefinition(edgeDefinition)`
///
/// *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.
+/// definition with the same attribute *collection*.
///
/// @EXAMPLES
///
@@ -2597,13 +2672,9 @@ Graph.prototype._extendEdgeDefinitions = function(edgeDefinition) {
/// @endDocuBlock
///
////////////////////////////////////////////////////////////////////////////////
-Graph.prototype._editEdgeDefinitions = function(edgeDefinition, dropCollections) {
- var self = this;
- var dropCandidates;
- var currentEdgeDefinition = {};
- var exOrphanCandidates = [];
- var effectedGraphs = [];
+Graph.prototype._editEdgeDefinitions = function(edgeDefinition) {
+ var self = this;
//check, if in graphs edge definition
if (this.__edgeCollections[edgeDefinition.collection] === undefined) {
@@ -2613,108 +2684,33 @@ Graph.prototype._editEdgeDefinitions = function(edgeDefinition, dropCollections)
throw err;
}
+ findOrCreateCollectionsByEdgeDefinitions([edgeDefinition]);
+
+ //evaluate collections to add to orphanage
+ var possibleOrphans = [];
+ var currentEdgeDefinition;
+ this.__edgeDefinitions.forEach(
+ function(ed) {
+ if (edgeDefinition.collection === ed.collection) {
+ currentEdgeDefinition = ed;
+ }
+ }
+ );
+
+ var currentCollections = _.union(currentEdgeDefinition.from, currentEdgeDefinition.to);
+ var newCollections = _.union(edgeDefinition.from, edgeDefinition.to);
+ currentCollections.forEach(
+ function(colName) {
+ if (newCollections.indexOf(colName) === -1) {
+ possibleOrphans.push(colName);
+ }
+ }
+ );
//change definition for ALL graphs
var graphs = 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});
- effectedGraphs.push(graph._key);
- 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) {
- exOrphanCandidates.push(vc);
- self.__vertexCollections[vc] = db[vc];
- }
- }
- );
- edgeDefinition.to.forEach(
- function(vc) {
- if (self.__vertexCollections[vc] === undefined) {
- exOrphanCandidates.push(vc);
- 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];
- }
- }
- );
-
- //orphans treatment
- effectedGraphs.forEach(
- function(gN) {
- var g;
- if (gN === self.__name) {
- g = self;
- } else {
- g = _graph(gN);
- }
- var orphans = g._getOrphanCollections();
- exOrphanCandidates.forEach(
- function(eOC) {
- if (orphans.indexOf(eOC) !== -1) {
- g._removeOrphanCollection(eOC);
- }
- }
- );
+ changeEdgeDefinitionsForGraph(graph, edgeDefinition, newCollections, possibleOrphans, self);
}
);
@@ -2725,14 +2721,12 @@ Graph.prototype._editEdgeDefinitions = function(edgeDefinition, dropCollections)
/// @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.
+/// in another edge definition of the graph, they will be moved to the orphanage.
///
-/// `general-graph._deleteEdgeDefinition(edgeCollectionName, dropCollections)`
+/// `general-graph._deleteEdgeDefinition(edgeCollectionName)`
///
/// *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
///
@@ -2741,56 +2735,49 @@ Graph.prototype._editEdgeDefinitions = function(edgeDefinition, dropCollections)
/// 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);
+/// g._deleteEdgeDefinition("myEC1");
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// @endDocuBlock
///
////////////////////////////////////////////////////////////////////////////////
-Graph.prototype._deleteEdgeDefinition = function(edgeCollection, dropCollections) {
+Graph.prototype._deleteEdgeDefinition = function(edgeCollection) {
+
+ //check, if in graphs edge definition
+ if (this.__edgeCollections[edgeCollection] === undefined) {
+ var err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.message;
+ throw err;
+ }
+
var edgeDefinitions = this.__edgeDefinitions,
- vertexCollections = [],
- definitionFound = false,
+ self = this,
+ usedVertexCollections = [],
+ possibleOrphans = [],
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);
- }
- }
- );
- }
+ index = idx;
+ possibleOrphans = edgeDefinition.from;
+ possibleOrphans = _.union(possibleOrphans, edgeDefinition.to);
+ } else {
+ usedVertexCollections = _.union(usedVertexCollections, edgeDefinition.from);
+ usedVertexCollections = _.union(usedVertexCollections, edgeDefinition.to);
}
}
);
- 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);
- }
+ this.__edgeDefinitions.splice(index, 1);
+ possibleOrphans.forEach(
+ function(po) {
+ if (usedVertexCollections.indexOf(po) === -1) {
+ self.__orphanCollections.push(po);
}
- );
-
- }
-
+ }
+ );
};
////////////////////////////////////////////////////////////////////////////////
@@ -2816,17 +2803,17 @@ Graph.prototype._deleteEdgeDefinition = function(edgeCollection, dropCollections
///
////////////////////////////////////////////////////////////////////////////////
-Graph.prototype._addOrphanCollection = function(vertexCollection, createCollection) {
+Graph.prototype._addOrphanCollection = function(orphanCollectionName, createCollection) {
//check edgeCollection
- var ec = db._collection(vertexCollection);
+ var ec = db._collection(orphanCollectionName);
var err;
if (ec === null) {
if (createCollection !== false) {
- db._create(vertexCollection);
+ db._create(orphanCollectionName);
} 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;
+ err.errorMessage = orphanCollectionName + arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message;
throw err;
}
} else if (ec.type() !== 2) {
@@ -2835,8 +2822,14 @@ Graph.prototype._addOrphanCollection = function(vertexCollection, createCollecti
err.errorMessage = arangodb.errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.message;
throw err;
}
+ if (this.__vertexCollections[orphanCollectionName] !== undefined) {
+ err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.message;
+ throw err;
+ }
- this.__orphanCollections.push(vertexCollection);
+ this.__orphanCollections.push(orphanCollectionName);
db._graphs.update(this.__name, {orphanCollections: this.__orphanCollections});
};
diff --git a/js/client/modules/org/arangodb/foxx/manager.js b/js/client/modules/org/arangodb/foxx/manager.js
index 618e388efb..2c62d4cdcd 100644
--- a/js/client/modules/org/arangodb/foxx/manager.js
+++ b/js/client/modules/org/arangodb/foxx/manager.js
@@ -378,7 +378,7 @@ function cmdUsage () {
var fm = "foxx-manager";
printf("Example usage:\n");
- printf(" %s install \n", fm);
+ printf(" %s install option1=value1\n", fm);
printf(" %s uninstall \n\n", fm);
printf("Further help:\n");
@@ -460,6 +460,43 @@ function fetchDirectoryForInstall (name) {
return exports.fetch("directory", name).app;
}
+////////////////////////////////////////////////////////////////////////////////
+/// @brief extracts command-line options
+////////////////////////////////////////////////////////////////////////////////
+
+function extractCommandLineOptions (args) {
+ 'use strict';
+
+ var options = {};
+ var nargs = [];
+ var i;
+
+ var re1 = /^([\-_a-zA-Z0-9]*)=(.*)$/;
+ var re2 = /^(0|.0|([0-9]*(\.[0-9]*)?))$/;
+
+ for (i = 0; i < args.length; ++i) {
+ var a = args[i];
+ var m = re1.exec(a);
+
+ if (m !== null) {
+ var k = m[1];
+ var v = m[2];
+
+ if (re2.test(v)) {
+ options[k] = parseFloat(v);
+ }
+ else {
+ options[k] = v;
+ }
+ }
+ else {
+ nargs.push(args[i]);
+ }
+ }
+
+ return { 'options': options, 'args': nargs };
+}
+
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
@@ -481,17 +518,37 @@ exports.run = function (args) {
var printf = arangodb.printf;
var res;
+ function extractOptions () {
+ var co = extractCommandLineOptions(args);
+
+ if (3 < co.args.length) {
+ var options = JSON.parse(co.args[3]);
+
+ if (options.hasOwnProperty("configuration")) {
+ var k;
+
+ for (k in co.options) {
+ if (co.options.hasOwnProperty(k)) {
+ options.configuration[k] = co.options[k];
+ }
+ }
+ }
+ else {
+ options.configuration = co.options;
+ }
+
+ return options;
+ }
+
+ return { configuration: co.options };
+ }
+
try {
if (type === 'fetch') {
exports.fetch(args[1], args[2], args[3]);
}
else if (type === 'mount') {
- if (3 < args.length) {
- exports.mount(args[1], args[2], JSON.parse(args[3]));
- }
- else {
- exports.mount(args[1], args[2]);
- }
+ exports.mount(args[1], args[2], extractOptions());
}
else if (type === 'rescan') {
exports.rescan();
@@ -506,16 +563,13 @@ exports.run = function (args) {
exports.unmount(args[1]);
}
else if (type === 'install') {
- if (3 < args.length) {
- res = exports.install(args[1], args[2], JSON.parse(args[3]));
- }
- else {
- res = exports.install(args[1], args[2]);
- }
+ var options = extractOptions();
+ res = exports.install(args[1], args[2], options);
printf("Application %s installed successfully at mount point %s\n",
res.appId,
res.mount);
+ printf("options used: %s", JSON.stringify(options));
}
else if (type === 'replace') {
if (3 < args.length) {
diff --git a/js/common/bootstrap/errors.js b/js/common/bootstrap/errors.js
index 49167af3a6..72b4eb39a6 100644
--- a/js/common/bootstrap/errors.js
+++ b/js/common/bootstrap/errors.js
@@ -216,6 +216,8 @@
"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_GRAPH_COLLECTION_USED_IN_EDGE_DEF" : { "code" : 1929, "message" : "collection used in edge def" },
+ "ERROR_GRAPH_EDGE_COLLECTION_NOT_USED" : { "code" : 1930, "message" : "edge collection not used in graph" },
"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/modules/org/arangodb/general-graph.js b/js/common/modules/org/arangodb/general-graph.js
index 4058ce4ac0..ba278623d5 100644
--- a/js/common/modules/org/arangodb/general-graph.js
+++ b/js/common/modules/org/arangodb/general-graph.js
@@ -2032,7 +2032,8 @@ var checkIfMayBeDropped = function(colName, graphName, graphs) {
var _drop = function(graphId, dropCollections) {
- var gdb = getGraphCollection();
+ var gdb = getGraphCollection(),
+ graphs;
if (!gdb.exists(graphId)) {
var err = new ArangoError();
@@ -2049,7 +2050,7 @@ var _drop = function(graphId, dropCollections) {
var from = edgeDefinition.from;
var to = edgeDefinition.to;
var collection = edgeDefinition.collection;
- var graphs = getGraphCollection().toArray();
+ graphs = getGraphCollection().toArray();
if (checkIfMayBeDropped(collection, graph._key, graphs)) {
db._drop(collection);
}
@@ -2069,6 +2070,20 @@ var _drop = function(graphId, dropCollections) {
);
}
);
+ //drop orphans
+ graphs = getGraphCollection().toArray();
+ if (!graph.orphanCollections) {
+ graph.orphanCollections = [];
+ }
+ graph.orphanCollections.forEach(
+ function(oC) {
+ if (checkIfMayBeDropped(oC, graph._key, graphs)) {
+ try {
+ db._drop(oC);
+ } catch (e) {}
+ }
+ }
+ );
}
gdb.remove(graphId);
@@ -2481,9 +2496,10 @@ Graph.prototype._amountCommonProperties = function(vertex1Example, vertex2Exampl
////////////////////////////////////////////////////////////////////////////////
/// @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.
+/// Extends the edge definitions of a graph. If an orphan collection is used in this
+/// edge definitino, it will be removed from the orphenage. 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)`
///
@@ -2492,10 +2508,10 @@ Graph.prototype._amountCommonProperties = function(vertex1Example, vertex2Exampl
/// @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]);
+/// var graph = require("org/arangodb/general-graph")
+/// var ed1 = graph._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var ed2 = graph._directedRelationDefinition("myEC2", ["myVC1"], ["myVC3"]);
+/// var g = graph._create("myGraph", [ed1]);
/// g._extendEdgeDefinitions(ed2);
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
@@ -2569,40 +2585,95 @@ Graph.prototype._extendEdgeDefinitions = function(edgeDefinition) {
};
+////////////////////////////////////////////////////////////////////////////////
+/// @brief internal function for editing edge definitions
+////////////////////////////////////////////////////////////////////////////////
+
+var changeEdgeDefinitionsForGraph = function(graph, edgeDefinition, newCollections, possibleOrphans, self) {
+
+ var oldCollections = [];
+ var graphCollections = [];
+ var graphObj = _graph(graph._key);
+ var eDs = graph.edgeDefinitions;
+
+ //replace edgeDefintion
+ eDs.forEach(
+ function(eD, id) {
+ if(eD.collection === edgeDefinition.collection) {
+ oldCollections = _.union(oldCollections, eD.from);
+ oldCollections = _.union(oldCollections, 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;
+ }
+ } else {
+ //collect all used collections
+ graphCollections = _.union(graphCollections, eD.from);
+ graphCollections = _.union(graphCollections, eD.to);
+ }
+ }
+ );
+
+
+ //remove used collection from orphanage
+ newCollections.forEach(
+ function(nc) {
+ if (graph._key === self.__name) {
+ if (self.__vertexCollections[nc] === undefined) {
+ self.__vertexCollections[nc] = db[nc];
+ }
+ try {
+ graphObj._removeOrphanCollection(nc);
+ } catch (e) {
+ }
+ }
+ }
+ );
+
+ //move unused collections to orphanage
+ possibleOrphans.forEach(
+ function(po) {
+ if (graphCollections.indexOf(po) === -1) {
+ delete graphObj.__vertexCollections[po];
+ graphObj._addOrphanCollection(po);
+ }
+ }
+ );
+};
////////////////////////////////////////////////////////////////////////////////
/// @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.
+/// replace the existing edge definition of the graph which has the same collection.
+/// Vertex Collections of the replaced edge definition, that are not used in the new
+/// definition will transform to an orphan. Orphans that are used in this new edge
+/// definition will be deleted from the list of orphans. Other graphs with the same edge
+/// definition will be modified, too.
///
-/// `general-graph._editEdgeDefinition(edgeDefinition, dropCollections)`
+/// `general-graph._editEdgeDefinition(edgeDefinition)`
///
/// *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.
+/// definition with the same attribute *collection*.
///
/// @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]);
+/// var graph = require("org/arangodb/general-graph")
+/// var ed1 = graph._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var ed2 = graph._directedRelationDefinition("myEC1", ["myVC2"], ["myVC3"]);
+/// var g = graph._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 = {};
- var exOrphanCandidates = [];
- var effectedGraphs = [];
+Graph.prototype._editEdgeDefinitions = function(edgeDefinition) {
+ var self = this;
//check, if in graphs edge definition
if (this.__edgeCollections[edgeDefinition.collection] === undefined) {
@@ -2612,108 +2683,33 @@ Graph.prototype._editEdgeDefinitions = function(edgeDefinition, dropCollections)
throw err;
}
+ findOrCreateCollectionsByEdgeDefinitions([edgeDefinition]);
+
+ //evaluate collections to add to orphanage
+ var possibleOrphans = [];
+ var currentEdgeDefinition;
+ this.__edgeDefinitions.forEach(
+ function(ed) {
+ if (edgeDefinition.collection === ed.collection) {
+ currentEdgeDefinition = ed;
+ }
+ }
+ );
+
+ var currentCollections = _.union(currentEdgeDefinition.from, currentEdgeDefinition.to);
+ var newCollections = _.union(edgeDefinition.from, edgeDefinition.to);
+ currentCollections.forEach(
+ function(colName) {
+ if (newCollections.indexOf(colName) === -1) {
+ possibleOrphans.push(colName);
+ }
+ }
+ );
//change definition for ALL graphs
var graphs = 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});
- effectedGraphs.push(graph._key);
- 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) {
- exOrphanCandidates.push(vc);
- self.__vertexCollections[vc] = db[vc];
- }
- }
- );
- edgeDefinition.to.forEach(
- function(vc) {
- if (self.__vertexCollections[vc] === undefined) {
- exOrphanCandidates.push(vc);
- 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];
- }
- }
- );
-
- //orphans treatment
- effectedGraphs.forEach(
- function(gN) {
- var g;
- if (gN === self.__name) {
- g = self;
- } else {
- g = _graph(gN);
- }
- var orphans = g._getOrphanCollections();
- exOrphanCandidates.forEach(
- function(eOC) {
- if (orphans.indexOf(eOC) !== -1) {
- g._removeOrphanCollection(eOC);
- }
- }
- );
+ changeEdgeDefinitionsForGraph(graph, edgeDefinition, newCollections, possibleOrphans, self);
}
);
@@ -2724,72 +2720,63 @@ Graph.prototype._editEdgeDefinitions = function(edgeDefinition, dropCollections)
/// @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.
+/// in another edge definition of the graph, they will be moved to the orphanage.
///
-/// `general-graph._deleteEdgeDefinition(edgeCollectionName, dropCollections)`
+/// `general-graph._deleteEdgeDefinition(edgeCollectionName)`
///
/// *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);
+/// var graph = require("org/arangodb/general-graph")
+/// var ed1 = graph._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var ed2 = graph._directedRelationDefinition("myEC2", ["myVC1"], ["myVC3"]);
+/// var g = graph._create("myGraph", [ed1, ed2]);
+/// g._deleteEdgeDefinition("myEC1");
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// @endDocuBlock
///
////////////////////////////////////////////////////////////////////////////////
-Graph.prototype._deleteEdgeDefinition = function(edgeCollection, dropCollections) {
+Graph.prototype._deleteEdgeDefinition = function(edgeCollection) {
+
+ //check, if in graphs edge definition
+ if (this.__edgeCollections[edgeCollection] === undefined) {
+ var err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.message;
+ throw err;
+ }
+
var edgeDefinitions = this.__edgeDefinitions,
- vertexCollections = [],
- definitionFound = false,
+ self = this,
+ usedVertexCollections = [],
+ possibleOrphans = [],
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);
- }
- }
- );
- }
+ index = idx;
+ possibleOrphans = edgeDefinition.from;
+ possibleOrphans = _.union(possibleOrphans, edgeDefinition.to);
+ } else {
+ usedVertexCollections = _.union(usedVertexCollections, edgeDefinition.from);
+ usedVertexCollections = _.union(usedVertexCollections, edgeDefinition.to);
}
}
);
- 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);
- }
+ this.__edgeDefinitions.splice(index, 1);
+ possibleOrphans.forEach(
+ function(po) {
+ if (usedVertexCollections.indexOf(po) === -1) {
+ self.__orphanCollections.push(po);
}
- );
-
- }
-
+ }
+ );
};
////////////////////////////////////////////////////////////////////////////////
@@ -2805,9 +2792,9 @@ Graph.prototype._deleteEdgeDefinition = function(edgeCollection, dropCollections
/// @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]);
+/// var graph = require("org/arangodb/general-graph")
+/// var ed1 = graph._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var g = graph._create("myGraph", [ed1]);
/// g._addOrphanCollection("myVC3", true);
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
@@ -2815,17 +2802,17 @@ Graph.prototype._deleteEdgeDefinition = function(edgeCollection, dropCollections
///
////////////////////////////////////////////////////////////////////////////////
-Graph.prototype._addOrphanCollection = function(vertexCollection, createCollection) {
+Graph.prototype._addOrphanCollection = function(orphanCollectionName, createCollection) {
//check edgeCollection
- var ec = db._collection(vertexCollection);
+ var ec = db._collection(orphanCollectionName);
var err;
if (ec === null) {
if (createCollection !== false) {
- db._create(vertexCollection);
+ db._create(orphanCollectionName);
} 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;
+ err.errorMessage = orphanCollectionName + arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message;
throw err;
}
} else if (ec.type() !== 2) {
@@ -2834,8 +2821,14 @@ Graph.prototype._addOrphanCollection = function(vertexCollection, createCollecti
err.errorMessage = arangodb.errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.message;
throw err;
}
+ if (this.__vertexCollections[orphanCollectionName] !== undefined) {
+ err = new ArangoError();
+ err.errorNum = arangodb.errors.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.code;
+ err.errorMessage = arangodb.errors.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.message;
+ throw err;
+ }
- this.__orphanCollections.push(vertexCollection);
+ this.__orphanCollections.push(orphanCollectionName);
db._graphs.update(this.__name, {orphanCollections: this.__orphanCollections});
};
@@ -2849,9 +2842,9 @@ Graph.prototype._addOrphanCollection = function(vertexCollection, createCollecti
/// @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]);
+/// var graph = require("org/arangodb/general-graph")
+/// var ed1 = graph._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var g = graph._create("myGraph", [ed1]);
/// g._addOrphanCollection("myVC3", true);
/// g._getOrphanCollections();
/// @END_EXAMPLE_ARANGOSH_OUTPUT
@@ -2878,9 +2871,9 @@ Graph.prototype._getOrphanCollections = function() {
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__removeOrphanCollections}
-/// var examples = require("org/arangodb/graph-examples/example-graph.js");
-/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
-/// var g = examples._create("myGraph", [ed1]);
+/// var graph = require("org/arangodb/general-graph")
+/// var ed1 = graph._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
+/// var g = graph._create("myGraph", [ed1]);
/// g._addOrphanCollection("myVC3", true);
/// g._addOrphanCollection("myVC4", true);
/// g._getOrphanCollections();
diff --git a/js/common/tests/shell-general-graph.js b/js/common/tests/shell-general-graph.js
index 86085c7873..9712a787a0 100644
--- a/js/common/tests/shell-general-graph.js
+++ b/js/common/tests/shell-general-graph.js
@@ -60,8 +60,52 @@ function GeneralGraphCreationSuite() {
)
);
+ var gN1 = "UnitTestEdgeDefDeleteGraph1",
+ gN2 = "UnitTestEdgeDefDeleteGraph2",
+ ec1 = "UnitTestEdgeDefDeleteEdgeCol1",
+ ec2 = "UnitTestEdgeDefDeleteEdgeCol2",
+ ec3 = "UnitTestEdgeDefDeleteEdgeCol3",
+ vc1 = "UnitTestEdgeDefDeleteVertexCol1",
+ vc2 = "UnitTestEdgeDefDeleteVertexCol2",
+ vc3 = "UnitTestEdgeDefDeleteVertexCol3",
+ vc4 = "UnitTestEdgeDefDeleteVertexCol4",
+ vc5 = "UnitTestEdgeDefDeleteVertexCol5",
+ vc6 = "UnitTestEdgeDefDeleteVertexCol6";
+
return {
+ setUp: function() {
+ try {
+ graph._drop(gN1);
+ } catch(ignore) {
+ }
+ try {
+ graph._drop(gN2);
+ } catch(ignore) {
+ }
+
+ },
+
+ tearDown: function() {
+ db._drop(ec1);
+ db._drop(ec2);
+ db._drop(ec3);
+ db._drop(vc1);
+ db._drop(vc2);
+ db._drop(vc3);
+ db._drop(vc4);
+ db._drop(vc5);
+ db._drop(vc6);
+ try {
+ graph._drop(gN1);
+ } catch(ignore) {
+ }
+ try {
+ graph._drop(gN2);
+ } catch(ignore) {
+ }
+ },
+
////////////////////////////////////////////////////////////////////////////////
/// @brief test: Graph Creation
////////////////////////////////////////////////////////////////////////////////
@@ -413,58 +457,39 @@ function GeneralGraphCreationSuite() {
},
- test_deleteEdgeDefinitionFromExistingGraph: function() {
- var gN1 = "UnitTestEdgeDefDeleteGraph1",
- gN2 = "UnitTestEdgeDefDeleteGraph2",
- ec1 = "UnitTestEdgeDefDeleteEdgeCol1",
- ec2 = "UnitTestEdgeDefDeleteEdgeCol2",
- ec3 = "UnitTestEdgeDefDeleteEdgeCol3",
- vc1 = "UnitTestEdgeDefDeleteVertexCol1",
- vc2 = "UnitTestEdgeDefDeleteVertexCol2",
- vc3 = "UnitTestEdgeDefDeleteVertexCol3",
- vc4 = "UnitTestEdgeDefDeleteVertexCol4",
- vc5 = "UnitTestEdgeDefDeleteVertexCol5";
- try {
- graph._drop(gN1);
- } catch(ignore) {
- }
- try {
- graph._drop(gN2);
- } catch(ignore) {
- }
-
+ test_deleteEdgeDefinitionFromExistingGraph1: function() {
var dr1 = graph._directedRelationDefinition(ec1, [vc1], [vc1, vc2]),
- dr2 = graph._directedRelationDefinition(ec2, [vc3], [vc4, vc5]),
- dr3 = graph._directedRelationDefinition(ec3, [vc4], [vc5]),
- g1 = graph._create(gN1, [dr1, dr2, dr3]),
- g2 = graph._create(gN2, [dr3]);
-
- g1._deleteEdgeDefinition(ec1, false);
- assertEqual([dr2, dr3], g1.__edgeDefinitions);
-
- g1._deleteEdgeDefinition(ec2, true);
- assertEqual([dr3], g1.__edgeDefinitions);
- assertTrue(db._collection(vc3) === null);
- assertFalse(db._collection(vc4) === null);
- assertFalse(db._collection(vc5) === null);
+ g1 = graph._create(gN1, [dr1]);
try {
- graph._drop(gN1);
- } catch(ignore) {
- }
- try {
- graph._drop(gN2);
- } catch(ignore) {
+ g1._deleteEdgeDefinition(ec1);
+ } catch (e) {
+ assertEqual(
+ e.errorMessage,
+ arangodb.errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.message
+ );
}
},
+ test_deleteEdgeDefinitionFromExistingGraph2: function() {
+
+ var dr1 = graph._directedRelationDefinition(ec1, [vc1], [vc1, vc2]),
+ dr2 = graph._directedRelationDefinition(ec2, [vc3], [vc4, vc5]),
+ dr3 = graph._directedRelationDefinition(ec3, [vc4], [vc5]),
+ g1 = graph._create(gN1, [dr1, dr2, dr3]);
+
+ assertEqual([dr1, dr2, dr3], g1.__edgeDefinitions);
+ g1._deleteEdgeDefinition(ec1);
+ assertEqual([dr2, dr3], g1.__edgeDefinitions);
+ assertEqual([vc1, vc2], g1._getOrphanCollections());
+
+ g1._deleteEdgeDefinition(ec2);
+ assertEqual([dr3], g1.__edgeDefinitions);
+ assertEqual([vc1, vc2, vc3], g1._getOrphanCollections());
+ },
+
test_extendEdgeDefinitionFromExistingGraph1: function() {
- var gN1 = "UnitTestEdgeDefExtend1Graph1",
- ec1 = "UnitTestEdgeDefExtend1EdgeCol1",
- vc1 = "UnitTestEdgeDefExtend1VertexCol1",
- vc2 = "UnitTestEdgeDefExtend1VertexCol2",
- vc3 = "UnitTestEdgeDefExtend1VertexCol3";
try {
graph._drop(gN1);
@@ -492,24 +517,6 @@ function GeneralGraphCreationSuite() {
},
test_extendEdgeDefinitionFromExistingGraph2: function() {
- var gN1 = "UnitTestEdgeDefExtend2Graph1",
- gN2 = "UnitTestEdgeDefExtend2Graph2",
- ec1 = "UnitTestEdgeDefExtend2EdgeCol1",
- ec2 = "UnitTestEdgeDefExtend2EdgeCol2",
- ec3 = "UnitTestEdgeDefExtend2EdgeCol3",
- vc1 = "UnitTestEdgeDefExtend2VertexCol1",
- vc2 = "UnitTestEdgeDefExtend2VertexCol2",
- vc3 = "UnitTestEdgeDefExtend2VertexCol3",
- vc4 = "UnitTestEdgeDefExtend2VertexCol4",
- vc5 = "UnitTestEdgeDefExtend2VertexCol5";
- try {
- graph._drop(gN1);
- } catch(ignore) {
- }
- try {
- graph._drop(gN2);
- } catch(ignore) {
- }
var dr1 = graph._directedRelationDefinition(ec1, [vc1], [vc1, vc2]),
dr2 = graph._directedRelationDefinition(ec2, [vc3], [vc4, vc5]),
@@ -538,16 +545,6 @@ function GeneralGraphCreationSuite() {
},
test_extendEdgeDefinitionFromExistingGraph3: function() {
- var gN1 = "UnitTestEdgeDefExtend3Graph1",
- gN2 = "UnitTestEdgeDefExtend3Graph2",
- ec1 = "UnitTestEdgeDefExtend3EdgeCol1",
- ec2 = "UnitTestEdgeDefExtend3EdgeCol2",
- ec3 = "UnitTestEdgeDefExtend3EdgeCol3",
- vc1 = "UnitTestEdgeDefExtend3VertexCol1",
- vc2 = "UnitTestEdgeDefExtend3VertexCol2",
- vc3 = "UnitTestEdgeDefExtend3VertexCol3",
- vc4 = "UnitTestEdgeDefExtend3VertexCol4",
- vc5 = "UnitTestEdgeDefExtend3VertexCol5";
try {
graph._drop(gN1);
} catch(ignore) {
@@ -572,32 +569,9 @@ function GeneralGraphCreationSuite() {
g1._extendEdgeDefinitions(dr3);
assertEqual([dr1, dr2, dr3], g1.__edgeDefinitions);
-
- try {
- graph._drop(gN1);
- } catch(ignore) {
- }
- try {
- graph._drop(gN2);
- } catch(ignore) {
- }
-
},
test_editEdgeDefinitionFromExistingGraph1: function() {
- var gN1 = "UnitTestEdgeDefEdit1Graph1",
- ec1 = "UnitTestEdgeDefEdit1EdgeCol1",
- ec2 = "UnitTestEdgeDefEdit1EdgeCol2",
- vc1 = "UnitTestEdgeDefEdit1VertexCol1",
- vc2 = "UnitTestEdgeDefEdit1VertexCol2",
- vc3 = "UnitTestEdgeDefEdit1VertexCol3",
- vc4 = "UnitTestEdgeDefEdit1VertexCol4",
- vc5 = "UnitTestEdgeDefEdit1VertexCol5";
- try {
- graph._drop(gN1);
- } catch(ignore) {
- }
-
var dr1 = graph._directedRelationDefinition(ec1, [vc1], [vc1, vc2]),
dr2 = graph._directedRelationDefinition(ec2, [vc3], [vc4, vc5]),
g1 = graph._create(gN1, [dr1]);
@@ -607,77 +581,35 @@ function GeneralGraphCreationSuite() {
} catch (e) {
assertEqual(
e.errorMessage,
- arangodb.errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED
+ arangodb.errors.ERROR_GRAPH_EDGE_COLLECTION_NOT_USED.message
);
}
- try {
- graph._drop(gN1);
- } catch(ignore) {
- }
-
},
test_editEdgeDefinitionFromExistingGraph2: function() {
- var gN1 = "UnitTestEdgeDefEdit2Graph1",
- gN2 = "UnitTestEdgeDefEdit2Graph2",
- ec1 = "UnitTestEdgeDefEdit2EdgeCol1",
- vc1 = "UnitTestEdgeDefEdit2VertexCol1",
- vc2 = "UnitTestEdgeDefEdit2VertexCol2",
- vc3 = "UnitTestEdgeDefEdit2VertexCol3",
- vc4 = "UnitTestEdgeDefEdit2VertexCol4",
- vc5 = "UnitTestEdgeDefEdit2VertexCol5";
- try {
- graph._drop(gN1);
- } catch(ignore) {
- }
- try {
- graph._drop(gN2);
- } catch(ignore) {
- }
- var dr1 = graph._directedRelationDefinition(ec1, [vc1], [vc1, vc2]),
- dr2 = graph._directedRelationDefinition(ec1, [vc3], [vc4, vc5]),
- g1 = graph._create(gN1, [dr1]),
+ var dr1 = graph._directedRelationDefinition(ec1, [vc1, vc2], [vc3, vc4]),
+ dr2 = graph._directedRelationDefinition(ec2, [vc1], [vc4]),
+ dr3 = graph._directedRelationDefinition(ec1, [vc5], [vc5]),
+ g1 = graph._create(gN1, [dr1, dr2]),
g2 = graph._create(gN2, [dr1]);
- g1._editEdgeDefinitions(dr2, true);
- assertEqual([dr2], g1.__edgeDefinitions);
- assertEqual([dr2], g2.__edgeDefinitions);
- assertTrue(db._collection(vc1) === null);
- assertTrue(db._collection(vc2) === null);
-
- try {
- graph._drop(gN1);
- } catch(ignore) {
- }
- try {
- graph._drop(gN2);
- } catch(ignore) {
- }
+ g1._editEdgeDefinitions(dr3);
+ assertEqual([dr3, dr2], g1.__edgeDefinitions);
+ assertEqual([dr3], g2.__edgeDefinitions);
+ g1 = graph._graph(gN1);
+ g2 = graph._graph(gN2);
+ assertTrue(g1._getOrphanCollections().indexOf(vc2) !== -1);
+ assertTrue(g1._getOrphanCollections().indexOf(vc3) !== -1);
+ assertTrue(g2._getOrphanCollections().indexOf(vc1) !== -1);
+ assertTrue(g2._getOrphanCollections().indexOf(vc2) !== -1);
+ assertTrue(g2._getOrphanCollections().indexOf(vc3) !== -1);
+ assertTrue(g2._getOrphanCollections().indexOf(vc4) !== -1);
},
test_editEdgeDefinitionFromExistingGraph3: function() {
- var prefix = "UnitTestEdgeDefEdit3",
- gN1 = prefix + "Graph1",
- gN2 = prefix + "Graph2",
- ec1 = prefix + "EdgeCol1",
- ec2 = prefix + "EdgeCol2",
- vc1 = prefix + "VertexCol1",
- vc2 = prefix + "VertexCol2",
- vc3 = prefix + "VertexCol3",
- vc4 = prefix + "VertexCol4",
- vc5 = prefix + "VertexCol5",
- vc6 = prefix + "VertexCol6";
- try {
- graph._drop(gN1);
- } catch(ignore) {
- }
- try {
- graph._drop(gN2);
- } catch(ignore) {
- }
var dr1 = graph._directedRelationDefinition(ec1, [vc1], [vc1, vc2]),
dr2 = graph._directedRelationDefinition(ec1, [vc3], [vc4, vc5]),
@@ -689,13 +621,15 @@ function GeneralGraphCreationSuite() {
g2._addOrphanCollection(vc5);
g2._addOrphanCollection(vc6);
g1._editEdgeDefinitions(dr2, true);
+
assertEqual([dr2, dr3], g1.__edgeDefinitions);
assertEqual([dr2], g2.__edgeDefinitions);
- assertTrue(db._collection(vc1) === null);
- assertFalse(db._collection(vc2) === null);
- assertEqual([], g1._getOrphanCollections());
+ g1 = graph._graph(gN1);
g2 = graph._graph(gN2);
- assertEqual([vc6], g2._getOrphanCollections());
+ assertEqual([vc1], g1._getOrphanCollections());
+ assertTrue(g2._getOrphanCollections().indexOf(vc1) !== -1);
+ assertTrue(g2._getOrphanCollections().indexOf(vc2) !== -1);
+ assertTrue(g2._getOrphanCollections().indexOf(vc6) !== -1);
try {
graph._drop(gN1);
@@ -2562,8 +2496,8 @@ function OrphanCollectionSuite() {
},
test_addOrphanCollection1: function() {
- g1._addOrphanCollection(vC1, false);
- assertEqual(g1._getOrphanCollections(), [vC1]);
+ g1._addOrphanCollection(vC5, true);
+ assertEqual(g1._getOrphanCollections(), [vC5]);
},
test_addOrphanCollection2: function() {
@@ -2588,6 +2522,15 @@ function OrphanCollectionSuite() {
assertEqual(g1._getOrphanCollections(), []);
},
+ test_addOrphanCollection4: function() {
+ try {
+ g1._addOrphanCollection(vC1);
+ } catch (e) {
+ assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.code);
+ assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF.message);
+ }
+ },
+
test_removeOrphanCollection1: function() {
var name = "completelyNonsenseNameForACollectionBLUBBBBB"
try {
diff --git a/js/server/modules/org/arangodb/ahuacatl.js b/js/server/modules/org/arangodb/ahuacatl.js
index 043d2d2a39..9fcd2dc169 100644
--- a/js/server/modules/org/arangodb/ahuacatl.js
+++ b/js/server/modules/org/arangodb/ahuacatl.js
@@ -4437,13 +4437,15 @@ function TRAVERSAL_FUNC (func,
maxIterations: params.maxIterations,
uniqueness: params.uniqueness,
expander: direction,
+ direction: direction,
strategy: params.strategy,
order: params.order,
itemOrder: params.itemOrder,
startVertex : startVertex,
endVertex : endVertex,
weight : params.weight,
- defaultWeight : params.defaultWeight
+ defaultWeight : params.defaultWeight,
+ prefill : params.prefill
};
@@ -4643,18 +4645,6 @@ function DETERMINE_WEIGHT (edge, weight, defaultWeight) {
return Infinity;
}
-////////////////////////////////////////////////////////////////////////////////
-/// @brief visitor callback function for traversal
-////////////////////////////////////////////////////////////////////////////////
-
-function TRAVERSAL_SHORTEST_PATH_VISITOR (config, result, vertex, path) {
- "use strict";
-
- if (config.endVertex && config.endVertex === vertex._id) {
- result.push(CLONE({ vertex: vertex, path: path , startVertex : config.startVertex}));
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
/// @brief visitor callback function for traversal
@@ -4664,18 +4654,19 @@ function TRAVERSAL_DISTANCE_VISITOR (config, result, vertex, path) {
"use strict";
if (config.endVertex && config.endVertex === vertex._id) {
+ var subPaths = [];
var dist = 0;
- if (config.weight) {
- path.edges.forEach(function (e) {
+ path.edges.forEach(function (e) {
+ if (config.weight) {
if (typeof e[config.weight] === "number") {
dist = dist + e[config.weight];
} else if (config.defaultWeight) {
dist = dist + config.defaultWeight;
}
- });
- } else {
- dist = path.edges.length;
- }
+ } else {
+ dist++;
+ }
+ });
result.push(
CLONE({ vertex: vertex, distance: dist , path: path , startVertex : config.startVertex})
);
@@ -4683,6 +4674,62 @@ function TRAVERSAL_DISTANCE_VISITOR (config, result, vertex, path) {
}
+////////////////////////////////////////////////////////////////////////////////
+/// @brief visitor callback function for traversal
+////////////////////////////////////////////////////////////////////////////////
+
+function TRAVERSAL_DIJSKTRA_VISITOR (config, result, vertex, path) {
+ "use strict";
+ if (config.endVertex && config.endVertex === vertex._id) {
+ path.vertices.forEach(function (from) {
+ path.vertices.forEach(function (to) {
+ if (config.prefill.indexOf(JSON.stringify({ from : TO_ID(from), to : TO_ID(to)})) !== -1) {
+ return;
+ }
+ var positionFrom = path.vertices.indexOf(from);
+ var positionTo = path.vertices.indexOf(to);
+ if (positionFrom > positionTo && config.direction !== 'any') {
+ return;
+ }
+ var startVertex = from._id;
+ var vertex = to;
+
+ var distance = 0;
+ var pathNew = {vertices : [from], edges : []};
+ while (positionFrom !== positionTo) {
+ var edgePosition;
+ if (positionFrom > positionTo) {
+ edgePosition = positionFrom-1;
+ } else {
+ edgePosition = positionFrom;
+ }
+ if (positionFrom > positionTo) {
+ positionFrom = positionFrom -1;
+ } else {
+ positionFrom ++;
+ }
+ pathNew.vertices.push(path.vertices[positionFrom]);
+ pathNew.edges.push(path.edges[edgePosition]);
+ if (config.weight) {
+ if (path.edges[edgePosition][config.weight] &&
+ typeof path.edges[edgePosition][config.weight] === "number") {
+ distance = distance + path.edges[edgePosition][config.weight];
+ } else if (config.defaultWeight) {
+ distance = distance + config.defaultWeight;
+ }
+ } else {
+ distance++;
+ }
+ }
+ result.push(
+ CLONE({ vertex: vertex, distance: distance , path: pathNew , startVertex : startVertex})
+ );
+ });
+ });
+ }
+}
+
+
////////////////////////////////////////////////////////////////////////////////
/// @brief helper function to determine parameters for SHORTEST_PATH and
@@ -4920,6 +4967,8 @@ function MERGE_EXAMPLES_WITH_EDGES (examples, edges) {
return result;
}
+
+
////////////////////////////////////////////////////////////////////////////////
/// @brief calculate shortest paths by dijkstra
////////////////////////////////////////////////////////////////////////////////
@@ -4931,17 +4980,29 @@ function CALCULATE_SHORTEST_PATHES_WITH_DIJKSTRA (graphName, graphData, options)
params.weight = options.weight;
params.defaultWeight = options.defaultWeight;
params = SHORTEST_PATH_PARAMS(params);
- params.visitor = TRAVERSAL_DISTANCE_VISITOR;
+ params.visitor = TRAVERSAL_DIJSKTRA_VISITOR;
var result = [];
+
+ var calculated = {};
graphData.fromVertices.forEach(function (v) {
graphData.toVertices.forEach(function (t) {
+ if (calculated[JSON.stringify({ from : TO_ID(v), to : TO_ID(t)})]) {
+ result.push(calculated[JSON.stringify({ from : TO_ID(v), to : TO_ID(t)})]);
+ return;
+ }
+ params.prefill = Object.keys(calculated);
var e = TRAVERSAL_FUNC("GENERAL_GRAPH_SHORTEST_PATH",
factory,
TO_ID(v),
TO_ID(t),
options.direction,
params);
- result = result.concat(e);
+ e.forEach(function (f) {
+ if (TO_ID(v) === f.startVertex && TO_ID(t) === f.vertex._id) {
+ result.push(f);
+ }
+ calculated[JSON.stringify({ from : f.startVertex, to : f.vertex._id})] = f;
+ });
});
});
result.forEach(function (r) {
diff --git a/js/server/modules/org/arangodb/foxx/manager.js b/js/server/modules/org/arangodb/foxx/manager.js
index 75a3172d47..57e79bede4 100644
--- a/js/server/modules/org/arangodb/foxx/manager.js
+++ b/js/server/modules/org/arangodb/foxx/manager.js
@@ -88,6 +88,7 @@ function getStorage () {
////////////////////////////////////////////////////////////////////////////////
/// @brief check a manifest for completeness
+///
/// this implements issue #590: Manifest Lint
////////////////////////////////////////////////////////////////////////////////
@@ -120,14 +121,15 @@ function checkManifest (filename, mf) {
var expected = {
"assets": [ false, "object" ],
"author": [ false, "string" ],
+ "configuration": [ false, "object" ],
"contributors": [ false, "array" ],
"controllers": [ false, "object" ],
"defaultDocument": [ false, "string" ],
"description": [ true, "string" ],
"engines": [ false, "object" ],
"files": [ false, "object" ],
- "keywords": [ false, "array" ],
"isSystem": [ false, "boolean" ],
+ "keywords": [ false, "array" ],
"lib": [ false, "string" ],
"license": [ false, "string" ],
"name": [ true, "string" ],
@@ -363,9 +365,9 @@ function buildFileAsset (app, path, basePath, asset) {
var content = buildAssetContent(app, asset.files, basePath);
var type;
- // -----------------------------------------------------------------------------
+ // .............................................................................
// content-type detection
- // -----------------------------------------------------------------------------
+ // .............................................................................
// contentType explicitly specified for asset
if (asset.hasOwnProperty("contentType") && asset.contentType !== '') {
@@ -388,9 +390,9 @@ function buildFileAsset (app, path, basePath, asset) {
type = arangodb.guessContentType("");
}
- // -----------------------------------------------------------------------------
+ // .............................................................................
// return content
- // -----------------------------------------------------------------------------
+ // .............................................................................
return { contentType: type, body: content };
}
@@ -528,6 +530,7 @@ function executeAppScript (app, name, mount, prefix) {
appContext.mount = mount;
appContext.collectionPrefix = prefix;
appContext.options = app._options;
+ appContext.configuration = app._options.configuration;
appContext.basePath = fs.join(root, app._path);
appContext.isDevelopment = devel;
@@ -747,6 +750,7 @@ function routingAalApp (app, mount, options) {
appContextTempl.mount = mount; // global mount
appContextTempl.options = options;
+ appContextTempl.configuration = app._options.configuration;
appContextTempl.collectionPrefix = prefix; // collection prefix
appContextTempl.basePath = fs.join(root, app._path);
@@ -908,6 +912,68 @@ function scanDirectory (path) {
}
}
+////////////////////////////////////////////////////////////////////////////////
+/// @brief create configuration
+////////////////////////////////////////////////////////////////////////////////
+
+function checkConfiguration (app, options) {
+ 'use strict';
+
+ if (options === undefined || options === null) {
+ options = {};
+ }
+
+ if (! options.hasOwnProperty("configuration")) {
+ options.configuration = {};
+ }
+
+ if (! app._manifest.hasOwnProperty("configuration")) {
+ return options;
+ }
+
+ var configuration = options.configuration;
+ var expected = app._manifest.configuration;
+ var att;
+
+ for (att in expected) {
+ if (expected.hasOwnProperty(att)) {
+ if (configuration.hasOwnProperty(att)) {
+ var value = configuration[att];
+ var expectedType = expected[att].type;
+ var actualType = Array.isArray(value) ? "array" : typeof(value);
+
+ if (actualType !== expectedType) {
+ throw new Error(
+ "configuration for '" + app._manifest.name + "' uses "
+ + "an invalid data type (" + actualType + ") "
+ + "for " + expectedType + " attribute '" + att + "'");
+ }
+ }
+ else if (expected[att].hasOwnProperty("default")) {
+ configuration[att] = expected[att]["default"];
+ }
+ else {
+ throw new Error(
+ "configuration for '" + app._manifest.name + "' is "
+ + "missing a value for attribute '" + att + "'");
+ }
+ }
+ }
+
+ // additionally check if there are superfluous attributes in the manifest
+ for (att in configuration) {
+ if (configuration.hasOwnProperty(att)) {
+ if (! expected.hasOwnProperty(att)) {
+ console.warn("configuration for '%s' contains an unknown attribute '%s'",
+ app._manifest.name,
+ att);
+ }
+ }
+ }
+
+ return options;
+}
+
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
@@ -950,6 +1016,7 @@ exports.rescan = function () {
/// * options:
/// collectionPrefix: overwrites the default prefix
/// reload: reload the routing info (default: true)
+/// configuration: configuration options
///
/// Output:
/// * appId: the application identifier (must be mounted)
@@ -983,7 +1050,7 @@ exports.mount = function (appId, mount, options) {
// install the application
// .............................................................................
- options = options || { };
+ options = checkConfiguration(app, options);
var doc;
diff --git a/js/server/tests/ahuacatl-general-graph.js b/js/server/tests/ahuacatl-general-graph.js
index 1fb7acd6bc..e9a329aebd 100644
--- a/js/server/tests/ahuacatl-general-graph.js
+++ b/js/server/tests/ahuacatl-general-graph.js
@@ -1475,6 +1475,16 @@ function ahuacatlQueryGeneralTraversalTestSuite() {
assertEqual(actual[0]["UnitTests_Leipziger/Gerda"], 1);
+ actual = getQueryResults("RETURN GRAPH_ECCENTRICITY('werKenntWen')");
+ assertEqual(actual[0]["UnitTests_Berliner/Anton"].toFixed(1), 0.6);
+ assertEqual(actual[0]["UnitTests_Berliner/Berta"].toFixed(2), 0.75);
+ assertEqual(actual[0]["UnitTests_Frankfurter/Emil"].toFixed(2), 0.75);
+ assertEqual(actual[0]["UnitTests_Frankfurter/Fritz"].toFixed(1), 0.6);
+ assertEqual(actual[0]["UnitTests_Hamburger/Caesar"].toFixed(1), 0.6);
+ assertEqual(actual[0]["UnitTests_Hamburger/Dieter"], 1);
+ assertEqual(actual[0]["UnitTests_Leipziger/Gerda"], 1);
+
+
actual = getQueryResults("RETURN GRAPH_ECCENTRICITY('werKenntWen', {algorithm : 'dijkstra', direction : 'inbound'})");
assertEqual(actual[0]["UnitTests_Berliner/Anton"], 1);
assertEqual(actual[0]["UnitTests_Berliner/Berta"], 1);
diff --git a/lib/BasicsC/errors.dat b/lib/BasicsC/errors.dat
index e502e42237..5b1b1574eb 100755
--- a/lib/BasicsC/errors.dat
+++ b/lib/BasicsC/errors.dat
@@ -296,6 +296,8 @@ ERROR_GRAPH_DUPLICATE,1925,"graph already exists","a graph with this name alread
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.",
+ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF,1929,"collection used in edge def","The collection is already used in an edge definition of the graph.",
+ERROR_GRAPH_EDGE_COLLECTION_NOT_USED,1930,"edge collection not used in graph","The edge collection is not used in any edge definition of the graph.",
################################################################################
## Session errors
diff --git a/lib/BasicsC/voc-errors.c b/lib/BasicsC/voc-errors.c
index 87c251f84f..4e7d2df694 100644
--- a/lib/BasicsC/voc-errors.c
+++ b/lib/BasicsC/voc-errors.c
@@ -212,6 +212,8 @@ void TRI_InitialiseErrorMessages (void) {
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_GRAPH_COLLECTION_USED_IN_EDGE_DEF, "collection used in edge def");
+ REG_ERROR(ERROR_GRAPH_EDGE_COLLECTION_NOT_USED, "edge collection not used in graph");
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 61e6534c41..55106de472 100644
--- a/lib/BasicsC/voc-errors.h
+++ b/lib/BasicsC/voc-errors.h
@@ -498,6 +498,10 @@ extern "C" {
/// the collection is not a vertex collection.
/// - 1928: @LIT{not in orphan collection}
/// Vertex collection not in orphan collection of the graph.
+/// - 1929: @LIT{collection used in edge def}
+/// The collection is already used in an edge definition of the graph.
+/// - 1930: @LIT{edge collection not used in graph}
+/// The edge collection is not used in any edge definition 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}
@@ -2638,6 +2642,26 @@ void TRI_InitialiseErrorMessages (void);
#define TRI_ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION (1928)
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1929: ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF
+///
+/// collection used in edge def
+///
+/// The collection is already used in an edge definition of the graph.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_GRAPH_COLLECTION_USED_IN_EDGE_DEF (1929)
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief 1930: ERROR_GRAPH_EDGE_COLLECTION_NOT_USED
+///
+/// edge collection not used in graph
+///
+/// The edge collection is not used in any edge definition of the graph.
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_ERROR_GRAPH_EDGE_COLLECTION_NOT_USED (1930)
+
////////////////////////////////////////////////////////////////////////////////
/// @brief 1950: ERROR_SESSION_UNKNOWN
///