1
0
Fork 0
arangodb/js/common/modules/@arangodb/graph-common.js

733 lines
22 KiB
JavaScript

/*jshint strict: false */
////////////////////////////////////////////////////////////////////////////////
/// @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 is = require("@arangodb/is"),
propertyKeys = require("@arangodb/util").propertyKeys,
shallowCopy = require("@arangodb/util").shallowCopy,
Edge,
Graph,
Vertex,
GraphArray,
Iterator;
Iterator = function (wrapper, cursor, stringRepresentation) {
this.next = function next() {
if (cursor.hasNext()) {
return wrapper(cursor.next());
}
return undefined;
};
this.hasNext = function hasNext() {
return cursor.hasNext();
};
this._PRINT = function (context) {
context.output += stringRepresentation;
};
};
////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a graph arrays
////////////////////////////////////////////////////////////////////////////////
GraphArray = function (len) {
if (len !== undefined) {
this.length = len;
}
};
GraphArray.prototype = new Array(0);
////////////////////////////////////////////////////////////////////////////////
/// @brief map
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.map = function (fun, thisp) {
var len = this.length;
var i;
if (typeof fun !== "function") {
throw new TypeError();
}
var res = new GraphArray(len);
for (i = 0; i < len; i++) {
if (this.hasOwnProperty(i)) {
res[i] = fun.call(thisp, this[i], i, this);
}
}
return res;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief get the in vertices
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.getInVertex = function () {
return this.map(function(a) {return a.getInVertex();});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief get the out vertices
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.getOutVertex = function () {
return this.map(function(a) {return a.getOutVertex();});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief get the peer vertices
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.getPeerVertex = function (vertex) {
return this.map(function(a) {return a.getPeerVertex(vertex);});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief sets the property
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.setProperty = function (name, value) {
return this.map(function(a) {return a.setProperty(name, value);});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief get the edges
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.edges = function () {
return this.map(function(a) {return a.edges();});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief get outbound edges
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.outbound = function () {
return this.map(function(a) {return a.outbound();});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief get inbound edges
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.inbound = function () {
return this.map(function(a) {return a.inbound();});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief get the in edges
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.getInEdges = function () {
var args = arguments;
return this.map(function(a) {return a.getInEdges.apply(a, args);});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief get the out edges
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.getOutEdges = function () {
var args = arguments;
return this.map(function(a) {return a.getOutEdges.apply(a, args);});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief get the edges
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.getEdges = function () {
var args = arguments;
return this.map(function(a) {return a.getEdges.apply(a, args);});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of edges
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.degree = function () {
return this.map(function(a) {return a.degree();});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of in-edges
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.inDegree = function () {
return this.map(function(a) {return a.inDegree();});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of out-edges
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.inDegree = function () {
return this.map(function(a) {return a.outDegree();});
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the properties
////////////////////////////////////////////////////////////////////////////////
GraphArray.prototype.properties = function () {
return this.map(function(a) {return a.properties();});
};
Edge = function (graph, properties) {
this._graph = graph;
this._id = properties._key;
this._properties = properties;
};
////////////////////////////////////////////////////////////////////////////////
/// the real docu is in Users/ModuleGraph/EdgeMethods.mdpp
////////////////////////////////////////////////////////////////////////////////
Edge.prototype.getId = function () {
return this._properties._key;
};
////////////////////////////////////////////////////////////////////////////////
/// the real docu is in Users/ModuleGraph/EdgeMethods.mdpp
////////////////////////////////////////////////////////////////////////////////
Edge.prototype.getLabel = function () {
return this._properties.$label;
};
////////////////////////////////////////////////////////////////////////////////
/// the real docu is in Users/ModuleGraph/EdgeMethods.mdpp
////////////////////////////////////////////////////////////////////////////////
Edge.prototype.getProperty = function (name) {
return this._properties[name];
};
////////////////////////////////////////////////////////////////////////////////
/// the real docu is in Users/ModuleGraph/EdgeMethods.mdpp
////////////////////////////////////////////////////////////////////////////////
Edge.prototype.getPropertyKeys = function () {
return propertyKeys(this._properties);
};
////////////////////////////////////////////////////////////////////////////////
/// the real docu is in Users/ModuleGraph/EdgeMethods.mdpp
////////////////////////////////////////////////////////////////////////////////
Edge.prototype.properties = function () {
return shallowCopy(this._properties);
};
////////////////////////////////////////////////////////////////////////////////
/// the real docu is in Users/ModuleGraph/EdgeMethods.mdpp
////////////////////////////////////////////////////////////////////////////////
Edge.prototype.getInVertex = function () {
return this._graph.getVertex(this._properties._to);
};
////////////////////////////////////////////////////////////////////////////////
/// the real docu is in Users/ModuleGraph/EdgeMethods.mdpp
////////////////////////////////////////////////////////////////////////////////
Edge.prototype.getOutVertex = function () {
return this._graph.getVertex(this._properties._from);
};
////////////////////////////////////////////////////////////////////////////////
/// this is no documentation.
/// @start Docu Block edgeGetPeerVertex
///
/// `edge*.getPeerVertex(vertex)`
///
/// Returns the peer vertex of the *edge* and the *vertex*.
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_OUTPUT{edgeGetPeerVertex}
/// ~ db._drop("v");
/// ~ db._drop("e");
/// Graph = require("@arangodb/graph-blueprint").Graph;
/// g = new Graph("example", "v", "e");
/// v1 = g.addVertex("1");
/// v2 = g.addVertex("2");
/// e = g.addEdge(v1, v2, "1-to-2", "knows");
/// e.getPeerVertex(v1);
/// ~ Graph.drop("example");
/// ~ db._drop("v");
/// ~ db._drop("e");
/// @END_EXAMPLE_ARANGOSH_OUTPUT
/// @end Docu Block
////////////////////////////////////////////////////////////////////////////////
Edge.prototype.getPeerVertex = function (vertex) {
if (vertex._properties._id === this._properties._to) {
return this._graph.getVertex(this._properties._from);
}
if (vertex._properties._id === this._properties._from) {
return this._graph.getVertex(this._properties._to);
}
return null;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief edge printing
////////////////////////////////////////////////////////////////////////////////
Edge.prototype._PRINT = function (context) {
if (!this._properties._id) {
context.output += "[deleted Edge]";
}
else if (this._properties._key !== undefined) {
if (typeof this._properties._key === "string") {
context.output += "Edge(\"" + this._properties._key + "\")";
}
else {
context.output += "Edge(" + this._properties._key + ")";
}
}
else {
context.output += "Edge(<" + this._id + ">)";
}
};
Vertex = function (graph, properties) {
this._graph = graph;
this._id = properties._key;
this._properties = properties;
};
////////////////////////////////////////////////////////////////////////////////
/// the real docu is in Users/ModuleGraph/VertexMethods.mdpp
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.addInEdge = function (out, id, label, data) {
return this._graph.addEdge(out, this, id, label, data);
};
////////////////////////////////////////////////////////////////////////////////
/// the real docu is in Users/ModuleGraph/VertexMethods.mdpp
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.addOutEdge = function (ine, id, label, data) {
return this._graph.addEdge(this, ine, id, label, data);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of edges
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.degree = function () {
return this.getEdges().length;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of in-edges
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.inDegree = function () {
return this.getInEdges().length;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of out-edges
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.outDegree = function () {
return this.getOutEdges().length;
};
////////////////////////////////////////////////////////////////////////////////
/// this is no documentation.
/// @start Docu Block peerGetId
///
/// `peer.getId()`
///
/// Returns the identifier of the *peer*. If the vertex was deleted, then
/// *undefined* is returned.
///
/// @EXAMPLES
///
/// @verbinclude graph-vertex-get-id
/// @end Docu Block
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.getId = function () {
return this._properties._key;
};
////////////////////////////////////////////////////////////////////////////////
/// this is no documentation.
/// @start Docu Block peerGetProperty
///
/// `peer.getProperty(edge)`
///
/// Returns the property *edge* a *peer*.
///
/// @EXAMPLES
///
/// @verbinclude graph-vertex-get-property
/// @end Docu Block
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.getProperty = function (name) {
return this._properties[name];
};
////////////////////////////////////////////////////////////////////////////////
/// this is no documentation.
/// @start Docu Block peerGetPropertyKeys
///
/// `peer.getPropertyKeys()`
///
/// Returns all propety names a *peer*.
///
/// @EXAMPLES
///
/// @verbinclude graph-vertex-get-property-keys
/// @end Docu Block
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.getPropertyKeys = function () {
return propertyKeys(this._properties);
};
////////////////////////////////////////////////////////////////////////////////
/// this is no documentation.
/// @start Docu Block peerproperties
///
/// `peer.properties()`
///
/// Returns all properties and their values of a *peer*
///
/// @EXAMPLES
///
/// @verbinclude graph-vertex-properties
/// @end Docu Block
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.properties = function () {
return shallowCopy(this._properties);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief vertex representation
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype._PRINT = function (context) {
if (! this._properties._id) {
context.output += "[deleted Vertex]";
}
else if (this._properties._key !== undefined) {
if (typeof this._properties._key === "string") {
context.output += "Vertex(\"" + this._properties._key + "\")";
}
else {
context.output += "Vertex(" + this._properties._key + ")";
}
}
else {
context.output += "Vertex(<" + this._id + ">)";
}
};
Graph = function (name, vertices, edges, waitForSync) {
this.initialize(name, vertices, edges, waitForSync);
};
Graph.prototype._prepareEdgeData = function (data, label) {
var edgeData;
if (is.notExisty(data) && is.object(label)) {
data = label;
label = null;
}
if (is.notExisty(label) && is.existy(data) && is.existy(data.$label)) {
label = data.$label;
}
if (is.notExisty(data) || is.noObject(data)) {
edgeData = {};
} else {
edgeData = shallowCopy(data) || {};
}
edgeData.$label = label;
return edgeData;
};
Graph.prototype._prepareVertexData = function (data) {
var vertexData;
if (is.notExisty(data) || is.noObject(data)) {
vertexData = {};
} else {
vertexData = shallowCopy(data) || {};
}
return vertexData;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief get a vertex from the graph, create it if it doesn't exist
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.getOrAddVertex = function (id) {
var v = this.getVertex(id);
if (v === null) {
v = this.addVertex(id);
}
return v;
};
////////////////////////////////////////////////////////////////////////////////
/// the real docu is in Users/ModuleGraph/GraphConstructor.mdpp
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.addEdge = function (out_vertex, in_vertex, id, label, data, waitForSync) {
var out_vertex_id, in_vertex_id;
if (is.string(out_vertex)) {
out_vertex_id = out_vertex;
} else {
out_vertex_id = out_vertex._properties._id;
}
if (is.string(in_vertex)) {
in_vertex_id = in_vertex;
} else {
in_vertex_id = in_vertex._properties._id;
}
return this._saveEdge(id,
out_vertex_id,
in_vertex_id,
this._prepareEdgeData(data, label),
waitForSync);
};
////////////////////////////////////////////////////////////////////////////////
/// the real docu is in Users/ModuleGraph/GraphConstructor.mdpp
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.addVertex = function (id, data, waitForSync) {
return this._saveVertex(id, this._prepareVertexData(data), waitForSync);
};
////////////////////////////////////////////////////////////////////////////////
/// this is no documentation.
/// @brief replaces an existing vertex by ID
///
/// @FUN{@FA{graph}.replaceVertex(*peer*, *peer*)}
///
/// Replaces an existing vertex by ID
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.replaceVertex = function (id, data) {
this._replaceVertex(id, data);
};
////////////////////////////////////////////////////////////////////////////////
/// this is no documentation.
/// @start DocuBlock graphReplaceEdge
///
/// `graph.replaceEdge(peer, peer)`
///
/// Replaces an existing edge by ID
/// @end Docu Block
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.replaceEdge = function (id, data) {
this._replaceEdge(id, data);
};
////////////////////////////////////////////////////////////////////////////////
/// this is no documentation.
/// @brief returns the number of vertices
///
/// @FUN{@FA{graph}.order()}
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.order = function () {
return this._vertices.count();
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of edges
///
/// @FUN{@FA{graph}.size()}
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.size = function () {
return this._edges.count();
};
////////////////////////////////////////////////////////////////////////////////
/// this is no documentation.
/// @brief empties the internal cache for Predecessors
///
/// @FUN{@FA{graph}.emptyCachedPredecessors()}
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.emptyCachedPredecessors = function () {
this.predecessors = {};
};
////////////////////////////////////////////////////////////////////////////////
/// @brief gets Predecessors for a pair from the internal cache
///
/// @FUN{@FA{graph}.getCachedPredecessors(@FA{target}), @FA{source})}
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.getCachedPredecessors = function (target, source) {
var predecessors;
if (this.predecessors[target.getId()]) {
predecessors = this.predecessors[target.getId()][source.getId()];
}
return predecessors;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief sets Predecessors for a pair in the internal cache
///
/// @FUN{@FA{graph}.setCachedPredecessors(@FA{target}), @FA{source}, @FA{value})}
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.setCachedPredecessors = function (target, source, value) {
if (!this.predecessors[target.getId()]) {
this.predecessors[target.getId()] = {};
}
this.predecessors[target.getId()][source.getId()] = value;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a vertex
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.constructVertex = function (data) {
var id, rev;
if (typeof data === "string") {
id = data;
} else {
id = data._id;
rev = data._rev;
}
var vertex = this._verticesCache[id];
if (vertex === undefined || vertex._rev !== rev) {
var properties = this._vertices.document(id);
if (! properties) {
throw "accessing a deleted vertex";
}
this._verticesCache[id] = vertex = new Vertex(this, properties);
}
return vertex;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief constructs an edge
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.constructEdge = function (data) {
var id, rev, edge, properties;
if (typeof data === "string") {
id = data;
} else {
id = data._id;
rev = data._rev;
}
edge = this._edgesCache[id];
if (edge === undefined || edge._rev !== rev) {
properties = this._edges.document(id);
if (!properties) {
throw "accessing a deleted edge";
}
this._edgesCache[id] = edge = new Edge(this, properties);
}
return edge;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief graph printing
////////////////////////////////////////////////////////////////////////////////
Graph.prototype._PRINT = function (context) {
context.output += "Graph(\"" + this._properties._key + "\")";
};
exports.Edge = Edge;
exports.Graph = Graph;
exports.Vertex = Vertex;
exports.GraphArray = GraphArray;
exports.Iterator = Iterator;