mirror of https://gitee.com/bigwinds/arangodb
traversal aql
This commit is contained in:
parent
eb7150d815
commit
c99ce5167d
|
@ -706,7 +706,9 @@ TRI_associative_pointer_t* TRI_CreateFunctionsAql (void) {
|
||||||
REGISTER_FUNCTION("GRAPH_PATHS", "GENERAL_GRAPH_PATHS", false, false, "s|s,b,n,n", &OptimisePaths);
|
REGISTER_FUNCTION("GRAPH_PATHS", "GENERAL_GRAPH_PATHS", false, false, "s|s,b,n,n", &OptimisePaths);
|
||||||
REGISTER_FUNCTION("SHORTEST_PATH", "GRAPH_SHORTEST_PATH", false, false, "h,h,s,s,s|a", NULL);
|
REGISTER_FUNCTION("SHORTEST_PATH", "GRAPH_SHORTEST_PATH", false, false, "h,h,s,s,s|a", NULL);
|
||||||
REGISTER_FUNCTION("TRAVERSAL", "GRAPH_TRAVERSAL", false, false, "h,h,s,s|a", NULL);
|
REGISTER_FUNCTION("TRAVERSAL", "GRAPH_TRAVERSAL", false, false, "h,h,s,s|a", NULL);
|
||||||
|
REGISTER_FUNCTION("GRAPH_TRAVERSAL", "GENERAL_GRAPH_TRAVERSAL", false, false, "s,s,s|a", NULL);
|
||||||
REGISTER_FUNCTION("TRAVERSAL_TREE", "GRAPH_TRAVERSAL_TREE", false, false, "h,h,s,s,s|a", NULL);
|
REGISTER_FUNCTION("TRAVERSAL_TREE", "GRAPH_TRAVERSAL_TREE", false, false, "h,h,s,s,s|a", NULL);
|
||||||
|
REGISTER_FUNCTION("GRAPH_TRAVERSAL_TREE", "GENERAL_GRAPH_TRAVERSAL_TREE", false, false, "s,s,s,s|a", NULL);
|
||||||
REGISTER_FUNCTION("EDGES", "GRAPH_EDGES", false, false, "h,s,s|l", NULL);
|
REGISTER_FUNCTION("EDGES", "GRAPH_EDGES", false, false, "h,s,s|l", NULL);
|
||||||
REGISTER_FUNCTION("GRAPH_EDGES", "GENERAL_GRAPH_EDGES", false, false, "s,s,s|lza,ls", NULL);
|
REGISTER_FUNCTION("GRAPH_EDGES", "GENERAL_GRAPH_EDGES", false, false, "s,s,s|lza,ls", NULL);
|
||||||
REGISTER_FUNCTION("NEIGHBORS", "GRAPH_NEIGHBORS", false, false, "h,h,s,s|l", NULL);
|
REGISTER_FUNCTION("NEIGHBORS", "GRAPH_NEIGHBORS", false, false, "h,h,s,s|l", NULL);
|
||||||
|
|
|
@ -4329,39 +4329,36 @@ function TRAVERSAL_CHECK_EXAMPLES_TYPEWEIGHTS (examples, func) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief tranform key to id
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function TO_ID (vertex, collection) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
if (vertex === 'object' && vertex.hasOwnProperty('_id')) {
|
||||||
|
return vertex._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertex.indexOf('/') === -1 && collection) {
|
||||||
|
return collection + '/' + vertex;
|
||||||
|
}
|
||||||
|
return vertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief traverse a graph
|
/// @brief traverse a graph
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
function TRAVERSAL_FUNC (func,
|
function TRAVERSAL_FUNC (func,
|
||||||
vertexCollection,
|
datasource,
|
||||||
edgeCollection,
|
|
||||||
startVertex,
|
startVertex,
|
||||||
endVertex,
|
endVertex,
|
||||||
direction,
|
direction,
|
||||||
params) {
|
params) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
if (startVertex === 'object' && startVertex.hasOwnProperty('_id')) {
|
|
||||||
startVertex = startVertex._id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startVertex.indexOf('/') === -1) {
|
|
||||||
startVertex = vertexCollection + '/' + startVertex;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endVertex !== undefined) {
|
|
||||||
if (endVertex === 'object' && endVertex.hasOwnProperty('_id')) {
|
|
||||||
endVertex = endVertex._id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endVertex.indexOf('/') === -1) {
|
|
||||||
endVertex = vertexCollection + '/' + endVertex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vertexCollection = COLLECTION(vertexCollection);
|
|
||||||
edgeCollection = COLLECTION(edgeCollection);
|
|
||||||
|
|
||||||
if (params === undefined) {
|
if (params === undefined) {
|
||||||
params = { };
|
params = { };
|
||||||
|
@ -4388,7 +4385,7 @@ function TRAVERSAL_FUNC (func,
|
||||||
var config = {
|
var config = {
|
||||||
distance: params.distance,
|
distance: params.distance,
|
||||||
connect: params.connect,
|
connect: params.connect,
|
||||||
datasource: TRAVERSAL.collectionDatasourceFactory(edgeCollection),
|
datasource: datasource,
|
||||||
trackPaths: params.paths || false,
|
trackPaths: params.paths || false,
|
||||||
visitor: params.visitor,
|
visitor: params.visitor,
|
||||||
maxDepth: params.maxDepth,
|
maxDepth: params.maxDepth,
|
||||||
|
@ -4491,11 +4488,10 @@ function GRAPH_SHORTEST_PATH (vertexCollection,
|
||||||
params.distance = undefined;
|
params.distance = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRAVERSAL_FUNC("SHORTEST_PATH",
|
return TRAVERSAL_FUNC("SHORTEST_PATH",
|
||||||
vertexCollection,
|
TRAVERSAL.collectionDatasourceFactory(COLLECTION(edgeCollection)),
|
||||||
edgeCollection,
|
TO_ID(startVertex, vertexCollection),
|
||||||
startVertex,
|
TO_ID(endVertex, vertexCollection),
|
||||||
endVertex,
|
|
||||||
direction,
|
direction,
|
||||||
params);
|
params);
|
||||||
}
|
}
|
||||||
|
@ -4517,15 +4513,40 @@ function GRAPH_TRAVERSAL (vertexCollection,
|
||||||
|
|
||||||
params.visitor = TRAVERSAL_VISITOR;
|
params.visitor = TRAVERSAL_VISITOR;
|
||||||
|
|
||||||
return TRAVERSAL_FUNC("TRAVERSAL",
|
return TRAVERSAL_FUNC("TRAVERSAL",
|
||||||
vertexCollection,
|
TRAVERSAL.collectionDatasourceFactory(COLLECTION(edgeCollection)),
|
||||||
edgeCollection,
|
TO_ID(startVertex, vertexCollection),
|
||||||
startVertex,
|
undefined,
|
||||||
undefined,
|
|
||||||
direction,
|
direction,
|
||||||
params);
|
params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief traverse a graph
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function GENERAL_GRAPH_TRAVERSAL (graphName,
|
||||||
|
startVertex,
|
||||||
|
direction,
|
||||||
|
params) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
if (params === undefined) {
|
||||||
|
params = { };
|
||||||
|
}
|
||||||
|
|
||||||
|
params.visitor = TRAVERSAL_VISITOR;
|
||||||
|
|
||||||
|
return TRAVERSAL_FUNC("TRAVERSAL",
|
||||||
|
TRAVERSAL.generalGraphDatasourceFactory(graphName),
|
||||||
|
TO_ID(startVertex),
|
||||||
|
undefined,
|
||||||
|
direction,
|
||||||
|
params);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief traverse a graph and create a hierarchical result
|
/// @brief traverse a graph and create a hierarchical result
|
||||||
/// this function uses the same setup as the TRAVERSE() function but will use
|
/// this function uses the same setup as the TRAVERSE() function but will use
|
||||||
|
@ -4551,10 +4572,9 @@ function GRAPH_TRAVERSAL_TREE (vertexCollection,
|
||||||
params.visitor = TRAVERSAL_TREE_VISITOR;
|
params.visitor = TRAVERSAL_TREE_VISITOR;
|
||||||
params.connect = connectName;
|
params.connect = connectName;
|
||||||
|
|
||||||
var result = TRAVERSAL_FUNC("TRAVERSAL_TREE",
|
var result = TRAVERSAL_FUNC("TRAVERSAL_TREE",
|
||||||
vertexCollection,
|
TRAVERSAL.collectionDatasourceFactory(COLLECTION(edgeCollection)),
|
||||||
edgeCollection,
|
TO_ID(startVertex, vertexCollection),
|
||||||
startVertex,
|
|
||||||
undefined,
|
undefined,
|
||||||
direction,
|
direction,
|
||||||
params);
|
params);
|
||||||
|
@ -4565,6 +4585,44 @@ function GRAPH_TRAVERSAL_TREE (vertexCollection,
|
||||||
return [ result[0][params.connect] ];
|
return [ result[0][params.connect] ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief traverse a graph and create a hierarchical result
|
||||||
|
/// this function uses the same setup as the TRAVERSE() function but will use
|
||||||
|
/// a different visitor to create the result
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function GENERAL_GRAPH_TRAVERSAL_TREE (graphName,
|
||||||
|
startVertex,
|
||||||
|
direction,
|
||||||
|
connectName,
|
||||||
|
params) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
if (connectName === "") {
|
||||||
|
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "TRAVERSAL_TREE");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params === undefined) {
|
||||||
|
params = { };
|
||||||
|
}
|
||||||
|
|
||||||
|
params.visitor = TRAVERSAL_TREE_VISITOR;
|
||||||
|
params.connect = connectName;
|
||||||
|
|
||||||
|
var result = TRAVERSAL_FUNC("TRAVERSAL_TREE",
|
||||||
|
TRAVERSAL.generalGraphDatasourceFactory(graphName),
|
||||||
|
TO_ID(startVertex),
|
||||||
|
undefined,
|
||||||
|
direction,
|
||||||
|
params);
|
||||||
|
|
||||||
|
if (result.length === 0) {
|
||||||
|
return [ ];
|
||||||
|
}
|
||||||
|
return [ result[0][params.connect] ];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief return connected edges
|
/// @brief return connected edges
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -4836,6 +4894,8 @@ exports.GRAPH_PATHS = GRAPH_PATHS;
|
||||||
exports.GRAPH_SHORTEST_PATH = GRAPH_SHORTEST_PATH;
|
exports.GRAPH_SHORTEST_PATH = GRAPH_SHORTEST_PATH;
|
||||||
exports.GRAPH_TRAVERSAL = GRAPH_TRAVERSAL;
|
exports.GRAPH_TRAVERSAL = GRAPH_TRAVERSAL;
|
||||||
exports.GRAPH_TRAVERSAL_TREE = GRAPH_TRAVERSAL_TREE;
|
exports.GRAPH_TRAVERSAL_TREE = GRAPH_TRAVERSAL_TREE;
|
||||||
|
exports.GENERAL_GRAPH_TRAVERSAL = GENERAL_GRAPH_TRAVERSAL;
|
||||||
|
exports.GENERAL_GRAPH_TRAVERSAL_TREE = GENERAL_GRAPH_TRAVERSAL_TREE;
|
||||||
exports.GRAPH_EDGES = GRAPH_EDGES;
|
exports.GRAPH_EDGES = GRAPH_EDGES;
|
||||||
exports.GENERAL_GRAPH_EDGES = GENERAL_GRAPH_EDGES;
|
exports.GENERAL_GRAPH_EDGES = GENERAL_GRAPH_EDGES;
|
||||||
exports.GENERAL_GRAPH_PATHS = GENERAL_GRAPH_PATHS;
|
exports.GENERAL_GRAPH_PATHS = GENERAL_GRAPH_PATHS;
|
||||||
|
|
|
@ -262,7 +262,7 @@ function ahuacatlQueryGeneralPathsTestSuite() {
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief checks EDGES()
|
/// @brief checks GRAPH_PATHS()
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testPaths: function () {
|
testPaths: function () {
|
||||||
|
@ -352,11 +352,161 @@ function ahuacatlQueryGeneralPathsTestSuite() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test suite for GRAPH_TRAVERSAL() function
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function ahuacatlQueryGeneralTraversalTestSuite() {
|
||||||
|
var vertex = null;
|
||||||
|
var edge = null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief set up
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
setUp: function () {
|
||||||
|
db._drop("UnitTests_Berliner");
|
||||||
|
db._drop("UnitTests_Hamburger");
|
||||||
|
db._drop("UnitTests_Frankfurter");
|
||||||
|
db._drop("UnitTests_Leipziger");
|
||||||
|
db._drop("UnitTests_KenntAnderenBerliner");
|
||||||
|
db._drop("UnitTests_KenntAnderen");
|
||||||
|
|
||||||
|
KenntAnderenBerliner = "UnitTests_KenntAnderenBerliner";
|
||||||
|
KenntAnderen = "UnitTests_KenntAnderen";
|
||||||
|
|
||||||
|
Berlin = db._create("UnitTests_Berliner");
|
||||||
|
Hamburg = db._create("UnitTests_Hamburger");
|
||||||
|
Frankfurt = db._create("UnitTests_Frankfurter");
|
||||||
|
Leipzig = db._create("UnitTests_Leipziger");
|
||||||
|
db._createEdgeCollection(KenntAnderenBerliner);
|
||||||
|
db._createEdgeCollection(KenntAnderen);
|
||||||
|
|
||||||
|
var Anton = Berlin.save({ _key: "Anton" , gender : "male"});
|
||||||
|
var Berta = Berlin.save({ _key: "Berta" , gender : "female"});
|
||||||
|
var Caesar = Hamburg.save({ _key: "Caesar" , gender : "male"});
|
||||||
|
var Dieter = Hamburg.save({ _key: "Dieter" , gender : "male"});
|
||||||
|
var Emil = Frankfurt.save({ _key: "Emil" , gender : "male"});
|
||||||
|
var Fritz = Frankfurt.save({ _key: "Fritz" , gender : "male"});
|
||||||
|
var Gerda = Leipzig.save({ _key: "Gerda" , gender : "female"});
|
||||||
|
|
||||||
|
try {
|
||||||
|
db._collection("_graphs").remove("_graphs/werKenntWen")
|
||||||
|
} catch (err) {
|
||||||
|
}
|
||||||
|
var g = graph._create(
|
||||||
|
"werKenntWen",
|
||||||
|
graph.edgeDefinitions(
|
||||||
|
graph._undirectedRelationDefinition(KenntAnderenBerliner, "UnitTests_Berliner"),
|
||||||
|
graph._directedRelationDefinition(KenntAnderen,
|
||||||
|
["UnitTests_Hamburger", "UnitTests_Frankfurter", "UnitTests_Berliner", "UnitTests_Leipziger"],
|
||||||
|
["UnitTests_Hamburger", "UnitTests_Frankfurter", "UnitTests_Berliner", "UnitTests_Leipziger"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
function makeEdge(from, to, collection) {
|
||||||
|
collection.save(from, to, { what: from.split("/")[1] + "->" + to.split("/")[1] });
|
||||||
|
}
|
||||||
|
makeEdge(Berta._id, Anton._id, g[KenntAnderenBerliner]);
|
||||||
|
makeEdge(Caesar._id, Anton._id, g[KenntAnderen]);
|
||||||
|
makeEdge(Caesar._id, Berta._id, g[KenntAnderen]);
|
||||||
|
makeEdge(Berta._id, Gerda._id, g[KenntAnderen]);
|
||||||
|
makeEdge(Gerda._id, Dieter._id, g[KenntAnderen]);
|
||||||
|
makeEdge(Dieter._id, Emil._id, g[KenntAnderen]);
|
||||||
|
makeEdge(Emil._id, Fritz._id, g[KenntAnderen]);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief tear down
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
tearDown: function () {
|
||||||
|
db._drop("UnitTests_Berliner");
|
||||||
|
db._drop("UnitTests_Hamburger");
|
||||||
|
db._drop("UnitTests_Frankfurter");
|
||||||
|
db._drop("UnitTests_Leipziger");
|
||||||
|
db._drop("UnitTests_KenntAnderenBerliner");
|
||||||
|
db._drop("UnitTests_KenntAnderen");
|
||||||
|
db._collection("_graphs").remove("_graphs/werKenntWen");
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief checks GRAPH_TRAVERSAL()
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testGRAPH_TRAVERSALs: function () {
|
||||||
|
var actual, result= [];
|
||||||
|
|
||||||
|
actual = getQueryResults("FOR e IN GRAPH_TRAVERSAL('werKenntWen', 'UnitTests_Hamburger/Caesar', 'outbound') RETURN e");
|
||||||
|
//require("internal").print(actual);
|
||||||
|
actual.forEach(function (s) {
|
||||||
|
result.push(s.vertex._key);
|
||||||
|
});
|
||||||
|
//require("internal").print(result)
|
||||||
|
assertEqual(result, [
|
||||||
|
"Caesar",
|
||||||
|
"Anton",
|
||||||
|
"Berta",
|
||||||
|
"Anton",
|
||||||
|
"Gerda",
|
||||||
|
"Dieter",
|
||||||
|
"Emil",
|
||||||
|
"Fritz"
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
testGENERAL_GRAPH_TRAVERSAL_TREE: function () {
|
||||||
|
var actual, start, middle;
|
||||||
|
|
||||||
|
actual = getQueryResults("FOR e IN GRAPH_TRAVERSAL_TREE('werKenntWen', 'UnitTests_Hamburger/Caesar', 'outbound', 'connected') RETURN e");
|
||||||
|
start = actual[0][0];
|
||||||
|
|
||||||
|
assertEqual(start._key, "Caesar");
|
||||||
|
assertTrue(start.hasOwnProperty("connected"));
|
||||||
|
assertTrue(start.connected.length === 2);
|
||||||
|
assertEqual(start.connected[0]._key, "Anton");
|
||||||
|
assertEqual(start.connected[1]._key, "Berta");
|
||||||
|
|
||||||
|
assertTrue(!start.connected[0].hasOwnProperty("connected"));
|
||||||
|
assertTrue(start.connected[1].hasOwnProperty("connected"));
|
||||||
|
|
||||||
|
middle = start.connected[1];
|
||||||
|
|
||||||
|
assertTrue(middle.connected.length === 2);
|
||||||
|
assertEqual(middle.connected[0]._key, "Anton");
|
||||||
|
assertEqual(middle.connected[1]._key, "Gerda");
|
||||||
|
|
||||||
|
assertTrue(!middle.connected[0].hasOwnProperty("connected"));
|
||||||
|
assertTrue(middle.connected[1].hasOwnProperty("connected"));
|
||||||
|
|
||||||
|
middle = middle.connected[1];
|
||||||
|
assertTrue(middle.connected.length === 1);
|
||||||
|
assertEqual(middle.connected[0]._key, "Dieter");
|
||||||
|
|
||||||
|
middle = middle.connected[0];
|
||||||
|
|
||||||
|
assertTrue(middle.connected.length === 1);
|
||||||
|
assertEqual(middle.connected[0]._key, "Emil");
|
||||||
|
|
||||||
|
middle = middle.connected[0];
|
||||||
|
assertTrue(middle.connected.length === 1);
|
||||||
|
assertEqual(middle.connected[0]._key, "Fritz");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief executes the test suite
|
/// @brief executes the test suite
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
jsunity.run(ahuacatlQueryGeneralTraversalTestSuite);
|
||||||
jsunity.run(ahuacatlQueryGeneralEdgesTestSuite);
|
jsunity.run(ahuacatlQueryGeneralEdgesTestSuite);
|
||||||
jsunity.run(ahuacatlQueryGeneralPathsTestSuite);
|
jsunity.run(ahuacatlQueryGeneralPathsTestSuite);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue