mirror of https://gitee.com/bigwinds/arangodb
1972 lines
73 KiB
JavaScript
1972 lines
73 KiB
JavaScript
/*jshint globalstrict:false, strict:false, maxlen: 500 */
|
|
/*global assertEqual, assertTrue, AQL_EXECUTE */
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief tests for query language, graph functions
|
|
///
|
|
/// @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 Florian Bartels
|
|
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
var jsunity = require("jsunity");
|
|
var db = require("@arangodb").db;
|
|
var errors = require("internal").errors;
|
|
var graph = require("@arangodb/general-graph");
|
|
var helper = require("@arangodb/aql-helper");
|
|
var getQueryResults = helper.getQueryResults;
|
|
var getRawQueryResults = helper.getRawQueryResults;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief test suite for traversals using GRAPHS
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
function ahuacatlQueryGeneralEdgesTestSuite() {
|
|
|
|
var gN = "bla3";
|
|
var v1 = "UnitTestsAhuacatlVertex1";
|
|
var v2 = "UnitTestsAhuacatlVertex2";
|
|
var v3 = "UnitTestsAhuacatlVertex3";
|
|
var v4 = "UnitTestsAhuacatlVertex4";
|
|
var e1 = "UnitTestsAhuacatlEdge1";
|
|
var e2 = "UnitTestsAhuacatlEdge2";
|
|
var or = "UnitTestsAhuacatlOrphan";
|
|
|
|
// var AQL_VERTICES = "FOR v IN GRAPH_VERTICES(@name, @example, @options) SORT v RETURN v";
|
|
var exampleFilter = "FILTER x.hugo == true OR x.heinz == 1 RETURN x";
|
|
var AQL_PICK_START_EXAMPLE = `FOR start IN UNION (
|
|
(FOR x IN ${v1} ${exampleFilter}),
|
|
(FOR x IN ${v2} ${exampleFilter}),
|
|
(FOR x IN ${v3} ${exampleFilter}),
|
|
(FOR x IN ${v4} ${exampleFilter})
|
|
)`;
|
|
var AQL_START_EVERYWHERE = `FOR start IN UNION (
|
|
(FOR x IN ${v1} RETURN x),
|
|
(FOR x IN ${v2} RETURN x),
|
|
(FOR x IN ${v3} RETURN x),
|
|
(FOR x IN ${v4} RETURN x)
|
|
)`;
|
|
|
|
// var startExample = [{hugo : true}, {heinz : 1}];
|
|
|
|
return {
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief set up
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
setUpAll: function () {
|
|
db._drop(v1);
|
|
db._drop(v2);
|
|
db._drop(v3);
|
|
db._drop(v4);
|
|
db._drop(e1);
|
|
db._drop(e2);
|
|
db._drop(or);
|
|
|
|
var vertex1 = db._create(v1);
|
|
var vertex2 = db._create(v2);
|
|
var vertex3 = db._create(v3);
|
|
var vertex4 = db._create(v4);
|
|
var edge1 = db._createEdgeCollection(e1);
|
|
var edge2 = db._createEdgeCollection(e2);
|
|
var orphan = db._create(or);
|
|
|
|
vertex1.save({ _key: "v1", hugo: true});
|
|
vertex1.save({ _key: "v2", hugo: true});
|
|
vertex2.save({ _key: "v3", heinz: 1});
|
|
vertex2.save({ _key: "v4" });
|
|
vertex3.save({ _key: "v5" });
|
|
vertex3.save({ _key: "v6" });
|
|
vertex4.save({ _key: "v7" });
|
|
vertex4.save({ _key: "v8", heinz: 1});
|
|
orphan.save({ _key: "orphan" });
|
|
|
|
function makeEdge(from, to, collection) {
|
|
collection.save(from, to, { what: from.split("/")[1] + "->" + to.split("/")[1] });
|
|
}
|
|
|
|
makeEdge(v1 + "/v1", v1 + "/v2", edge1);
|
|
makeEdge(v1 + "/v2", v1 + "/v1", edge1);
|
|
makeEdge(v1 + "/v1", v3 + "/v5", edge2);
|
|
makeEdge(v1 + "/v2", v3 + "/v5", edge2);
|
|
makeEdge(v2 + "/v3", v3 + "/v6", edge2);
|
|
makeEdge(v2 + "/v4", v4 + "/v7", edge2);
|
|
makeEdge(v2 + "/v3", v3 + "/v5", edge2);
|
|
makeEdge(v2 + "/v3", v4 + "/v8", edge2);
|
|
|
|
try {
|
|
db._collection("_graphs").remove("_graphs/bla3");
|
|
} catch (ignore) {
|
|
}
|
|
graph._create(
|
|
"bla3",
|
|
graph._edgeDefinitions(
|
|
graph._relation(e1, v1, v1),
|
|
graph._relation(e2,
|
|
[v1, v2],
|
|
[v3, v4]
|
|
)
|
|
),
|
|
[or]
|
|
);
|
|
},
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief tear down
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
tearDownAll: function () {
|
|
db._drop(v1);
|
|
db._drop(v2);
|
|
db._drop(v3);
|
|
db._drop(v4);
|
|
db._drop(e1);
|
|
db._drop(e2);
|
|
db._drop(or);
|
|
db._collection("_graphs").remove("_graphs/bla3");
|
|
},
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks edges with a GRAPH
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// Section any direction
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
testEdgesAny: function () {
|
|
var query = `FOR v, e IN ANY @start GRAPH @name SORT e.what RETURN e.what`;
|
|
|
|
var bindVars = {
|
|
name: gN,
|
|
start: v1 + "/v1"
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual, [ "v1->v2", "v1->v5", "v2->v1" ]);
|
|
},
|
|
|
|
testEdgesAnyRestricted: function () {
|
|
var query = `WITH ${v1}, ${v2}, ${v3}, ${v4}
|
|
FOR v, e IN ANY @start @@collection
|
|
SORT e.what
|
|
RETURN e.what`;
|
|
var bindVars = {
|
|
start: v1 + "/v1",
|
|
"@collection": e1
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual, [ "v1->v2", "v2->v1" ]);
|
|
},
|
|
|
|
testEdgesAnyStartExample: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v, e IN ANY start GRAPH @name COLLECT what = e.what RETURN what`;
|
|
var bindVars = {
|
|
name: gN
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual, [
|
|
"v1->v2",
|
|
"v1->v5",
|
|
"v2->v1",
|
|
"v2->v5",
|
|
"v3->v5",
|
|
"v3->v6",
|
|
"v3->v8"
|
|
]);
|
|
},
|
|
|
|
testEdgesAnyStartExampleEdgeExample: function () {
|
|
var query = `FOR v, e IN ANY @start GRAPH @name FILTER e.what == "v2->v1" SORT e.what RETURN e.what`;
|
|
var bindVars = {
|
|
name: gN,
|
|
start: v1 + "/v1"
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 1);
|
|
assertEqual(actual[0], "v2->v1");
|
|
},
|
|
|
|
testEdgesInbound: function() {
|
|
var query = `FOR v, e IN INBOUND @start GRAPH @name SORT e.what RETURN e.what`;
|
|
var bindVars = {
|
|
name: gN,
|
|
start: v1 + "/v1"
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual, [ "v2->v1"]);
|
|
},
|
|
|
|
testEdgesInboundStartExample: function() {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v, e IN INBOUND start GRAPH @name SORT e.what RETURN e.what`;
|
|
var bindVars = {
|
|
name: gN
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 3);
|
|
assertEqual(actual[0], "v1->v2");
|
|
assertEqual(actual[1], "v2->v1");
|
|
assertEqual(actual[2], "v3->v8");
|
|
},
|
|
|
|
testEdgesInboundStartExampleRestricted: function() {
|
|
var query = `WITH ${v1}, ${v2}, ${v3}, ${v4}
|
|
${AQL_PICK_START_EXAMPLE}
|
|
FOR v, e IN INBOUND start @@collection SORT e.what RETURN e.what`;
|
|
var bindVars = {
|
|
"@collection": e2
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 1);
|
|
assertEqual(actual[0], "v3->v8");
|
|
},
|
|
|
|
testEdgesInboundStartExampleEdgeExample: function() {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v, e IN INBOUND start GRAPH @name FILTER e.what == 'v3->v8' SORT e.what RETURN e.what`;
|
|
var bindVars = {
|
|
name: gN
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 1);
|
|
assertEqual(actual[0], "v3->v8");
|
|
},
|
|
|
|
testEdgesOutbound: function() {
|
|
var query = `FOR v, e IN OUTBOUND @start GRAPH @name SORT e.what RETURN e.what`;
|
|
var bindVars = {
|
|
name: gN,
|
|
start: v1 + "/v1"
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual[0], "v1->v2");
|
|
assertEqual(actual[1], "v1->v5");
|
|
},
|
|
|
|
testEdgesOutboundStartExample: function() {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v, e IN OUTBOUND start GRAPH @name SORT e.what RETURN e.what`;
|
|
var bindVars = {
|
|
name: gN
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 7);
|
|
assertEqual(actual[0], "v1->v2");
|
|
assertEqual(actual[1], "v1->v5");
|
|
assertEqual(actual[2], "v2->v1");
|
|
assertEqual(actual[3], "v2->v5");
|
|
assertEqual(actual[4], "v3->v5");
|
|
assertEqual(actual[5], "v3->v6");
|
|
assertEqual(actual[6], "v3->v8");
|
|
},
|
|
|
|
testEdgesOutboundStartExampleRestricted: function() {
|
|
var query = `WITH ${v1}, ${v2}, ${v3}, ${v4}
|
|
${AQL_PICK_START_EXAMPLE}
|
|
FOR v, e IN OUTBOUND start @@collection
|
|
SORT e.what
|
|
RETURN e.what`;
|
|
var bindVars = {
|
|
"@collection": e2
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 5);
|
|
assertEqual(actual[0], "v1->v5");
|
|
assertEqual(actual[1], "v2->v5");
|
|
assertEqual(actual[2], "v3->v5");
|
|
assertEqual(actual[3], "v3->v6");
|
|
assertEqual(actual[4], "v3->v8");
|
|
},
|
|
|
|
testEdgesOutboundStartExampleRestrictedModify: function() {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v, e IN 1..2 OUTBOUND start @@collection SORT e.what
|
|
UPDATE e WITH {WasHere: True, When: DATE_NOW()} IN @@collection
|
|
RETURN e.what
|
|
`;
|
|
var bindVars = {
|
|
"@collection": e2
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
actual = getRawQueryResults("FOR x IN @@collection FILTER x.WasHere == True return x", bindVars);
|
|
assertEqual(actual.length, 5);
|
|
},
|
|
|
|
testEdgesOutboundStartExampleRestrictedLoadVertextByDocument: function() {
|
|
var query = `
|
|
${AQL_PICK_START_EXAMPLE}
|
|
FOR v, edge IN 1..2 OUTBOUND start @@collection SORT edge.what
|
|
LET fromVertex = DOCUMENT(edge._from)
|
|
LET toVertex = DOCUMENT(edge._to)
|
|
RETURN {edge, fromVertex, toVertex}`;
|
|
var bindVars = {
|
|
"@collection": e2
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
|
|
actual.forEach(function (oneEdgeSet) {
|
|
assertEqual(oneEdgeSet.edge._from, oneEdgeSet.fromVertex._id );
|
|
assertEqual(oneEdgeSet.edge._to, oneEdgeSet.toVertex._id );
|
|
});
|
|
},
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// Test Neighbors
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// Any direction
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
testNeighborsAny: function () {
|
|
var query = `FOR v IN ANY @start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true} SORT v._id RETURN v._id`;
|
|
var bindVars = {
|
|
name: gN,
|
|
start: v1 + "/v1"
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 2);
|
|
assertEqual(actual[0], v1 + "/v2");
|
|
assertEqual(actual[1], v3 + "/v5");
|
|
},
|
|
|
|
testNeighborsAnyEdgeExample: function () {
|
|
var query = `FOR v, e IN ANY @start GRAPH @name
|
|
FILTER e.what == "v2->v1"
|
|
COLLECT id = v._id
|
|
SORT id RETURN id`;
|
|
var bindVars = {
|
|
name: gN,
|
|
start: v1 + "/v1",
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 1);
|
|
assertEqual(actual[0], v1 + "/v2");
|
|
},
|
|
|
|
testNeighborsAnyStartExample: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE} FOR v IN ANY start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
COLLECT id = v._id
|
|
SORT id RETURN id`;
|
|
var bindVars = {
|
|
name: gN,
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 6);
|
|
assertEqual(actual[0], v1 + "/v1");
|
|
assertEqual(actual[1], v1 + "/v2");
|
|
assertEqual(actual[2], v2 + "/v3");
|
|
assertEqual(actual[3], v3 + "/v5");
|
|
assertEqual(actual[4], v3 + "/v6");
|
|
assertEqual(actual[5], v4 + "/v8");
|
|
},
|
|
|
|
testNeighborsAnyVertexExample: function () {
|
|
var query = `${AQL_START_EVERYWHERE}
|
|
FOR v IN ANY start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
FILTER v._key == "v1"
|
|
COLLECT id = v._id
|
|
SORT id RETURN id`;
|
|
var bindVars = {
|
|
name: gN
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 1);
|
|
assertEqual(actual[0], v1 + "/v1");
|
|
},
|
|
|
|
testNeighborsAnyStartExampleRestrictEdges: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN ANY start ${e2} OPTIONS {uniqueVertices: "global", bfs: true}
|
|
COLLECT id = v._id
|
|
SORT id RETURN id`;
|
|
var actual = getRawQueryResults(query);
|
|
assertEqual(actual.length, 4);
|
|
assertEqual(actual[0], v2 + "/v3");
|
|
assertEqual(actual[1], v3 + "/v5");
|
|
assertEqual(actual[2], v3 + "/v6");
|
|
assertEqual(actual[3], v4 + "/v8");
|
|
},
|
|
|
|
testNeighborsAnyStartExampleRestrictVertices: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN ANY start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
FILTER IS_SAME_COLLECTION(${v1}, v) OR IS_SAME_COLLECTION(${v3}, v)
|
|
COLLECT id = v._id SORT id RETURN id`;
|
|
var bindVars = {
|
|
name: gN
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 4);
|
|
assertEqual(actual[0], v1 + "/v1");
|
|
assertEqual(actual[1], v1 + "/v2");
|
|
assertEqual(actual[2], v3 + "/v5");
|
|
assertEqual(actual[3], v3 + "/v6");
|
|
},
|
|
|
|
testNeighborsAnyStartExampleRestrictEdgesAndVertices: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN ANY start ${e2} OPTIONS {uniqueVertices: "global", bfs: true}
|
|
FILTER IS_SAME_COLLECTION(${v1}, v) OR IS_SAME_COLLECTION(${v3}, v)
|
|
COLLECT id = v._id SORT id RETURN id`;
|
|
var actual = getRawQueryResults(query);
|
|
assertEqual(actual.length, 2);
|
|
assertEqual(actual[0], v3 + "/v5");
|
|
assertEqual(actual[1], v3 + "/v6");
|
|
},
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// direction outbound
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
testNeighborsOutbound: function () {
|
|
var query = `FOR v IN OUTBOUND @start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
SORT v._id RETURN v._id`;
|
|
var bindVars = {
|
|
name: gN,
|
|
start: v1 + "/v1"
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 2);
|
|
assertEqual(actual[0], v1 + "/v2");
|
|
assertEqual(actual[1], v3 + "/v5");
|
|
},
|
|
|
|
testNeighborsOutboundEdgeExample: function () {
|
|
var query = `FOR v, e IN OUTBOUND @start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
FILTER e.what == "v2->v1" OR e.what == "v1->v2"
|
|
SORT v._id RETURN v._id`;
|
|
var bindVars = {
|
|
name: gN,
|
|
start: v1 + "/v1",
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 1);
|
|
assertEqual(actual[0], v1 + "/v2");
|
|
},
|
|
|
|
testNeighborsOutboundStartExample: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN OUTBOUND start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
COLLECT id = v._id SORT id RETURN id`;
|
|
var bindVars = {
|
|
name: gN,
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 5);
|
|
|
|
assertEqual(actual[0], v1 + "/v1");
|
|
assertEqual(actual[1], v1 + "/v2");
|
|
assertEqual(actual[2], v3 + "/v5");
|
|
assertEqual(actual[3], v3 + "/v6");
|
|
assertEqual(actual[4], v4 + "/v8");
|
|
},
|
|
|
|
testNeighborsOutboundVertexExample: function () {
|
|
var query = `${AQL_START_EVERYWHERE}
|
|
FOR v IN OUTBOUND start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
FILTER v._key == "v1"
|
|
SORT v._id RETURN v._id`;
|
|
var bindVars = {
|
|
name: gN
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 1);
|
|
assertEqual(actual[0], v1 + "/v1");
|
|
},
|
|
|
|
testNeighborsOutboundStartExampleRestrictEdges: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN OUTBOUND start ${e2} OPTIONS {uniqueVertices: "global", bfs: true}
|
|
COLLECT id = v._id
|
|
SORT id
|
|
RETURN id`;
|
|
var actual = getRawQueryResults(query);
|
|
assertEqual(actual.length, 3);
|
|
assertEqual(actual[0], v3 + "/v5");
|
|
assertEqual(actual[1], v3 + "/v6");
|
|
assertEqual(actual[2], v4 + "/v8");
|
|
},
|
|
|
|
testNeighborsOutboundStartExampleRestrictVertices: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN OUTBOUND start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
FILTER IS_SAME_COLLECTION(${v1}, v) OR IS_SAME_COLLECTION(${v3}, v)
|
|
COLLECT id = v._id
|
|
SORT id RETURN id`;
|
|
var bindVars = {
|
|
name: gN
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 4);
|
|
assertEqual(actual[0], v1 + "/v1");
|
|
assertEqual(actual[1], v1 + "/v2");
|
|
assertEqual(actual[2], v3 + "/v5");
|
|
assertEqual(actual[3], v3 + "/v6");
|
|
},
|
|
|
|
testNeighborsOutboundStartExampleRestrictEdgesAndVertices: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN OUTBOUND start ${e2} OPTIONS {uniqueVertices: "global", bfs: true}
|
|
FILTER IS_SAME_COLLECTION(${v1}, v) OR IS_SAME_COLLECTION(${v3}, v)
|
|
COLLECT id = v._id
|
|
SORT id RETURN id`;
|
|
var actual = getRawQueryResults(query);
|
|
assertEqual(actual.length, 2);
|
|
assertEqual(actual[0], v3 + "/v5");
|
|
assertEqual(actual[1], v3 + "/v6");
|
|
},
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// inbound direction
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
testNeighborsInbound: function () {
|
|
var query = `FOR v IN INBOUND @start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
SORT v._id RETURN v._id`;
|
|
var bindVars = {
|
|
name: gN,
|
|
start: v1 + "/v1"
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 1);
|
|
assertEqual(actual[0], v1 + "/v2");
|
|
},
|
|
|
|
testNeighborsInboundEdgeExample: function () {
|
|
var query = `FOR v, e IN INBOUND @start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
FILTER e.what == "v2->v1"
|
|
SORT v._id RETURN v._id`;
|
|
var bindVars = {
|
|
name: gN,
|
|
start: v1 + "/v1"
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual[0], v1 + "/v2");
|
|
},
|
|
|
|
testNeighborsInboundStartExample: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN INBOUND start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
SORT v._id RETURN v._id`;
|
|
var bindVars = {
|
|
name: gN,
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 3);
|
|
assertEqual(actual[0], v1 + "/v1");
|
|
assertEqual(actual[1], v1 + "/v2");
|
|
assertEqual(actual[2], v2 + "/v3");
|
|
},
|
|
|
|
testNeighborsInboundNeighborExample: function () {
|
|
var query = `${AQL_START_EVERYWHERE}
|
|
FOR v IN INBOUND start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
FILTER v._key == "v1"
|
|
SORT v._id RETURN v._id`;
|
|
var bindVars = {
|
|
name: gN
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 2);
|
|
assertEqual(actual[0], v1 + "/v1");
|
|
assertEqual(actual[1], v1 + "/v1");
|
|
},
|
|
|
|
testNeighborsInboundStartExampleRestrictEdges: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN INBOUND start ${e2} OPTIONS {uniqueVertices: "global", bfs: true}
|
|
SORT v._id
|
|
RETURN v._id`;
|
|
var actual = getRawQueryResults(query);
|
|
assertEqual(actual.length, 1);
|
|
assertEqual(actual[0], v2 + "/v3");
|
|
},
|
|
|
|
testNeighborsInboundStartExampleRestrictVertices: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN INBOUND start GRAPH @name OPTIONS {uniqueVertices: "global", bfs: true}
|
|
FILTER IS_SAME_COLLECTION(${v1}, v) OR IS_SAME_COLLECTION(${v3}, v)
|
|
SORT v._id RETURN v._id`;
|
|
var bindVars = {
|
|
name: gN
|
|
};
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 2);
|
|
assertEqual(actual[0], v1 + "/v1");
|
|
assertEqual(actual[1], v1 + "/v2");
|
|
},
|
|
|
|
testNeighborsInboundStartExampleRestrictEdgesAndVertices: function () {
|
|
var query = `${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN INBOUND start ${e2} OPTIONS {uniqueVertices: "global", bfs: true}
|
|
FILTER IS_SAME_COLLECTION(${v1}, v) OR IS_SAME_COLLECTION(${v3}, v)
|
|
SORT v._id RETURN v._id`;
|
|
var actual = getRawQueryResults(query);
|
|
assertEqual(actual.length, 0);
|
|
},
|
|
|
|
testNeighborsInboundStartExampleRestrictEdgesAndVerticesMergeIntoEdges: function () {
|
|
var bindVars = {
|
|
name: gN,
|
|
'@eCol': e1
|
|
};
|
|
var query = `
|
|
${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN INBOUND start GRAPH @name OPTIONS {bfs: true, uniqueVertices: "global"}
|
|
FILTER IS_SAME_COLLECTION(${v1}, v) OR IS_SAME_COLLECTION(${v3}, v)
|
|
SORT v._id
|
|
FOR e in @@eCol
|
|
FILTER e._from == v._id
|
|
RETURN MERGE(e, {v_key: v._key, v_hugo: v.hugo, v_id: v._id})`;
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 2);
|
|
},
|
|
|
|
testNeighborsInboundStartExampleRestrictEdgesAndVerticesSubLoops: function () {
|
|
var bindVars = {
|
|
name: gN,
|
|
'@eCol': e1
|
|
};
|
|
var query = `
|
|
FOR edgeDoc in @@eCol
|
|
LET thisVertex = DOCUMENT(edgeDoc._to)
|
|
LET vertices = (
|
|
${AQL_PICK_START_EXAMPLE}
|
|
FOR v IN INBOUND start GRAPH @name OPTIONS {bfs: true, uniqueVertices: "global"}
|
|
FILTER IS_SAME_COLLECTION(${v1}, v) OR IS_SAME_COLLECTION(${v3}, v)
|
|
RETURN v)
|
|
FOR oneVertex IN vertices RETURN {hugo: thisVertex.hugo, neighborVertex: oneVertex}`;
|
|
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 4);
|
|
}
|
|
|
|
};
|
|
}
|
|
|
|
|
|
function ahuacatlQueryGeneralCommonTestSuite() {
|
|
|
|
var vertexIds = {};
|
|
|
|
var AQL_START_EVERYWHERE = `UNION((FOR x IN UnitTestsAhuacatlVertex1 RETURN x), (FOR x IN UnitTestsAhuacatlVertex2 RETURN x))`;
|
|
var startWithFilter = function (filter) {
|
|
return `UNION((FOR x IN UnitTestsAhuacatlVertex1 ${filter} RETURN x), (FOR x IN UnitTestsAhuacatlVertex2 ${filter} RETURN x))`;
|
|
};
|
|
|
|
return {
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief set up
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
setUpAll: function () {
|
|
db._drop("UnitTestsAhuacatlVertex1");
|
|
db._drop("UnitTestsAhuacatlVertex2");
|
|
db._drop("UnitTestsAhuacatlEdge1");
|
|
|
|
var vertex1 = db._create("UnitTestsAhuacatlVertex1");
|
|
var vertex2 = db._create("UnitTestsAhuacatlVertex2");
|
|
var edge1 = db._createEdgeCollection("UnitTestsAhuacatlEdge1");
|
|
|
|
var v1 = vertex1.save({ _key: "v1", hugo: true})._id;
|
|
var v2 = vertex1.save({ _key: "v2", hugo: true})._id;
|
|
var v3 = vertex1.save({ _key: "v3", heinz: 1})._id;
|
|
var v4 = vertex1.save({ _key: "v4", harald: "meier"})._id;
|
|
var v5 = vertex2.save({ _key: "v5", ageing: true})._id;
|
|
var v6 = vertex2.save({ _key: "v6", harald: "meier", ageing: true})._id;
|
|
var v7 = vertex2.save({ _key: "v7", harald: "meier"})._id;
|
|
var v8 = vertex2.save({ _key: "v8", heinz: 1, harald: "meier"})._id;
|
|
|
|
vertexIds.v1 = v1;
|
|
vertexIds.v2 = v2;
|
|
vertexIds.v3 = v3;
|
|
vertexIds.v4 = v4;
|
|
vertexIds.v5 = v5;
|
|
vertexIds.v6 = v6;
|
|
vertexIds.v7 = v7;
|
|
vertexIds.v8 = v8;
|
|
|
|
function makeEdge(from, to, collection) {
|
|
collection.save(from, to, { what: from.split("/")[1] + "->" + to.split("/")[1] });
|
|
}
|
|
|
|
makeEdge(v1, v2, edge1);
|
|
makeEdge(v2, v3, edge1);
|
|
makeEdge(v3, v5, edge1);
|
|
makeEdge(v2, v6, edge1);
|
|
makeEdge(v6, v7, edge1);
|
|
makeEdge(v4, v7, edge1);
|
|
makeEdge(v3, v7, edge1);
|
|
makeEdge(v8, v1, edge1);
|
|
makeEdge(v3, v5, edge1);
|
|
makeEdge(v3, v8, edge1);
|
|
|
|
try {
|
|
db._collection("_graphs").remove("_graphs/bla3");
|
|
} catch (ignore) {
|
|
}
|
|
graph._create(
|
|
"bla3",
|
|
graph._edgeDefinitions(
|
|
graph._relation("UnitTestsAhuacatlEdge1",
|
|
["UnitTestsAhuacatlVertex1", "UnitTestsAhuacatlVertex2"],
|
|
["UnitTestsAhuacatlVertex1", "UnitTestsAhuacatlVertex2"]
|
|
)
|
|
)
|
|
);
|
|
},
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief tear down
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
tearDownAll: function () {
|
|
db._drop("UnitTestsAhuacatlVertex1");
|
|
db._drop("UnitTestsAhuacatlVertex2");
|
|
db._drop("UnitTestsAhuacatlEdge1");
|
|
try {
|
|
db._collection("_graphs").remove("_graphs/bla3");
|
|
} catch (ignore) {
|
|
}
|
|
},
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks common neighbors
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
testCommonNeighbors: function () {
|
|
var query = `
|
|
LET n1 = (FOR n IN ANY 'UnitTestsAhuacatlVertex1/v3' GRAPH 'bla3' OPTIONS {bfs: true, uniqueVertices: "global"} RETURN n._id)
|
|
LET n2 = (FOR n IN ANY 'UnitTestsAhuacatlVertex2/v6' GRAPH 'bla3' OPTIONS {bfs: true, uniqueVertices: "global"} RETURN n._id)
|
|
LET common = INTERSECTION(n1, n2)
|
|
RETURN {left: 'UnitTestsAhuacatlVertex1/v3', right: 'UnitTestsAhuacatlVertex2/v6', neighbors: common}
|
|
`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 1);
|
|
assertEqual(actual[0].left, vertexIds.v3);
|
|
assertEqual(actual[0].right, vertexIds.v6);
|
|
assertEqual(actual[0].neighbors.sort(), [vertexIds.v2, vertexIds.v7].sort());
|
|
},
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks common neighbors
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
testCommonNeighborsIn: function () {
|
|
var query = `
|
|
FOR left IN ${AQL_START_EVERYWHERE}
|
|
LET n1 = (FOR n IN INBOUND left GRAPH 'bla3' OPTIONS {bfs: true, uniqueVertices: "global"} RETURN n._id)
|
|
FOR right IN ${AQL_START_EVERYWHERE}
|
|
FILTER left != right
|
|
LET n2 = (FOR n IN INBOUND right GRAPH 'bla3' OPTIONS {bfs: true, uniqueVertices: "global"} RETURN n._id)
|
|
LET neighbors = INTERSECTION(n1, n2)
|
|
FILTER LENGTH(neighbors) > 0
|
|
SORT left._id, right._id
|
|
RETURN {left: left._id, right: right._id, neighbors: neighbors}
|
|
`;
|
|
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 8, "We expect one entry for each pair of vertices having at least one common neighbor");
|
|
|
|
assertEqual(actual[0].left, vertexIds.v3);
|
|
assertEqual(actual[0].right, vertexIds.v6);
|
|
assertEqual(actual[0].neighbors.sort(), [vertexIds.v2].sort());
|
|
|
|
assertEqual(actual[1].left, vertexIds.v5);
|
|
assertEqual(actual[1].right, vertexIds.v7);
|
|
assertEqual(actual[1].neighbors.sort(), [vertexIds.v3].sort());
|
|
|
|
assertEqual(actual[2].left, vertexIds.v5);
|
|
assertEqual(actual[2].right, vertexIds.v8);
|
|
assertEqual(actual[2].neighbors.sort(), [vertexIds.v3].sort());
|
|
|
|
assertEqual(actual[3].left, vertexIds.v6);
|
|
assertEqual(actual[3].right, vertexIds.v3);
|
|
assertEqual(actual[3].neighbors.sort(), [vertexIds.v2].sort());
|
|
|
|
assertEqual(actual[4].left, vertexIds.v7);
|
|
assertEqual(actual[4].right, vertexIds.v5);
|
|
assertEqual(actual[4].neighbors.sort(), [vertexIds.v3].sort());
|
|
|
|
assertEqual(actual[5].left, vertexIds.v7);
|
|
assertEqual(actual[5].right, vertexIds.v8);
|
|
assertEqual(actual[5].neighbors.sort(), [vertexIds.v3].sort());
|
|
|
|
assertEqual(actual[6].left, vertexIds.v8);
|
|
assertEqual(actual[6].right, vertexIds.v5);
|
|
assertEqual(actual[6].neighbors.sort(), [vertexIds.v3].sort());
|
|
|
|
assertEqual(actual[7].left, vertexIds.v8);
|
|
assertEqual(actual[7].right, vertexIds.v7);
|
|
assertEqual(actual[7].neighbors.sort(), [vertexIds.v3].sort());
|
|
},
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks common neighbors
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
testCommonNeighborsOut: function () {
|
|
var query =`
|
|
FOR left IN ${startWithFilter("FILTER x.hugo == true")}
|
|
LET n1 = (FOR n IN 1..3 OUTBOUND left GRAPH 'bla3' RETURN DISTINCT n._id)
|
|
FOR right IN ${startWithFilter("FILTER x.heinz == 1")}
|
|
FILTER left != right
|
|
LET n2 = (FOR n IN 1..3 OUTBOUND right GRAPH 'bla3' RETURN DISTINCT n._id)
|
|
LET neighbors = INTERSECTION(n1, n2)
|
|
FILTER LENGTH(neighbors) > 0
|
|
SORT left._id, right._id
|
|
RETURN {left: left._id, right: right._id, neighbors: neighbors}`;
|
|
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 4, "Expect one result for each pair of vertices sharing neighbors");
|
|
|
|
assertEqual(actual[0].left, vertexIds.v1);
|
|
assertEqual(actual[0].right, vertexIds.v3);
|
|
assertEqual(actual[0].neighbors.sort(), [vertexIds.v2, vertexIds.v5, vertexIds.v7, vertexIds.v8].sort());
|
|
|
|
assertEqual(actual[1].left, vertexIds.v1);
|
|
assertEqual(actual[1].right, vertexIds.v8);
|
|
assertEqual(actual[1].neighbors.sort(), [vertexIds.v2, vertexIds.v3, vertexIds.v6].sort());
|
|
|
|
assertEqual(actual[2].left, vertexIds.v2);
|
|
assertEqual(actual[2].right, vertexIds.v3);
|
|
assertEqual(actual[2].neighbors.sort(), [vertexIds.v1, vertexIds.v5, vertexIds.v7, vertexIds.v8].sort());
|
|
|
|
assertEqual(actual[3].left, vertexIds.v2);
|
|
assertEqual(actual[3].right, vertexIds.v8);
|
|
assertEqual(actual[3].neighbors.sort(), [vertexIds.v1, vertexIds.v6, vertexIds.v3].sort());
|
|
},
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks common neighbors
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
testCommonNeighborsMixedOptionsDistinctFilters: function () {
|
|
var query = `
|
|
FOR left IN ${AQL_START_EVERYWHERE}
|
|
LET n1 = (FOR v IN OUTBOUND left GRAPH 'bla3' OPTIONS {bfs: true, uniqueVertices: "global"}
|
|
FILTER IS_SAME_COLLECTION(UnitTestsAhuacatlVertex1, v) RETURN v._id)
|
|
FOR right IN ${AQL_START_EVERYWHERE}
|
|
FILTER left != right
|
|
LET n2 = (FOR v IN 1..2 INBOUND right GRAPH 'bla3' OPTIONS {bfs: true, uniqueVertices: "global"}
|
|
FILTER IS_SAME_COLLECTION(UnitTestsAhuacatlVertex2, v) RETURN v._id)
|
|
LET neighbors = INTERSECTION(n1, n2)
|
|
FILTER LENGTH(neighbors) > 0
|
|
SORT left._id, right._id
|
|
RETURN {left: left._id, right: right._id, neighbors: neighbors}
|
|
`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 0, "Expect one result for each pair of vertices sharing neighbors");
|
|
},
|
|
|
|
testCommonNeighborsMixedOptionsFilterBasedOnOneCollectionOnly: function () {
|
|
var query = `
|
|
FOR left IN ${AQL_START_EVERYWHERE}
|
|
LET n1 = (FOR v IN OUTBOUND left GRAPH 'bla3' OPTIONS {bfs: true, uniqueVertices: "global"}
|
|
FILTER IS_SAME_COLLECTION(UnitTestsAhuacatlVertex2, v) RETURN v._id)
|
|
FOR right IN ${AQL_START_EVERYWHERE}
|
|
FILTER left != right
|
|
LET n2 = (FOR v IN 1..2 INBOUND right GRAPH 'bla3' OPTIONS {bfs: true, uniqueVertices: "global"}
|
|
FILTER IS_SAME_COLLECTION(UnitTestsAhuacatlVertex2, v) RETURN v._id)
|
|
LET neighbors = INTERSECTION(n1, n2)
|
|
FILTER LENGTH(neighbors) > 0
|
|
SORT left._id, right._id
|
|
RETURN {left: left._id, right: right._id, neighbors: neighbors}
|
|
`;
|
|
var actual = getQueryResults(query);
|
|
|
|
assertEqual(actual.length, 3, "Expect one result for each pair of vertices sharing neighbors");
|
|
assertEqual(actual[0].left, vertexIds.v2);
|
|
assertEqual(actual[0].right, vertexIds.v7);
|
|
assertEqual(actual[0].neighbors.sort(), [vertexIds.v6].sort());
|
|
|
|
assertEqual(actual[1].left, vertexIds.v3);
|
|
assertEqual(actual[1].right, vertexIds.v1);
|
|
assertEqual(actual[1].neighbors.sort(), [vertexIds.v8].sort());
|
|
|
|
assertEqual(actual[2].left, vertexIds.v3);
|
|
assertEqual(actual[2].right, vertexIds.v2);
|
|
assertEqual(actual[2].neighbors.sort(), [vertexIds.v8].sort());
|
|
},
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks common properties
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
testCommonProperties: function () {
|
|
var query = `FOR left IN ${AQL_START_EVERYWHERE}
|
|
SORT left._id
|
|
RETURN ZIP([left._id], [(FOR right IN ${AQL_START_EVERYWHERE}
|
|
FILTER left != right
|
|
LET shared = (FOR a IN ATTRIBUTES(left)
|
|
FILTER a != "_rev" AND (a == "_id"
|
|
OR left[a] == right[a])
|
|
RETURN a)
|
|
FILTER LENGTH(shared) > 1
|
|
RETURN KEEP(right, shared))]
|
|
)`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual[0]["UnitTestsAhuacatlVertex1/v1"].length, 1);
|
|
assertEqual(actual[1]["UnitTestsAhuacatlVertex1/v2"].length, 1);
|
|
assertEqual(actual[2]["UnitTestsAhuacatlVertex1/v3"].length, 1);
|
|
assertEqual(actual[3]["UnitTestsAhuacatlVertex1/v4"].length, 3);
|
|
|
|
assertEqual(actual[4]["UnitTestsAhuacatlVertex2/v5"].length, 1);
|
|
assertEqual(actual[5]["UnitTestsAhuacatlVertex2/v6"].length, 4);
|
|
|
|
assertEqual(actual[6]["UnitTestsAhuacatlVertex2/v7"].length, 3);
|
|
|
|
assertEqual(actual[7]["UnitTestsAhuacatlVertex2/v8"].length, 4);
|
|
|
|
},
|
|
|
|
testCommonPropertiesWithFilters: function () {
|
|
var query = `FOR left IN ${AQL_START_EVERYWHERE}
|
|
FILTER left.ageing == true
|
|
SORT left._id
|
|
RETURN ZIP([left._id], [(FOR right IN ${AQL_START_EVERYWHERE}
|
|
FILTER left != right
|
|
FILTER right.harald == "meier"
|
|
LET shared = (FOR a IN ATTRIBUTES(left)
|
|
FILTER a != "_rev" AND (a == "_id"
|
|
OR left[a] == right[a])
|
|
RETURN a)
|
|
FILTER LENGTH(shared) > 1
|
|
RETURN KEEP(right, shared))]
|
|
)`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual[0]["UnitTestsAhuacatlVertex2/v5"].length, 1);
|
|
assertEqual(actual[1]["UnitTestsAhuacatlVertex2/v6"].length, 3);
|
|
|
|
},
|
|
|
|
testCommonPropertiesWithFiltersAndIgnoringKeyHarald: function () {
|
|
var query = `FOR left IN ${AQL_START_EVERYWHERE}
|
|
SORT left._id
|
|
LET tmp = (FOR right IN ${AQL_START_EVERYWHERE}
|
|
FILTER left != right
|
|
LET shared = (FOR a IN ATTRIBUTES(left)
|
|
FILTER a != "_rev" AND a != "harald"
|
|
AND (a == "_id" OR left[a] == right[a])
|
|
RETURN a)
|
|
FILTER LENGTH(shared) > 1
|
|
RETURN KEEP(right, shared))
|
|
FILTER LENGTH(tmp) > 0
|
|
RETURN ZIP([left._id], [tmp])`;
|
|
var actual = getQueryResults(query);
|
|
|
|
assertEqual(actual[0]["UnitTestsAhuacatlVertex1/v1"].length, 1);
|
|
assertEqual(actual[1]["UnitTestsAhuacatlVertex1/v2"].length, 1);
|
|
assertEqual(actual[2]["UnitTestsAhuacatlVertex1/v3"].length, 1);
|
|
|
|
assertEqual(actual[3]["UnitTestsAhuacatlVertex2/v5"].length, 1);
|
|
|
|
assertEqual(actual[4]["UnitTestsAhuacatlVertex2/v6"].length, 1);
|
|
assertEqual(actual[5]["UnitTestsAhuacatlVertex2/v8"].length, 1);
|
|
|
|
}
|
|
};
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief test suite for SHORTEST PATH function
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
function ahuacatlQueryGeneralTraversalTestSuite() {
|
|
const v1 = "UnitTests_Berliner";
|
|
const v2 = "UnitTests_Hamburger";
|
|
const v3 = "UnitTests_Frankfurter";
|
|
const v4 = "UnitTests_Leipziger";
|
|
var vertexIds = {};
|
|
const graphName = "werKenntWen";
|
|
const AQL_START_EVERYWHERE = `UNION(
|
|
(FOR x IN ${v1} RETURN x),
|
|
(FOR x IN ${v2} RETURN x),
|
|
(FOR x IN ${v3} RETURN x),
|
|
(FOR x IN ${v4} RETURN x)
|
|
)`;
|
|
|
|
var startWithFilter = function (filter) {
|
|
return `UNION(
|
|
(FOR x IN ${v1} ${filter} RETURN x),
|
|
(FOR x IN ${v2} ${filter} RETURN x),
|
|
(FOR x IN ${v3} ${filter} RETURN x),
|
|
(FOR x IN ${v4} ${filter} RETURN x)
|
|
)`;
|
|
};
|
|
|
|
|
|
return {
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief set up
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
setUpAll: function () {
|
|
db._drop(v1);
|
|
db._drop(v2);
|
|
db._drop(v3);
|
|
db._drop(v4);
|
|
db._drop("UnitTests_KenntAnderenBerliner");
|
|
db._drop("UnitTests_KenntAnderen");
|
|
|
|
var KenntAnderenBerliner = "UnitTests_KenntAnderenBerliner";
|
|
var KenntAnderen = "UnitTests_KenntAnderen";
|
|
|
|
var Berlin = db._create(v1);
|
|
var Hamburg = db._create(v2);
|
|
var Frankfurt = db._create(v3);
|
|
var Leipzig = db._create(v4);
|
|
db._createEdgeCollection(KenntAnderenBerliner);
|
|
db._createEdgeCollection(KenntAnderen);
|
|
|
|
var Anton = Berlin.save({ _key: "Anton", gender: "male", age: 20});
|
|
var Berta = Berlin.save({ _key: "Berta", gender: "female", age: 25});
|
|
var Caesar = Hamburg.save({ _key: "Caesar", gender: "male", age: 30});
|
|
var Dieter = Hamburg.save({ _key: "Dieter", gender: "male", age: 20});
|
|
var Emil = Frankfurt.save({ _key: "Emil", gender: "male", age: 25});
|
|
var Fritz = Frankfurt.save({ _key: "Fritz", gender: "male", age: 30});
|
|
var Gerda = Leipzig.save({ _key: "Gerda", gender: "female", age: 40});
|
|
|
|
vertexIds.Anton = Anton._id;
|
|
vertexIds.Berta = Berta._id;
|
|
vertexIds.Caesar = Caesar._id;
|
|
vertexIds.Dieter = Dieter._id;
|
|
vertexIds.Emil = Emil._id;
|
|
vertexIds.Fritz = Fritz._id;
|
|
vertexIds.Gerda = Gerda._id;
|
|
|
|
try {
|
|
db._collection("_graphs").remove(graphName);
|
|
} catch (ignore) {
|
|
}
|
|
var g = graph._create(
|
|
graphName,
|
|
graph._edgeDefinitions(
|
|
graph._relation(KenntAnderenBerliner, v1, v1),
|
|
graph._relation(KenntAnderen,
|
|
[v1, v2, v3, v4],
|
|
[v1, v2, v3, v4]
|
|
)
|
|
)
|
|
);
|
|
|
|
function makeEdge(from, to, collection, distance) {
|
|
collection.save(from, to, { what: from.split("/")[1] + "->" + to.split("/")[1], entfernung: distance});
|
|
}
|
|
|
|
makeEdge(Berta._id, Anton._id, g[KenntAnderenBerliner], 0.1);
|
|
makeEdge(Caesar._id, Anton._id, g[KenntAnderen], 350);
|
|
makeEdge(Caesar._id, Berta._id, g[KenntAnderen], 250.1);
|
|
makeEdge(Berta._id, Gerda._id, g[KenntAnderen], 200);
|
|
makeEdge(Gerda._id, Dieter._id, g[KenntAnderen], "blub");
|
|
makeEdge(Dieter._id, Emil._id, g[KenntAnderen], 300);
|
|
makeEdge(Emil._id, Fritz._id, g[KenntAnderen], 0.2);
|
|
},
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief tear down
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
tearDownAll: function () {
|
|
graph._drop("werKenntWen", true);
|
|
},
|
|
|
|
testShortestPathWithGraphName: function () {
|
|
var query = `LET p = (FOR v, e IN OUTBOUND SHORTEST_PATH "${vertexIds.Caesar}" TO "${vertexIds.Emil}" GRAPH "${graphName}" RETURN {v: v._id, e: e._id})
|
|
LET edges = (FOR e IN p[*].e FILTER e != null RETURN e)
|
|
LET vertices = p[*].v
|
|
LET distance = LENGTH(edges)
|
|
RETURN {edges, vertices, distance}`;
|
|
|
|
var actual;
|
|
|
|
// Caesar -> Berta -> Gerda -> Dieter -> Emil
|
|
actual = getQueryResults(query);
|
|
assertEqual(actual.length, 1, "Exactly one element is returned");
|
|
var path = actual[0];
|
|
assertTrue(path.hasOwnProperty("vertices"), "The path contains all vertices");
|
|
assertTrue(path.hasOwnProperty("edges"), "The path contains all edges");
|
|
assertTrue(path.hasOwnProperty("distance"), "The path contains the distance");
|
|
assertEqual(path.vertices, [
|
|
vertexIds.Caesar, vertexIds.Berta, vertexIds.Gerda, vertexIds.Dieter, vertexIds.Emil
|
|
], "The correct shortest path is using these vertices");
|
|
assertEqual(path.distance, 4, "The distance is 1 per edge");
|
|
|
|
query = `
|
|
FOR source in ${AQL_START_EVERYWHERE}
|
|
FOR target in ${AQL_START_EVERYWHERE}
|
|
FILTER source != target
|
|
LET vertices = (FOR v, e IN INBOUND SHORTEST_PATH source TO target GRAPH "${graphName}" RETURN v._id)
|
|
FILTER LENGTH(vertices) > 0
|
|
LET distance = LENGTH(vertices) - 1
|
|
SORT source, target
|
|
RETURN {vertices, distance}`;
|
|
actual = getQueryResults(query);
|
|
assertEqual(actual.length, 17, "For each pair that has a shortest path one entry is required");
|
|
assertEqual(actual[0], {
|
|
vertices: [vertexIds.Anton, vertexIds.Berta],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[1], {
|
|
vertices: [vertexIds.Anton, vertexIds.Caesar],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[2], {
|
|
vertices: [vertexIds.Berta, vertexIds.Caesar],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[3], {
|
|
vertices: [vertexIds.Emil,vertexIds.Dieter, vertexIds.Gerda, vertexIds.Berta],
|
|
distance: 3
|
|
});
|
|
assertEqual(actual[4], {
|
|
vertices: [vertexIds.Emil, vertexIds.Dieter, vertexIds.Gerda, vertexIds.Berta, vertexIds.Caesar],
|
|
distance: 4
|
|
});
|
|
assertEqual(actual[5], {
|
|
vertices: [vertexIds.Emil, vertexIds.Dieter],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[6], {
|
|
vertices: [vertexIds.Emil, vertexIds.Dieter, vertexIds.Gerda],
|
|
distance: 2
|
|
});
|
|
assertEqual(actual[7], {
|
|
vertices: [vertexIds.Fritz, vertexIds.Emil,vertexIds.Dieter, vertexIds.Gerda, vertexIds.Berta],
|
|
distance: 4
|
|
});
|
|
assertEqual(actual[8], {
|
|
vertices: [vertexIds.Fritz, vertexIds.Emil],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[9], {
|
|
vertices: [vertexIds.Fritz, vertexIds.Emil, vertexIds.Dieter, vertexIds.Gerda, vertexIds.Berta, vertexIds.Caesar],
|
|
distance: 5
|
|
});
|
|
assertEqual(actual[10], {
|
|
vertices: [vertexIds.Fritz, vertexIds.Emil, vertexIds.Dieter],
|
|
distance: 2
|
|
});
|
|
assertEqual(actual[11], {
|
|
vertices: [vertexIds.Fritz, vertexIds.Emil, vertexIds.Dieter, vertexIds.Gerda],
|
|
distance: 3
|
|
});
|
|
assertEqual(actual[12], {
|
|
vertices: [vertexIds.Dieter, vertexIds.Gerda, vertexIds.Berta],
|
|
distance: 2
|
|
});
|
|
assertEqual(actual[13], {
|
|
vertices: [vertexIds.Dieter, vertexIds.Gerda, vertexIds.Berta, vertexIds.Caesar],
|
|
distance: 3
|
|
});
|
|
assertEqual(actual[14], {
|
|
vertices: [vertexIds.Dieter, vertexIds.Gerda],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[15], {
|
|
vertices: [vertexIds.Gerda, vertexIds.Berta],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[16], {
|
|
vertices: [vertexIds.Gerda, vertexIds.Berta, vertexIds.Caesar],
|
|
distance: 2
|
|
});
|
|
|
|
query = `FOR source IN ${AQL_START_EVERYWHERE}
|
|
FILTER source._id != "${vertexIds.Berta}"
|
|
LET vertices = (FOR v, e IN INBOUND SHORTEST_PATH source TO "${vertexIds.Berta}" GRAPH "${graphName}" RETURN v._id)
|
|
FILTER LENGTH(vertices) > 0
|
|
LET distance = LENGTH(vertices) - 1
|
|
SORT source
|
|
RETURN {vertices, distance}`;
|
|
actual = getQueryResults(query);
|
|
assertEqual(actual.length, 5, "For each pair that has a shortest path one entry is required");
|
|
assertEqual(actual[0], {
|
|
vertices: [vertexIds.Anton, vertexIds.Berta],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[1], {
|
|
vertices: [vertexIds.Emil, vertexIds.Dieter, vertexIds.Gerda, vertexIds.Berta],
|
|
distance: 3
|
|
});
|
|
assertEqual(actual[2], {
|
|
vertices: [vertexIds.Fritz, vertexIds.Emil, vertexIds.Dieter, vertexIds.Gerda, vertexIds.Berta],
|
|
distance: 4
|
|
});
|
|
assertEqual(actual[3], {
|
|
vertices: [vertexIds.Dieter, vertexIds.Gerda, vertexIds.Berta],
|
|
distance: 2
|
|
});
|
|
assertEqual(actual[4], {
|
|
vertices: [vertexIds.Gerda, vertexIds.Berta],
|
|
distance: 1
|
|
});
|
|
|
|
query = `FOR v IN OUTBOUND SHORTEST_PATH "${vertexIds.Caesar}" TO "${vertexIds.Anton}" GRAPH "${graphName}" OPTIONS {weightAttribute: "entfernung", defaultWeight: 80} RETURN v._id`;
|
|
actual = getQueryResults(query);
|
|
assertEqual(actual.length, 3);
|
|
|
|
query = `FOR v IN OUTBOUND SHORTEST_PATH "${vertexIds.Caesar}" TO "${vertexIds.Anton}" GRAPH "${graphName}" RETURN v._id`;
|
|
actual = getQueryResults(query);
|
|
assertEqual(actual.length, 2);
|
|
|
|
/*
|
|
COLLECT AGGREGATE does NOT work with non numeric values yet
|
|
query = `FOR v, e IN OUTBOUND SHORTEST_PATH "${vertexIds.Caesar}" TO "${vertexIds.Emil}" GRAPH "${graphName}" OPTIONS {weightAttribute: "entfernung", defaultWeight: 80} COLLECT AGGREGATE distance = SUM(e.entfernung) RETURN {vertex: "${vertexIds.Emil}", startVertex: "${vertexIds.Caesar}", distance: distance}`;
|
|
actual = getQueryResults(query);
|
|
assertEqual(actual,
|
|
[
|
|
{
|
|
vertex: vertexIds.Emil,
|
|
startVertex: vertexIds.Caesar,
|
|
distance: 830.1
|
|
}
|
|
]
|
|
);
|
|
*/
|
|
},
|
|
|
|
testFindShortestShortestPath: function () {
|
|
var query = `
|
|
FOR target IN ${startWithFilter("FILTER x.gender == 'female'")}
|
|
LET p = (FOR v IN INBOUND SHORTEST_PATH "${vertexIds.Fritz}" TO target GRAPH "${graphName}" RETURN v._id)
|
|
LET l = LENGTH(p)
|
|
FILTER l > 0
|
|
SORT l
|
|
LIMIT 1
|
|
RETURN {
|
|
distance: l - 1,
|
|
vertices: p
|
|
}
|
|
`;
|
|
var actual = getQueryResults(query);
|
|
// Find only one match, ignore the second one.
|
|
assertEqual(actual.length, 1);
|
|
// Find the right match
|
|
var path = actual[0];
|
|
assertEqual(path.distance, 3);
|
|
assertEqual(path.vertices, [
|
|
vertexIds.Fritz, vertexIds.Emil, vertexIds.Dieter, vertexIds.Gerda
|
|
]);
|
|
|
|
// Alternative (identical, in some cases this is more performant, in others the first one is better)
|
|
query = `
|
|
FOR v, e, p IN 1..1000 INBOUND "${vertexIds.Fritz}" GRAPH "${graphName}" OPTIONS {bfs: true}
|
|
FILTER v.gender == "female"
|
|
LIMIT 1
|
|
RETURN {
|
|
distance: LENGTH(p.edges),
|
|
vertices: p.vertices[*]._id
|
|
}`;
|
|
|
|
actual = getQueryResults(query);
|
|
// Find only one match, ignore the second one.
|
|
assertEqual(actual.length, 1);
|
|
// Find the right match
|
|
path = actual[0];
|
|
assertEqual(path.distance, 3);
|
|
assertEqual(path.vertices, [
|
|
vertexIds.Fritz, vertexIds.Emil, vertexIds.Dieter, vertexIds.Gerda
|
|
]);
|
|
},
|
|
|
|
testShortestPathWithExamples: function () {
|
|
var query = `
|
|
FOR start IN ${startWithFilter("FILTER x.gender == 'female'")}
|
|
FOR target IN ${startWithFilter("FILTER x.gender == 'male' AND x.age == 30")}
|
|
FILTER start != target
|
|
SORT start._id, target._id
|
|
LET p = (FOR v, e IN ANY SHORTEST_PATH start TO target GRAPH "${graphName}" RETURN {v: v._id, e: e._id})
|
|
LET edges = (FOR e IN p[*].e FILTER e != null RETURN e)
|
|
LET vertices = p[*].v
|
|
LET distance = LENGTH(edges)
|
|
FILTER distance > 0
|
|
RETURN {edges, vertices, distance}`;
|
|
var actual;
|
|
actual = getQueryResults(query);
|
|
assertEqual(actual.length, 4, "All connected pairs should have one entry.");
|
|
assertEqual(actual[0].vertices, [
|
|
vertexIds.Berta, vertexIds.Gerda, vertexIds.Dieter, vertexIds.Emil, vertexIds.Fritz
|
|
]);
|
|
assertEqual(actual[0].distance, 4);
|
|
|
|
assertEqual(actual[1].vertices, [
|
|
vertexIds.Berta, vertexIds.Caesar
|
|
]);
|
|
assertEqual(actual[1].distance, 1);
|
|
|
|
assertEqual(actual[2].vertices, [
|
|
vertexIds.Gerda, vertexIds.Dieter, vertexIds.Emil, vertexIds.Fritz
|
|
]);
|
|
assertEqual(actual[2].distance, 3);
|
|
|
|
assertEqual(actual[3].vertices, [
|
|
vertexIds.Gerda, vertexIds.Berta, vertexIds.Caesar
|
|
]);
|
|
assertEqual(actual[3].distance, 2);
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief test suite for and SHORTEST PATH function
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
function ahuacatlQueryGeneralCyclesSuite() {
|
|
|
|
const v1 = "UnitTests_Berliner";
|
|
const v2 = "UnitTests_Hamburger";
|
|
const v3 = "UnitTests_Frankfurter";
|
|
const v4 = "UnitTests_Leipziger";
|
|
var vertexIds = {};
|
|
|
|
const graphName = "werKenntWen";
|
|
const AQL_START_EVERYWHERE = `UNION(
|
|
(FOR x IN ${v1} RETURN x),
|
|
(FOR x IN ${v2} RETURN x),
|
|
(FOR x IN ${v3} RETURN x),
|
|
(FOR x IN ${v4} RETURN x)
|
|
)`;
|
|
|
|
return {
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief set up
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
setUpAll: function () {
|
|
db._drop(v1);
|
|
db._drop(v2);
|
|
db._drop(v3);
|
|
db._drop(v4);
|
|
db._drop("UnitTests_KenntAnderenBerliner");
|
|
db._drop("UnitTests_KenntAnderen");
|
|
|
|
var KenntAnderenBerliner = "UnitTests_KenntAnderenBerliner";
|
|
var KenntAnderen = "UnitTests_KenntAnderen";
|
|
|
|
var Berlin = db._create(v1);
|
|
var Hamburg = db._create(v2);
|
|
var Frankfurt = db._create(v3);
|
|
var Leipzig = db._create(v4);
|
|
db._createEdgeCollection(KenntAnderenBerliner);
|
|
db._createEdgeCollection(KenntAnderen);
|
|
|
|
var Anton = Berlin.save({ _key: "Anton", gender: "male", age: 20});
|
|
var Berta = Berlin.save({ _key: "Berta", gender: "female", age: 25});
|
|
var Caesar = Hamburg.save({ _key: "Caesar", gender: "male", age: 30});
|
|
Hamburg.save({ _key: "Dieter", gender: "male", age: 20});
|
|
Frankfurt.save({ _key: "Emil", gender: "male", age: 25});
|
|
var Fritz = Frankfurt.save({ _key: "Fritz", gender: "male", age: 30});
|
|
Leipzig.save({ _key: "Gerda", gender: "female", age: 40});
|
|
|
|
vertexIds.Anton = Anton._id;
|
|
vertexIds.Berta = Berta._id;
|
|
vertexIds.Caesar = Caesar._id;
|
|
vertexIds.Fritz = Fritz._id;
|
|
|
|
try {
|
|
db._collection("_graphs").remove(graphName);
|
|
} catch (ignore) {
|
|
}
|
|
var g = graph._create(
|
|
graphName,
|
|
graph._edgeDefinitions(
|
|
graph._relation(KenntAnderenBerliner, v1, v1),
|
|
graph._relation(KenntAnderen,
|
|
[v1, v2, v3, v4],
|
|
[v1, v2, v3, v4]
|
|
)
|
|
)
|
|
);
|
|
|
|
function makeEdge(from, to, collection, distance) {
|
|
collection.save(from, to, { what: from.split("/")[1] + "->" + to.split("/")[1], entfernung: distance});
|
|
}
|
|
|
|
makeEdge(Anton._id, Berta._id, g[KenntAnderen], 7);
|
|
makeEdge(Berta._id, Caesar._id, g[KenntAnderen], 8);
|
|
makeEdge(Anton._id, Fritz._id, g[KenntAnderen], 9);
|
|
makeEdge(Fritz._id, Caesar._id, g[KenntAnderen], 11);
|
|
makeEdge(Caesar._id, Berta._id, g[KenntAnderen], 2);
|
|
makeEdge(Berta._id, Anton._id, g[KenntAnderen], 3);
|
|
},
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief tear down
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
tearDownAll: 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 shortest path with graph name
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
testShortestPathWithGraphName: function () {
|
|
var actual;
|
|
var query = `
|
|
FOR source in ${AQL_START_EVERYWHERE}
|
|
FOR target in ${AQL_START_EVERYWHERE}
|
|
FILTER source != target
|
|
LET vertices = (FOR v, e IN INBOUND SHORTEST_PATH source TO target GRAPH "${graphName}" RETURN v._id)
|
|
FILTER LENGTH(vertices) > 0
|
|
LET distance = LENGTH(vertices) - 1
|
|
SORT source, target
|
|
RETURN {vertices, distance}`;
|
|
actual = getQueryResults(query);
|
|
assertEqual(actual.length, 12, "Expect one entry for every connected pair.");
|
|
assertEqual(actual[0], {
|
|
vertices: [vertexIds.Anton, vertexIds.Berta],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[1], {
|
|
vertices: [vertexIds.Anton, vertexIds.Berta, vertexIds.Caesar, vertexIds.Fritz],
|
|
distance: 3
|
|
});
|
|
assertEqual(actual[2], {
|
|
vertices: [vertexIds.Anton, vertexIds.Berta, vertexIds.Caesar],
|
|
distance: 2
|
|
});
|
|
assertEqual(actual[3], {
|
|
vertices: [vertexIds.Berta, vertexIds.Anton],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[4], {
|
|
vertices: [vertexIds.Berta, vertexIds.Caesar, vertexIds.Fritz],
|
|
distance: 2
|
|
});
|
|
assertEqual(actual[5], {
|
|
vertices: [vertexIds.Berta, vertexIds.Caesar],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[6], {
|
|
vertices: [vertexIds.Fritz, vertexIds.Anton],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[7], {
|
|
vertices: [vertexIds.Fritz, vertexIds.Anton, vertexIds.Berta],
|
|
distance: 2
|
|
});
|
|
assertEqual(actual[8], {
|
|
vertices: [vertexIds.Fritz, vertexIds.Anton, vertexIds.Berta, vertexIds.Caesar],
|
|
distance: 3
|
|
});
|
|
// we have two possible paths here.
|
|
assertEqual(actual[9].distance, 2);
|
|
assertEqual(actual[9].vertices[0], vertexIds.Caesar);
|
|
assertEqual(actual[9].vertices[2], vertexIds.Anton);
|
|
if (actual[9].vertices[1] !== vertexIds.Berta) {
|
|
assertEqual(actual[9].vertices[1], vertexIds.Fritz);
|
|
}
|
|
assertEqual(actual[10], {
|
|
vertices: [vertexIds.Caesar, vertexIds.Berta],
|
|
distance: 1
|
|
});
|
|
assertEqual(actual[11], {
|
|
vertices: [vertexIds.Caesar, vertexIds.Fritz],
|
|
distance: 1
|
|
});
|
|
}
|
|
|
|
};
|
|
}
|
|
|
|
function ahuacatlQueryMultiCollectionMadnessTestSuite() {
|
|
var gN = "UnitTestsAhuacatlGraph";
|
|
var v1 = "UnitTestsAhuacatlVertex1";
|
|
var v2 = "UnitTestsAhuacatlVertex2";
|
|
var v3 = "UnitTestsAhuacatlVertex3";
|
|
var e1 = "UnitTestsAhuacatlEdge1";
|
|
var e2 = "UnitTestsAhuacatlEdge2";
|
|
|
|
var s1;
|
|
var c1;
|
|
var t1;
|
|
var s2;
|
|
var c2;
|
|
var t2;
|
|
|
|
return {
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief set up
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
setUpAll: function () {
|
|
db._drop(v1);
|
|
db._drop(v2);
|
|
db._drop(v3);
|
|
db._drop(e1);
|
|
db._drop(e2);
|
|
|
|
var vertex1 = db._create(v1);
|
|
var vertex2 = db._create(v2);
|
|
var vertex3 = db._create(v3);
|
|
|
|
var edge1 = db._createEdgeCollection(e1);
|
|
var edge2 = db._createEdgeCollection(e2);
|
|
|
|
s1 = vertex1.save({ _key: "start"})._id;
|
|
c1 = vertex2.save({ _key: "center"})._id;
|
|
t1 = vertex3.save({ _key: "target"})._id;
|
|
s2 = vertex1.save({ _key: "start2"})._id;
|
|
c2 = vertex2.save({ _key: "center2"})._id;
|
|
t2 = vertex3.save({ _key: "target2"})._id;
|
|
|
|
function makeEdge(from, to, collection) {
|
|
collection.save(from, to, {});
|
|
}
|
|
|
|
makeEdge(s1, c1, edge1);
|
|
makeEdge(t1, c1, edge2);
|
|
makeEdge(s2, c2, edge1);
|
|
makeEdge(t2, c2, edge2);
|
|
makeEdge(t1, c2, edge2);
|
|
try {
|
|
graph._drop(gN);
|
|
} catch (ignore) {
|
|
}
|
|
graph._create(
|
|
gN,
|
|
graph._edgeDefinitions(
|
|
graph._relation(e1, v1, v2),
|
|
graph._relation(e2, v3, v2)
|
|
)
|
|
);
|
|
},
|
|
|
|
tearDownAll: function () {
|
|
graph._drop(gN, true);
|
|
},
|
|
|
|
testRestrictedPathHops1: function() {
|
|
var bindVars = {
|
|
start: s1
|
|
};
|
|
var query = `WITH ${v1}, ${v2}, ${v3}
|
|
FOR v IN 2 ANY @start ${e1}, ${e2}
|
|
FILTER IS_SAME_COLLECTION(${v3}, v)
|
|
SORT v._id
|
|
RETURN v`;
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 1);
|
|
assertEqual(actual[0]._id, t1);
|
|
},
|
|
|
|
testRestrictedPathHops2: function() {
|
|
var bindVars = {
|
|
start: s2
|
|
};
|
|
var query = `WITH ${v1}, ${v2}, ${v3}
|
|
FOR v IN 2 ANY @start ${e1}, ${e2}
|
|
FILTER IS_SAME_COLLECTION(${v3}, v)
|
|
SORT v._id
|
|
RETURN v`;
|
|
var actual = getRawQueryResults(query, bindVars);
|
|
assertEqual(actual.length, 2);
|
|
assertEqual(actual[0]._id, t1);
|
|
assertEqual(actual[1]._id, t2);
|
|
}
|
|
};
|
|
}
|
|
|
|
function ahuacatlQueryShortestPathTestSuite() {
|
|
|
|
const v1 = "UnitTestsAhuacatlVertex1";
|
|
const v2 = "UnitTestsAhuacatlVertex2";
|
|
const v3 = "UnitTestsAhuacatlVertex3";
|
|
const e1 = "UnitTestsAhuacatlEdge1";
|
|
const e2 = "UnitTestsAhuacatlEdge2";
|
|
const e3 = "UnitTestsAhuacatlEdge3";
|
|
const e4 = "UnitTestsAhuacatlEdge4";
|
|
|
|
const graphName = "abc";
|
|
|
|
return {
|
|
setUpAll: function () {
|
|
db._drop(v1);
|
|
db._drop(v2);
|
|
db._drop(v3);
|
|
db._drop(e1);
|
|
db._drop(e2);
|
|
db._drop(e3);
|
|
db._drop(e4);
|
|
|
|
var v1Col = db._create(v1);
|
|
var v2Col = db._create(v2);
|
|
var v3Col = db._create(v3);
|
|
db._createEdgeCollection(e1);
|
|
db._createEdgeCollection(e2);
|
|
db._createEdgeCollection(e3);
|
|
db._createEdgeCollection(e4);
|
|
|
|
var A = v1Col.save({ _key: "A"});
|
|
var B = v2Col.save({ _key: "B"});
|
|
var C = v3Col.save({ _key: "C"});
|
|
var D = v2Col.save({ _key: "D"});
|
|
var E = v3Col.save({ _key: "E"});
|
|
var F = v1Col.save({ _key: "F"});
|
|
|
|
try {
|
|
db._collection("_graphs").remove(graphName);
|
|
} catch (ignore) {
|
|
}
|
|
var g = graph._create(
|
|
graphName,
|
|
graph._edgeDefinitions(
|
|
graph._relation(e1, [v1, v2, v3], [v1, v2, v3]),
|
|
graph._relation(e2, [v1, v2, v3], [v1, v2, v3]),
|
|
graph._relation(e3, [v1, v2, v3], [v1, v2, v3]),
|
|
graph._relation(e4, [v1, v2, v3], [v1, v2, v3])
|
|
)
|
|
);
|
|
|
|
function makeEdge(from, to, collection, distance) {
|
|
collection.save(from, to, { what: from.split("/")[1] + "->" + to.split("/")[1], entfernung: distance});
|
|
}
|
|
|
|
makeEdge(A._id, B._id, g[e1], 4);
|
|
makeEdge(A._id, C._id, g[e2], 2);
|
|
makeEdge(B._id, C._id, g[e1], 5);
|
|
makeEdge(B._id, D._id, g[e3], 10);
|
|
makeEdge(C._id, E._id, g[e1], 3);
|
|
makeEdge(D._id, F._id, g[e4], 11);
|
|
makeEdge(E._id, D._id, g[e1], 4);
|
|
|
|
makeEdge(F._id, C._id, g[e1], 13);
|
|
makeEdge(F._id, E._id, g[e1], 6);
|
|
makeEdge(E._id, B._id, g[e1], 6);
|
|
makeEdge(C._id, A._id, g[e3], 2);
|
|
makeEdge(B._id, A._id, g[e2], 2);
|
|
},
|
|
|
|
tearDownAll: function () {
|
|
db._drop(v1);
|
|
db._drop(v2);
|
|
db._drop(v3);
|
|
db._drop(e1);
|
|
db._drop(e2);
|
|
db._drop(e3);
|
|
db._drop(e4);
|
|
db._collection("_graphs").remove(graphName);
|
|
},
|
|
|
|
testShortestPathAtoFoutbound: function () {
|
|
var query = `
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN OUTBOUND SHORTEST_PATH source TO target GRAPH "${graphName}" RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 4);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "B");
|
|
assertEqual(actual[1].e.entfernung, 4);
|
|
assertEqual(actual[2].v._key, "D");
|
|
assertEqual(actual[2].e.entfernung, 10);
|
|
assertEqual(actual[3].v._key, "F");
|
|
assertEqual(actual[3].e.entfernung, 11);
|
|
},
|
|
|
|
testShortestPathAtoFoutboundWeight: function () {
|
|
var query = `
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN OUTBOUND SHORTEST_PATH source TO target GRAPH "${graphName}" OPTIONS {weightAttribute: "entfernung", defaultWeight: 100} RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 5);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "C");
|
|
assertEqual(actual[1].e.entfernung, 2);
|
|
assertEqual(actual[2].v._key, "E");
|
|
assertEqual(actual[2].e.entfernung, 3);
|
|
assertEqual(actual[3].v._key, "D");
|
|
assertEqual(actual[3].e.entfernung, 4);
|
|
assertEqual(actual[4].v._key, "F");
|
|
assertEqual(actual[4].e.entfernung, 11);
|
|
},
|
|
|
|
testShortestPathAtoFoutboundEdgeCollectionRestriction: function () {
|
|
var query = `
|
|
WITH ${v1}, ${v2}, ${v3}
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN OUTBOUND SHORTEST_PATH source TO target ${e1},${e4} RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 6);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "B");
|
|
assertEqual(actual[1].e.entfernung, 4);
|
|
assertEqual(actual[2].v._key, "C");
|
|
assertEqual(actual[2].e.entfernung, 5);
|
|
assertEqual(actual[3].v._key, "E");
|
|
assertEqual(actual[3].e.entfernung, 3);
|
|
assertEqual(actual[4].v._key, "D");
|
|
assertEqual(actual[4].e.entfernung, 4);
|
|
assertEqual(actual[5].v._key, "F");
|
|
assertEqual(actual[5].e.entfernung, 11);
|
|
},
|
|
|
|
testShortestPathAtoFoutboundWeightEdgeCollectionRestriction: function () {
|
|
var query = `
|
|
WITH ${v1}, ${v2}, ${v3}
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN OUTBOUND SHORTEST_PATH source TO target ${e1},${e3},${e4} OPTIONS {weightAttribute: "entfernung", defaultWeight: 100} RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 4);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "B");
|
|
assertEqual(actual[1].e.entfernung, 4);
|
|
assertEqual(actual[2].v._key, "D");
|
|
assertEqual(actual[2].e.entfernung, 10);
|
|
assertEqual(actual[3].v._key, "F");
|
|
assertEqual(actual[3].e.entfernung, 11);
|
|
},
|
|
|
|
testShortestPathAtoFinbound: function () {
|
|
var query = `
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN INBOUND SHORTEST_PATH source TO target GRAPH "${graphName}" RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 3);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "C");
|
|
assertEqual(actual[1].e.entfernung, 2);
|
|
assertEqual(actual[2].v._key, "F");
|
|
assertEqual(actual[2].e.entfernung, 13);
|
|
},
|
|
|
|
testShortestPathAtoFinboundEdgeCollectionRestriction: function () {
|
|
var query = `
|
|
WITH ${v1}, ${v2}, ${v3}
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN INBOUND SHORTEST_PATH source TO target ${e1},${e2} RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 4);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "B");
|
|
assertEqual(actual[1].e.entfernung, 2);
|
|
assertEqual(actual[2].v._key, "E");
|
|
assertEqual(actual[2].e.entfernung, 6);
|
|
assertEqual(actual[3].v._key, "F");
|
|
assertEqual(actual[3].e.entfernung, 6);
|
|
},
|
|
|
|
testShortestPathAtoFinboundWeight: function () {
|
|
var query = `
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN INBOUND SHORTEST_PATH source TO target GRAPH "${graphName}" OPTIONS {weightAttribute: "entfernung", defaultWeight: 100} RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 4);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "B");
|
|
assertEqual(actual[1].e.entfernung, 2);
|
|
assertEqual(actual[2].v._key, "E");
|
|
assertEqual(actual[2].e.entfernung, 6);
|
|
assertEqual(actual[3].v._key, "F");
|
|
assertEqual(actual[3].e.entfernung, 6);
|
|
},
|
|
|
|
testShortestPathAtoFinboundWeightEdgeCollectionRestriction: function () {
|
|
var query = `
|
|
WITH ${v1}, ${v2}, ${v3}
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN INBOUND SHORTEST_PATH source TO target ${e1},${e3} OPTIONS {weightAttribute: "entfernung", defaultWeight: 100} RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 3);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "C");
|
|
assertEqual(actual[1].e.entfernung, 2);
|
|
assertEqual(actual[2].v._key, "F");
|
|
assertEqual(actual[2].e.entfernung, 13);
|
|
},
|
|
|
|
testShortestPathAtoFany: function () {
|
|
var query = `
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN ANY SHORTEST_PATH source TO target GRAPH "${graphName}" RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 3);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "C");
|
|
assertEqual(actual[1].e.entfernung, 2);
|
|
assertEqual(actual[2].v._key, "F");
|
|
assertEqual(actual[2].e.entfernung, 13);
|
|
},
|
|
|
|
testShortestPathAtoFanyEdgeCollectionRestriction: function () {
|
|
var query = `
|
|
WITH ${v1}, ${v2}, ${v3}
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN ANY SHORTEST_PATH source TO target ${e1} RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 4);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "B");
|
|
assertEqual(actual[1].e.entfernung, 4);
|
|
assertTrue(actual[2].v._key === "E" || actual[2].v._key === "C");
|
|
assertEqual(actual[3].v._key, "F");
|
|
if(actual[2].v._key === "E") {
|
|
assertEqual(actual[2].e.entfernung, 6);
|
|
assertEqual(actual[3].e.entfernung, 6);
|
|
} else if(actual[2].v._key === "C") {
|
|
assertEqual(actual[2].e.entfernung, 5);
|
|
assertEqual(actual[3].e.entfernung, 13);
|
|
}
|
|
},
|
|
|
|
testShortestPathAtoFanyWeight: function () {
|
|
var query = `
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN ANY SHORTEST_PATH source TO target GRAPH "${graphName}" OPTIONS {weightAttribute: "entfernung", defaultWeight: 100} RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 4);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "C");
|
|
assertEqual(actual[1].e.entfernung, 2);
|
|
assertEqual(actual[2].v._key, "E");
|
|
assertEqual(actual[2].e.entfernung, 3);
|
|
assertEqual(actual[3].v._key, "F");
|
|
assertEqual(actual[3].e.entfernung, 6);
|
|
},
|
|
|
|
testShortestPathAtoFanyWeightEdgeCollectionRestriction: function () {
|
|
var query = `
|
|
WITH ${v1}, ${v2}, ${v3}
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN ANY SHORTEST_PATH source TO target ${e1} OPTIONS {weightAttribute: "entfernung", defaultWeight: 100} RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 4);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "B");
|
|
assertEqual(actual[1].e.entfernung, 4);
|
|
assertEqual(actual[2].v._key, "E");
|
|
assertEqual(actual[2].e.entfernung, 6);
|
|
assertEqual(actual[3].v._key, "F");
|
|
assertEqual(actual[3].e.entfernung, 6);
|
|
},
|
|
|
|
testShortestPathAtoFdifferentDirections: function () {
|
|
var query = `
|
|
WITH ${v1}, ${v2}, ${v3}
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN OUTBOUND SHORTEST_PATH source TO target ${e1}, INBOUND ${e2},${e4} OPTIONS {weightAttribute: "entfernung", defaultWeight: 100} RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 6);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "B");
|
|
assertEqual(actual[1].e.entfernung, 2);
|
|
assertEqual(actual[2].v._key, "C");
|
|
assertEqual(actual[2].e.entfernung, 5);
|
|
assertEqual(actual[3].v._key, "E");
|
|
assertEqual(actual[3].e.entfernung, 3);
|
|
assertEqual(actual[4].v._key, "D");
|
|
assertEqual(actual[4].e.entfernung, 4);
|
|
assertEqual(actual[5].v._key, "F");
|
|
assertEqual(actual[5].e.entfernung, 11);
|
|
},
|
|
|
|
testShortestPathAtoFnoPath: function () {
|
|
var query = `
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN OUTBOUND SHORTEST_PATH source TO target ${e1} RETURN {v, e}`;
|
|
var actual = getQueryResults(query);
|
|
assertEqual(actual.length, 0);
|
|
},
|
|
|
|
testShortestPathAtoFwithDeletedVertex: function () {
|
|
db._collection(v2).remove({_key: "D"});
|
|
var query = `
|
|
LET source = "${v1}/A"
|
|
LET target = "${v1}/F"
|
|
FOR v, e IN OUTBOUND SHORTEST_PATH source TO target GRAPH "${graphName}" RETURN {v, e}`;
|
|
var full = AQL_EXECUTE(query);
|
|
var actual = full.json;
|
|
assertEqual(actual.length, 4);
|
|
assertEqual(actual[0].v._key, "A");
|
|
assertEqual(actual[0].e, null);
|
|
assertEqual(actual[1].v._key, "B");
|
|
assertEqual(actual[1].e.entfernung, 4);
|
|
assertEqual(actual[2].v, null);
|
|
assertEqual(actual[2].e.entfernung, 10);
|
|
assertEqual(actual[2].e._to, v2 + "/D");
|
|
assertEqual(actual[3].v._key, "F");
|
|
assertEqual(actual[3].e.entfernung, 11);
|
|
// We expect one warning
|
|
assertEqual(full.warnings.length, 1);
|
|
assertEqual(full.warnings[0].code, errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code);
|
|
}
|
|
|
|
};
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief executes the test suite
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
jsunity.run(ahuacatlQueryGeneralCommonTestSuite);
|
|
jsunity.run(ahuacatlQueryGeneralCyclesSuite);
|
|
jsunity.run(ahuacatlQueryGeneralTraversalTestSuite);
|
|
jsunity.run(ahuacatlQueryGeneralEdgesTestSuite);
|
|
jsunity.run(ahuacatlQueryMultiCollectionMadnessTestSuite);
|
|
jsunity.run(ahuacatlQueryShortestPathTestSuite);
|
|
|
|
return jsunity.done();
|
|
|