From ba90cd0b8ccfef4b611bea6a8f2bc0a5ea47b8ed Mon Sep 17 00:00:00 2001 From: Heiko Kernbach Date: Thu, 23 Apr 2020 16:43:04 +0200 Subject: [PATCH 1/8] init commit, added basic disjoint smart graph support --- run-small-disjoint-smart-graphs.js | 6 ++ test.js | 117 +++++++++++++++++++++++++++-- 2 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 run-small-disjoint-smart-graphs.js diff --git a/run-small-disjoint-smart-graphs.js b/run-small-disjoint-smart-graphs.js new file mode 100644 index 00000000..01920b18 --- /dev/null +++ b/run-small-disjoint-smart-graphs.js @@ -0,0 +1,6 @@ +function main () { + require("./test").test({small: true, disjointSmartGraphTests: true}); +} +if (typeof arango !== undefined) { + main(); +} diff --git a/test.js b/test.js index 611b00d6..3f6f2264 100644 --- a/test.js +++ b/test.js @@ -38,6 +38,7 @@ exports.test = function (global) { const supportsAnalyzers = !semver.satisfies(serverVersion, "3.5.0-rc.1 || 3.5.0-rc.2 || 3.5.0-rc.3"); const supportsSatelliteGraphs = semver.satisfies(serverVersion, ">=3.7.0-devel"); + const supportsDisjointSmartGraphs = semver.satisfies(serverVersion, ">=3.7.0-devel"); let silent = true; let testRunner = function (tests, options) { @@ -404,6 +405,9 @@ exports.test = function (global) { if (!supportsSatelliteGraphs) { print("Satellite graphs are not supported"); } + if (!supportsDisjointSmartGraphs) { + print("Disjoint Smart graphs are not supported"); + } function createSatelliteGraph(name) { let vertexCollectionName = name + "_vertex"; @@ -443,6 +447,36 @@ exports.test = function (global) { edges: db[edgesCollectionName] }; } + function createDisjointSmartGraph(name) { + const definition = (g, vertexCollectionName, edgesCollectionName) => { + return { + graph: g, + vertex: g[vertexCollectionName], + edges: db[edgesCollectionName] + }; + } + + let vertexCollectionName = name + "_vertex"; + let edgesCollectionName = name + "_edge"; + + var graph_module = require("@arangodb/smart-graph"); + if (graph_module._exists(name)) { + let g = graph_module._graph(name); + return definition(g, vertexCollectionName, edgesCollectionName); + } + + let opts = { + smartGraphAttribute: "myAwesomeSmartGraphValue", + isDisjoint: true, + numberOfShards + }; + + let g = graph_module._create( + name, [graph_module._relation(edgesCollectionName, vertexCollectionName, vertexCollectionName)], [], opts + ); + return definition(g, vertexCollectionName, edgesCollectionName); + } + function createCommunityGraph(name) { let vertexCollectionName = name + "_vertex"; let edgesCollectionName = name + "_edge"; @@ -473,8 +507,13 @@ exports.test = function (global) { print("Creating satellite graph"); satg = createSatelliteGraph("sat"); } + let dsg; + if (supportsDisjointSmartGraphs) { + print("Creating Disjoint Smart graph"); + dsg = createDisjointSmartGraph("disjointSmartGraph"); + } - if (!gc || !sg || (supportsSatelliteGraphs && !satg)) { + if (!gc || !sg || (supportsSatelliteGraphs && !satg) || (supportsDisjointSmartGraphs && !dsg)) { throw "failed to create graphs"; } @@ -1636,7 +1675,6 @@ exports.test = function (global) { // ///////////////////////////////////////////////////////////////////////////// genericSatelliteGraph = function (params) { - let bindParam = { "@c": params.collection, "g": params.graph, @@ -1654,6 +1692,22 @@ exports.test = function (global) { ); }, + genericDisjointSmartGraph = function (params) { + let bindParam = { + "@c": params.collection, + "g": params.graph, + "v": params.graph + "_vertex" + }; + + if ('bindParamModifier' in params) { + params.bindParamModifier(params, bindParam); + } + + db._query( + params.queryString, + bindParam, {} + ); + }, // ///////////////////////////////////////////////////////////////////////////// // main @@ -2453,20 +2507,64 @@ exports.test = function (global) { `, } } - - + ], + disjointSmartGraphTests = [ + { + name: "aql-traversal-index-join", + params: { func: genericDisjointSmartGraph, + queryString: ` + FOR v, e, p IN 1..3 OUTBOUND CONCAT(@v, "/smart0:test0") GRAPH @g + FOR doc in @@c + FILTER doc.value1 == v.value1 + RETURN doc + ` } + }, + { + name: "aql-traversal-graph", + params: { func: genericDisjointSmartGraph, + queryString: ` + FOR v, e, p IN 1..3 OUTBOUND CONCAT(@v, "/smart0:test0") GRAPH @g + return v`, + bindParamModifier: function(param, bindParam) { delete bindParam["@c"]; } + } + }, + { + name: "aql-index-traversal-graph", + params: { func: genericDisjointSmartGraph, + queryString: ` + for doc in @@c + filter doc.value1 >= 0 and doc.value1 <= 10 + let vkey = CONCAT(@v,"/smart", doc.value3, ":test", doc.value3) + for v, e, p in 1..4 outbound vkey graph @g + return {doc, p} + `, + } + }, + { + name: "aql-enum-collection-traversal-graph", + params: { func: genericDisjointSmartGraph, + queryString: ` + for doc in @@c + let vkey = CONCAT(@v,"/smart", doc.value3, ":test", doc.value3) + for v, e, p in 1..4 outbound vkey graph @g + filter v.value1 <= doc.value1 + return {doc, p} + `, + } + } ]; const runSatelliteGraphTests = (global.satelliteGraphTests && isEnterprise && isCluster); + const runDisjointSmartGraphTests = (global.disjointSmartGraphTests && isEnterprise && isCluster); if (global.documents || global.edges || global.search || - global.noMaterializationSearch || global.subqueryTests || runSatelliteGraphTests) { + global.noMaterializationSearch || global.subqueryTests || runSatelliteGraphTests || runDisjointSmartGraphTests) { initializeValuesCollection(); } if (global.edges || global.subqueryTests) { initializeEdgeCollection(); } - if (runSatelliteGraphTests) { + if (runSatelliteGraphTests || runDisjointSmartGraphTests) { initializeGraphs(); } if (global.search) { @@ -2855,6 +2953,13 @@ exports.test = function (global) { satelliteCase.params.graph = "sat"; satelliteTestsCases.push(satelliteCase); } + + if (supportsDisjointSmartGraphs) { + let disjointSmartCase = _.cloneDeep(item); + disjointSmartCase.name = disjointSmartCase.name + "-disjointSmart"; + disjointSmartCase.params.graph = "disjointSmartGraph"; + satelliteTestsCases.push(disjointSmartCase); + } }); let satelliteTestsResult = testRunner(satelliteTestsCases, options); From c6f656a7e1a1ed409a88bd7bf3b335cbc361aeae Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Fri, 24 Apr 2020 19:14:51 +0200 Subject: [PATCH 2/8] Added generator for Disjoint Graphs. No tests using these Graphs yet. ALso it seems the disjointGraph is not Disjoint --- test.js | 305 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 223 insertions(+), 82 deletions(-) diff --git a/test.js b/test.js index 3f6f2264..24174ff9 100644 --- a/test.js +++ b/test.js @@ -466,7 +466,7 @@ exports.test = function (global) { } let opts = { - smartGraphAttribute: "myAwesomeSmartGraphValue", + smartGraphAttribute: "value2", isDisjoint: true, numberOfShards }; @@ -495,99 +495,240 @@ exports.test = function (global) { edges: db[edgesCollectionName] }; } - - print("Creating community graph"); - let gc = createCommunityGraph("comm"); - - print("Creating smart graph"); - let sg = createSmartGraph("smart"); - - let satg; - if (supportsSatelliteGraphs) { - print("Creating satellite graph"); - satg = createSatelliteGraph("sat"); - } - let dsg; - if (supportsDisjointSmartGraphs) { - print("Creating Disjoint Smart graph"); - dsg = createDisjointSmartGraph("disjointSmartGraph"); - } - - if (!gc || !sg || (supportsSatelliteGraphs && !satg) || (supportsDisjointSmartGraphs && !dsg)) { - throw "failed to create graphs"; - } - - function fillGraphEdges (c, n, vc) { - print("Filling edges for ", c.name()) - let j = 0, - k = 50, - l = 0; - fillCollection(c, n, function(i) { - let obj = { - _key: "smart" + j + ":" + j + "_" + i + ":" + "smart" + i, - _from: vc.name() + "/smart" + j + ":test" + j, - _to: vc.name() + "/smart" + i + ":test" + i, - value: j + "-" + i}; - if (++l === k) { - ++j; + let createFullyConnectedGraph = () => { + print("Creating community graph"); + let gc = createCommunityGraph("comm"); + + print("Creating smart graph"); + let sg = createSmartGraph("smart"); + + let satg; + if (supportsSatelliteGraphs) { + print("Creating satellite graph"); + satg = createSatelliteGraph("sat"); + } + + if (!gc || !sg || (supportsSatelliteGraphs && !satg)) { + throw "failed to create graphs"; + } + + function fillGraphEdges(c, n, vc) { + print("Filling edges for ", c.name()) + let j = 0, + k = 50, l = 0; - k--; - if (k === 0) { - k = 50; + fillCollection(c, n, function (i) { + let obj = { + _key: "smart" + j + ":" + j + "_" + i + ":" + "smart" + i, + _from: vc.name() + "/smart" + j + ":test" + j, + _to: vc.name() + "/smart" + i + ":test" + i, + value: j + "-" + i + }; + if (++l === k) { + ++j; + l = 0; + k--; + if (k === 0) { + k = 50; + } } + return obj; + }); + } + + function fillGraphVertexes(c, n, g) { + print("Filling Vertexes for ", c.name()) + fillCollection(c, n, function (i) { + return { + _key: "smart" + i + ":test" + i, + value1: i, + value2: "smart" + i, + value3: i, + value4: "test" + i, + value5: i, + value6: "test" + i, + value7: i % g, + value8: "test" + (i % g) + }; + }); + } + + function createVertexes(n) { + let g = n / 100; + fillGraphVertexes(gc.vertex, n, g); + fillGraphVertexes(sg.vertex, n, g); + if (supportsSatelliteGraphs) { + fillGraphVertexes(satg.vertex, n, g); } - return obj; - }); - } + } + + function createEdges(n) { + fillGraphEdges(gc.edges, n, gc.vertex); + fillGraphEdges(sg.edges, n, sg.vertex); + if (supportsSatelliteGraphs) { + fillGraphEdges(satg.edges, n, satg.vertex); + } + } + + if (global.small) { + createVertexes(10000); + createEdges(10000); + } + + if (global.medium) { + createVertexes(100000); + createEdges(100000); + } + + if (global.big) { + createVertexes(1000000); + createEdges(1000000); + } + }; - function fillGraphVertexes (c, n, g) { - print("Filling Vertexes for ", c.name()) - fillCollection(c, n, function(i) { - return { - _key: "smart" + i + ":test" + i, - value1: i, - value2: "smart" + i, - value3: i, - value4: "test" + i, - value5: i, - value6: "test" + i, - value7: i % g, - value8: "test" + (i % g) + let createDisjointGraph = () => { + print("Creating community graph"); + let gc = createCommunityGraph("disjointcomm"); + + print("Creating smart graph"); + let sg = createSmartGraph("disjointsmart"); + + let satg; + if (supportsSatelliteGraphs) { + print("Creating satellite graph"); + satg = createSatelliteGraph("disjointsat"); + } + let dsg; + if (supportsDisjointSmartGraphs) { + print("Creating Disjoint Smart graph"); + dsg = createDisjointSmartGraph("disjointSmartGraph"); + } + + if (!gc || !sg || (supportsSatelliteGraphs && !satg) || (supportsDisjointSmartGraphs && !dsg)) { + throw "failed to create graphs"; + } + + // This is a seedable RandomNumberGenerator + // it is not operfect for Random numbers, + // but good enough for what we are doing here + function* RandomNumberGenerator(seed) { + while (true) { + const nextVal = Math.cos(seed++) * 10000; + yield nextVal - Math.floor(nextVal); + } + }; + + const fillGraph = (vCol, eCol, number, degree) => { + print('Filling graph'); + // Every graph uses the same Seed, so all graphs + // look identical + const rand = RandomNumberGenerator(42); + const getRandom = (min, max) => { + return Math.floor(rand.next().value * (max - min + 1)); + } + + let vertexGroups = []; + for (let i = 1; i < Math.floor(number / 1000); ++i) { + // create random sized groups of graphs. + // We randomly pick index borders + vertexGroups.push(getRandom(0, number)); + } + vertexGroups = vertexGroups.sort(); + print('Borders: ' + JSON.stringify(vertexGroups)); + + print("Filling Vertexes for ", vCol.name()); + const genSmartValue = (smartGroup) => { + return `smart${smartGroup}`; }; - }); - } + const genKey = (smartGroup, i) => { + return `${genSmartValue(smartGroup)}:test${i}`; + }; + const genId = (smartGroup, i) => { + return `${vCol.name()}/${genKey(smartGroup, i)}`; + }; + { + let smartGroup = 0; + fillCollection(vCol, number, (i) => { + if (smartGroup < vertexGroups.length && i >= vertexGroups[smartGroup]) { + // Group full, go to next group; + ++smartGroup; + } + return { + _key: genKey(smartGroup, i), + value1: i, + value2: genSmartValue(smartGroup), + value3: i, + value4: "test" + i, + value5: i, + value6: "test" + i, + value7: i % (number / 100), + value8: "test" + (i % (number / 100)) + }; + }); + } - function createVertexes(n) { - let g = n / 100; - fillGraphVertexes(gc.vertex, n, g); - fillGraphVertexes(sg.vertex, n, g); - if (supportsSatelliteGraphs) { - fillGraphVertexes(satg.vertex, n, g); + print("Filling Edges for ", eCol.name()); + { + let smartGroup = 0; + let counter = 0; + // We create degree * vertexes many edges into every vertex group. + // So in average every vertex has degree many edges. + fillCollection(eCol, number * degree, (i) => { + if (smartGroup < vertexGroups.length && Math.floor(i / degree) >= vertexGroups[smartGroup]) { + // All edges for group created, go to next group; + print(`SmartGroup: ${smartGroup} has ${counter} many edges`); + ++smartGroup; + counter = 0; + } + const [min, max] = (() => { + if (smartGroup === 0) { + return [0, vertexGroups[smartGroup]]; + } + if (smartGroup === vertexGroups.length) { + return [vertexGroups[smartGroup - 1], number]; + } + return [vertexGroups[smartGroup - 1], vertexGroups[smartGroup]]; + })(); + counter++; + const from = getRandom(min, max); + const to = getRandom(min, max); + return { + _from: genId(from), + _to: genId(to), + value: `${from}-${to}` + }; + }); + } + }; + + const createGraphs = (n) => { + const degree = 5; + fillGraph(gc.vertex, gc.edges, n, degree); + fillGraph(sg.vertex, sg.edges, n, degree); + if (supportsSatelliteGraphs) { + fillGraph(satg.vertex, satg.edges, n, degree); + } + if (supportsDisjointSmartGraphs) { + fillGraph(dsg.vertex, dsg.edges, n, degree); + } } - } - function createEdges(n) { - fillGraphEdges(gc.edges, n, gc.vertex); - fillGraphEdges(sg.edges, n, sg.vertex); - if (supportsSatelliteGraphs) { - fillGraphEdges(satg.edges, n, satg.vertex); + if (global.small) { + createGraphs(10000); } - } - if (global.small) { - createVertexes(10000); - createEdges(10000); - } + if (global.medium) { + createGraphs(100000); + } - if (global.medium) { - createVertexes(100000); - createEdges(100000); - } + if (global.big) { + createGraphs(1000000); + } + }; - if (global.big) { - createVertexes(1000000); - createEdges(1000000); - } + createFullyConnectedGraph(); + createDisjointGraph(); + }, initializePhrasesView = function () { From d60a104b67953bc4cf47a16501a74987df237a7b Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Mon, 27 Apr 2020 16:20:09 +0200 Subject: [PATCH 3/8] USe all parameters of a function please --- test.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test.js b/test.js index 24174ff9..e0b4ddd9 100644 --- a/test.js +++ b/test.js @@ -624,7 +624,7 @@ exports.test = function (global) { // look identical const rand = RandomNumberGenerator(42); const getRandom = (min, max) => { - return Math.floor(rand.next().value * (max - min + 1)); + return Math.floor(rand.next().value * (max - min + 1)) + min; } let vertexGroups = []; @@ -692,9 +692,11 @@ exports.test = function (global) { counter++; const from = getRandom(min, max); const to = getRandom(min, max); + + print(`Edge: ${from} -> ${to}, using [${min}, ${max}]`); return { - _from: genId(from), - _to: genId(to), + _from: genId(smartGroup, from), + _to: genId(smartGroup, to), value: `${from}-${to}` }; }); From e60083e2603dd37d85a10e905315467a84093230 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Mon, 27 Apr 2020 16:20:33 +0200 Subject: [PATCH 4/8] Removed debug output --- test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test.js b/test.js index e0b4ddd9..b771b253 100644 --- a/test.js +++ b/test.js @@ -692,8 +692,6 @@ exports.test = function (global) { counter++; const from = getRandom(min, max); const to = getRandom(min, max); - - print(`Edge: ${from} -> ${to}, using [${min}, ${max}]`); return { _from: genId(smartGroup, from), _to: genId(smartGroup, to), From 37c547bca97d87a8a72d037c32b449ba5829a339 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Tue, 28 Apr 2020 09:20:18 +0200 Subject: [PATCH 5/8] Removed debug output. Disjoint Graph now seems to be created correctly. Next up: Modify queries such that there is a list of random valid start vertices and we do a traversal for each of those --- test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test.js b/test.js index b771b253..e68bd362 100644 --- a/test.js +++ b/test.js @@ -676,7 +676,6 @@ exports.test = function (global) { fillCollection(eCol, number * degree, (i) => { if (smartGroup < vertexGroups.length && Math.floor(i / degree) >= vertexGroups[smartGroup]) { // All edges for group created, go to next group; - print(`SmartGroup: ${smartGroup} has ${counter} many edges`); ++smartGroup; counter = 0; } From 5984b56339d367dc4bb865f24b837e3ba7c62b81 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Wed, 29 Apr 2020 12:25:26 +0200 Subject: [PATCH 6/8] Refactored Disjoint SmartGraph creation to allow using the GraphObjects from within the Test code, this allows to generate start vertices more easily --- test.js | 4484 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 2304 insertions(+), 2180 deletions(-) diff --git a/test.js b/test.js index e68bd362..bf3947ad 100644 --- a/test.js +++ b/test.js @@ -40,6 +40,200 @@ exports.test = function (global) { const supportsSatelliteGraphs = semver.satisfies(serverVersion, ">=3.7.0-devel"); const supportsDisjointSmartGraphs = semver.satisfies(serverVersion, ">=3.7.0-devel"); + // This is a seedable RandomNumberGenerator + // it is not operfect for Random numbers, + // but good enough for what we are doing here + function* RandomNumberGenerator(seed) { + while (true) { + const nextVal = Math.cos(seed++) * 10000; + yield nextVal - Math.floor(nextVal); + } + }; + + class GraphGenerator { + constructor (nameprefix, type, runnerName, scale) { + this._rand = new RandomNumberGenerator(42); + this._name = `${nameprefix}${type}${runnerName}${scale}`; + this._runnerName = `${runnerName}-${scale}`; + switch (scale) { + case "small": + this._numVertices = 10000; + break; + case "medium": + this._numVertices = 100000; + break; + case "big": + this._numVertices = 1000000; + break; + default: + throw "Invalid scale for test"; + } + // This is a arbitrary number and defines the average amount of + // edges per vertex. + this._degree = 5; + if (isEnterprise) { + if (type === "satellite") { + this._module = require("@arangodb/satellite-graph"); + } else { + this._module = require("@arangodb/smart-graph"); + } + } else { + this._module = require("@arangodb/general-graph"); + } + + this._vertexGroups = []; + for (let i = 1; i < Math.floor(this._numVertices / 1000); ++i) { + // create random sized groups of graphs. + // We randomly pick index borders + this._vertexGroups.push(this.getRandom(0, this._numVertices)); + } + this._vertexGroups = this._vertexGroups.sort(); + + this._ensureDatastructure(type); + } + + _resetRand () { + this._rand = new RandomNumberGenerator(42); + } + + _ensureDatastructure (type) { + if (this._vCol) { + // already ensured + return; + } + const vertexCollectionName = `${this.name()}_vertex`; + const edgeCollectionName = `${this.name()}_edge`; + + if (this._module._exists(this.name())) { + this._graph = this._module._graph(this.name()); + this._needsData = false; + } else { + const rel = [this.graph_module._relation(edgeCollectionName, vertexCollectionName, vertexCollectionName)]; + const options = {}; + switch (type) { + case "comm": + case "satellite": + break; + case "disjoint": + options.isDisjoint = true; + // fallthrough intentional + case "smart": + options.smartGraphAttribute = "value2"; + options.numberOfShards = numberOfShards; + break; + } + this._graph = this._module._create(this.name(), rel, [], options); + this._needsData = true; + } + this._vCol = this._graph[vertexCollectionName]; + this._eCol = this._graph[edgeCollectionName]; + } + + vertexCollection () { + return this._vCol; + } + + edgeCollection () { + return this._eCol; + } + + numVertices () { + return this._numVertices; + } + + numEdges () { + return this._numVertices * this._degree; + } + + needsData () { + return this._needsData; + } + + dataProduced () { + this._needsData = false; + } + + getRandom (min, max) { + return Math.floor(this._rand.next().value * (max - min + 1)) + min; + } + + getSmartGroup (index) { + for (let i = 0; i < this._vertexGroups.length; ++i) { + if (index < this._vertexGroups[i]) { + // Find the first border that is higher than the given number + return i; + } + } + return this._vertexGroups.length; + } + + genSmartValue (smartGroup) { + return `smart${smartGroup}`; + } + + genKey (i) { + return `${this.genSmartValue(this.getSmartGroup(i))}:test${i}`; + } + + genId (i) { + return `${this._vCol.name()}/${this.genKey(i)}`; + } + + randomId () { + return this.getRandom(0, this._numVertices); + } + + getRandomStartVertices (length) { + // Make sure we always get the same seed, + // No matter how many operations have been + // done before. + this._resetRand(); + // Hihi Javascript + return Array.from({ length }).map(_ => this.genId(this.randomId())); + } + + vertexData (i) { + return { + _key: this.genKey(i), + value1: i, + value2: this.genSmartValue(this.getSmartGroup(i)), + value3: i, + value4: "test" + i, + value5: i, + value6: "test" + i, + value7: i % (this._numVertices / 100), + value8: "test" + (i % (this._numVertices / 100)) + }; + } + + edgeData (i) { + const smartGroup = this.getSmartGroup(Math.floor(i / this._degree)); + const [min, max] = (() => { + if (smartGroup === 0) { + return [0, this._vertexGroups[smartGroup] - 1]; + } + if (smartGroup === this._vertexGroups.length) { + return [this._vertexGroups[smartGroup - 1], this._numVertices - 1]; + } + return [this._vertexGroups[smartGroup - 1], this._vertexGroups[smartGroup] - 1]; + })(); + const from = this.getRandom(min, max); + const to = this.getRandom(min, max); + const fromId = this.genId(from); + const toId = this.genId(to); + print(fromId, toId); + return { + _from: this.genId(from), + _to: this.genId(to), + value: `${from}-${to}` + }; + } + + namePostfix () { + return this._runnerName; + } + } + let silent = true; let testRunner = function (tests, options) { let calc = function (values, options) { @@ -86,18 +280,18 @@ exports.test = function (global) { let measure = function (test, collection, options) { let timedExecution = function (test, collection) { - let params = buildParams(test, collection); - const start = time(); - if (typeof params.setupEachCall === "function") { - params.setupEachCall(params); - } - test.params.func(params); - let end = time(); - if (typeof params.teardownEachCall === "function") { - params.teardownEachCall(params); - } - return end - start; - }, + let params = buildParams(test, collection); + const start = time(); + if (typeof params.setupEachCall === "function") { + params.setupEachCall(params); + } + test.params.func(params); + let end = time(); + if (typeof params.teardownEachCall === "function") { + params.teardownEachCall(params); + } + return end - start; + }, results = []; internal.wait(1, true); @@ -217,8 +411,8 @@ exports.test = function (global) { fs.writeFileSync( fs.join(global.xmlDirectory, `pref-${name}.xml`), `` + 1000}" />` ); } }; @@ -237,7 +431,7 @@ exports.test = function (global) { return csv; }; - function createArangoSearch (params) { + function createArangoSearch(params) { if (db._view(params.name) !== null) { return; } @@ -252,7 +446,7 @@ exports.test = function (global) { db._createView(params.name, "arangosearch", meta); } - function fillCollection (c, n, generator, batchSize) { + function fillCollection(c, n, generator, batchSize) { batchSize = batchSize || 10000; let batch = []; @@ -273,7 +467,7 @@ exports.test = function (global) { } } - function fillEdgeCollection (c, n, vc) { + function fillEdgeCollection(c, n, vc) { let j = 0, k = 50, l = 0; @@ -296,8 +490,8 @@ exports.test = function (global) { }); } - function fillDocumentCollection (c, n, g) { - fillCollection (c, n, function (i) { + function fillDocumentCollection(c, n, g) { + fillCollection(c, n, function (i) { return { _key: "test" + i, value1: i, @@ -313,17 +507,17 @@ exports.test = function (global) { } let initializeValuesCollection = function () { - function createDocuments (n) { + function createDocuments(n) { let name = "values" + n; if (db._collection(name) !== null) { return; } db._drop(name); internal.print("creating collection " + name); - let c = db._create(name, {numberOfShards}), + let c = db._create(name, { numberOfShards }), g = n / 100; - fillDocumentCollection (c, n, g); + fillDocumentCollection(c, n, g); c.ensureIndex({ type: "hash", fields: ["value1"] }); c.ensureIndex({ type: "hash", fields: ["value2"] }); @@ -346,109 +540,108 @@ exports.test = function (global) { internal.wal.flush(true, true); }, - initializeView = function () { - function createView (n) { - let params = { - name: "v_values" + n, - collections: ["values" + n], - analyzers: ["identity"], - storedValues: [] - }; - - createArangoSearch(params); - } - - if (global.small) { - createView(10000); - } + initializeView = function () { + function createView(n) { + let params = { + name: "v_values" + n, + collections: ["values" + n], + analyzers: ["identity"], + storedValues: [] + }; - if (global.medium) { - createView(100000); - } + createArangoSearch(params); + } - if (global.big) { - createView(1000000); - } + if (global.small) { + createView(10000); + } - internal.wal.flush(true, true); - }, + if (global.medium) { + createView(100000); + } - initializeEdgeCollection = function () { - function createEdges (n) { - let name = "edges" + n; - if (db._collection(name) !== null) { - return; + if (global.big) { + createView(1000000); } - db._drop(name); - internal.print("creating collection " + name); - let c = db._createEdgeCollection(name, {numberOfShards}); - fillEdgeCollection (c, n, db._collection("values" + n)); - } - if (global.small) { - createEdges(10000); - } + internal.wal.flush(true, true); + }, - if (global.medium) { - createEdges(100000); - } + initializeEdgeCollection = function () { + function createEdges(n) { + let name = "edges" + n; + if (db._collection(name) !== null) { + return; + } + db._drop(name); + internal.print("creating collection " + name); + let c = db._createEdgeCollection(name, { numberOfShards }); + fillEdgeCollection(c, n, db._collection("values" + n)); + } - if (global.big) { - createEdges(1000000); - } + if (global.small) { + createEdges(10000); + } - internal.wal.flush(true, true); - }, + if (global.medium) { + createEdges(100000); + } - initializeGraphs = function() { + if (global.big) { + createEdges(1000000); + } - if (!supportsSatelliteGraphs) { - print("Satellite graphs are not supported"); - } - if (!supportsDisjointSmartGraphs) { - print("Disjoint Smart graphs are not supported"); - } + internal.wal.flush(true, true); + }, - function createSatelliteGraph(name) { - let vertexCollectionName = name + "_vertex"; - let edgesCollectionName = name + "_edge"; + initializeGraphs = function () { - var graph_module = require("@arangodb/satellite-graph"); - if (graph_module._exists(name)) { - let g = graph_module._graph(name); - return { graph: g, - vertex: g[vertexCollectionName], - edges: db[edgesCollectionName] }; + if (!supportsSatelliteGraphs) { + print("Satellite graphs are not supported"); + } + if (!supportsDisjointSmartGraphs) { + print("Disjoint Smart graphs are not supported"); } - let g = graph_module._create(name, [ graph_module._relation(edgesCollectionName, vertexCollectionName, vertexCollectionName)], [], {}); - return { graph: g, - vertex: g[vertexCollectionName], - edges: db[edgesCollectionName] }; - } + function createSatelliteGraph(name) { + let vertexCollectionName = name + "_vertex"; + let edgesCollectionName = name + "_edge"; - function createSmartGraph(name) { - let vertexCollectionName = name + "_vertex"; - let edgesCollectionName = name + "_edge"; + var graph_module = require("@arangodb/satellite-graph"); + if (graph_module._exists(name)) { + let g = graph_module._graph(name); + return { + graph: g, + vertex: g[vertexCollectionName], + edges: db[edgesCollectionName] + }; + } - var graph_module = require("@arangodb/smart-graph"); - if (graph_module._exists(name)) { - let g = graph_module._graph(name); - return { graph: g, + let g = graph_module._create(name, [graph_module._relation(edgesCollectionName, vertexCollectionName, vertexCollectionName)], [], {}); + return { + graph: g, vertex: g[vertexCollectionName], - edges: db[edgesCollectionName] }; + edges: db[edgesCollectionName] + }; } - let opts = {smartGraphAttribute: "value2", numberOfShards }; + function createSmartGraph(name) { + let vertexCollectionName = name + "_vertex"; + let edgesCollectionName = name + "_edge"; - let g = graph_module._create(name, [ graph_module._relation(edgesCollectionName, vertexCollectionName, vertexCollectionName)], [], opts); - return { graph: g, - vertex: g[vertexCollectionName], - edges: db[edgesCollectionName] }; - } + var graph_module = require("@arangodb/smart-graph"); + if (graph_module._exists(name)) { + let g = graph_module._graph(name); + return { + graph: g, + vertex: g[vertexCollectionName], + edges: db[edgesCollectionName] + }; + } - function createDisjointSmartGraph(name) { - const definition = (g, vertexCollectionName, edgesCollectionName) => { + let opts = { smartGraphAttribute: "value2", numberOfShards }; + + let g = graph_module._create(name, [graph_module._relation(edgesCollectionName, vertexCollectionName, vertexCollectionName)], [], opts); return { graph: g, vertex: g[vertexCollectionName], @@ -456,649 +649,536 @@ exports.test = function (global) { }; } - let vertexCollectionName = name + "_vertex"; - let edgesCollectionName = name + "_edge"; - - var graph_module = require("@arangodb/smart-graph"); - if (graph_module._exists(name)) { - let g = graph_module._graph(name); - return definition(g, vertexCollectionName, edgesCollectionName); - } - - let opts = { - smartGraphAttribute: "value2", - isDisjoint: true, - numberOfShards - }; - - let g = graph_module._create( - name, [graph_module._relation(edgesCollectionName, vertexCollectionName, vertexCollectionName)], [], opts - ); - return definition(g, vertexCollectionName, edgesCollectionName); - } + function createCommunityGraph(name) { + let vertexCollectionName = name + "_vertex"; + let edgesCollectionName = name + "_edge"; - function createCommunityGraph(name) { - let vertexCollectionName = name + "_vertex"; - let edgesCollectionName = name + "_edge"; + var graph_module = require("@arangodb/general-graph"); + if (graph_module._exists(name)) { + let g = graph_module._graph(name); + return { + graph: g, + vertex: g[vertexCollectionName], + edges: db[edgesCollectionName] + }; + } - var graph_module = require("@arangodb/general-graph"); - if (graph_module._exists(name)) { - let g = graph_module._graph(name); - return { graph: g, + let g = graph_module._create(name, [graph_module._relation(edgesCollectionName, vertexCollectionName, vertexCollectionName)], [], {}); + return { + graph: g, vertex: g[vertexCollectionName], - edges: db[edgesCollectionName] }; + edges: db[edgesCollectionName] + }; } - let g = graph_module._create(name, [ graph_module._relation(edgesCollectionName, vertexCollectionName, vertexCollectionName)], [], {}); - return { graph: g, - vertex: g[vertexCollectionName], - edges: db[edgesCollectionName] }; - } - - let createFullyConnectedGraph = () => { - print("Creating community graph"); - let gc = createCommunityGraph("comm"); + let createFullyConnectedGraph = () => { + print("Creating community graph"); + let gc = createCommunityGraph("comm"); - print("Creating smart graph"); - let sg = createSmartGraph("smart"); + print("Creating smart graph"); + let sg = createSmartGraph("smart"); - let satg; - if (supportsSatelliteGraphs) { - print("Creating satellite graph"); - satg = createSatelliteGraph("sat"); - } + let satg; + if (supportsSatelliteGraphs) { + print("Creating satellite graph"); + satg = createSatelliteGraph("sat"); + } - if (!gc || !sg || (supportsSatelliteGraphs && !satg)) { - throw "failed to create graphs"; - } + if (!gc || !sg || (supportsSatelliteGraphs && !satg)) { + throw "failed to create graphs"; + } - function fillGraphEdges(c, n, vc) { - print("Filling edges for ", c.name()) - let j = 0, - k = 50, - l = 0; - fillCollection(c, n, function (i) { - let obj = { - _key: "smart" + j + ":" + j + "_" + i + ":" + "smart" + i, - _from: vc.name() + "/smart" + j + ":test" + j, - _to: vc.name() + "/smart" + i + ":test" + i, - value: j + "-" + i - }; - if (++l === k) { - ++j; + function fillGraphEdges(c, n, vc) { + print("Filling edges for ", c.name()) + let j = 0, + k = 50, l = 0; - k--; - if (k === 0) { - k = 50; + fillCollection(c, n, function (i) { + let obj = { + _key: "smart" + j + ":" + j + "_" + i + ":" + "smart" + i, + _from: vc.name() + "/smart" + j + ":test" + j, + _to: vc.name() + "/smart" + i + ":test" + i, + value: j + "-" + i + }; + if (++l === k) { + ++j; + l = 0; + k--; + if (k === 0) { + k = 50; + } } - } - return obj; - }); - } - - function fillGraphVertexes(c, n, g) { - print("Filling Vertexes for ", c.name()) - fillCollection(c, n, function (i) { - return { - _key: "smart" + i + ":test" + i, - value1: i, - value2: "smart" + i, - value3: i, - value4: "test" + i, - value5: i, - value6: "test" + i, - value7: i % g, - value8: "test" + (i % g) - }; - }); - } - - function createVertexes(n) { - let g = n / 100; - fillGraphVertexes(gc.vertex, n, g); - fillGraphVertexes(sg.vertex, n, g); - if (supportsSatelliteGraphs) { - fillGraphVertexes(satg.vertex, n, g); + return obj; + }); } - } - function createEdges(n) { - fillGraphEdges(gc.edges, n, gc.vertex); - fillGraphEdges(sg.edges, n, sg.vertex); - if (supportsSatelliteGraphs) { - fillGraphEdges(satg.edges, n, satg.vertex); + function fillGraphVertexes(c, n, g) { + print("Filling Vertexes for ", c.name()) + fillCollection(c, n, function (i) { + return { + _key: "smart" + i + ":test" + i, + value1: i, + value2: "smart" + i, + value3: i, + value4: "test" + i, + value5: i, + value6: "test" + i, + value7: i % g, + value8: "test" + (i % g) + }; + }); } - } - - if (global.small) { - createVertexes(10000); - createEdges(10000); - } - if (global.medium) { - createVertexes(100000); - createEdges(100000); - } + function createVertexes(n) { + let g = n / 100; + fillGraphVertexes(gc.vertex, n, g); + fillGraphVertexes(sg.vertex, n, g); + if (supportsSatelliteGraphs) { + fillGraphVertexes(satg.vertex, n, g); + } + } - if (global.big) { - createVertexes(1000000); - createEdges(1000000); - } - }; - - let createDisjointGraph = () => { - print("Creating community graph"); - let gc = createCommunityGraph("disjointcomm"); + function createEdges(n) { + fillGraphEdges(gc.edges, n, gc.vertex); + fillGraphEdges(sg.edges, n, sg.vertex); + if (supportsSatelliteGraphs) { + fillGraphEdges(satg.edges, n, satg.vertex); + } + } - print("Creating smart graph"); - let sg = createSmartGraph("disjointsmart"); + if (global.small) { + createVertexes(10000); + createEdges(10000); + } - let satg; - if (supportsSatelliteGraphs) { - print("Creating satellite graph"); - satg = createSatelliteGraph("disjointsat"); - } - let dsg; - if (supportsDisjointSmartGraphs) { - print("Creating Disjoint Smart graph"); - dsg = createDisjointSmartGraph("disjointSmartGraph"); - } + if (global.medium) { + createVertexes(100000); + createEdges(100000); + } - if (!gc || !sg || (supportsSatelliteGraphs && !satg) || (supportsDisjointSmartGraphs && !dsg)) { - throw "failed to create graphs"; - } - - // This is a seedable RandomNumberGenerator - // it is not operfect for Random numbers, - // but good enough for what we are doing here - function* RandomNumberGenerator(seed) { - while (true) { - const nextVal = Math.cos(seed++) * 10000; - yield nextVal - Math.floor(nextVal); + if (global.big) { + createVertexes(1000000); + createEdges(1000000); } }; - const fillGraph = (vCol, eCol, number, degree) => { - print('Filling graph'); - // Every graph uses the same Seed, so all graphs - // look identical - const rand = RandomNumberGenerator(42); - const getRandom = (min, max) => { - return Math.floor(rand.next().value * (max - min + 1)) + min; - } + let createDisjointGraph = () => { + const prefix = "disjoint"; + let graphs = []; + const buildGraph = (prefix, type, runnerName, scale) => { + print(`Creating ${runnerName} graph`); + let graph = new GraphGenerator(prefix, type, runnerName, scale); + if (graph.needsData()) { + print(`Filling ${runnerName} graph`); - let vertexGroups = []; - for (let i = 1; i < Math.floor(number / 1000); ++i) { - // create random sized groups of graphs. - // We randomly pick index borders - vertexGroups.push(getRandom(0, number)); - } - vertexGroups = vertexGroups.sort(); - print('Borders: ' + JSON.stringify(vertexGroups)); - - print("Filling Vertexes for ", vCol.name()); - const genSmartValue = (smartGroup) => { - return `smart${smartGroup}`; - }; - const genKey = (smartGroup, i) => { - return `${genSmartValue(smartGroup)}:test${i}`; - }; - const genId = (smartGroup, i) => { - return `${vCol.name()}/${genKey(smartGroup, i)}`; + print(`Filling Vertexes for ${graph.vertexCollection().name()}`); + fillCollection(graph.vertexCollection(), graph.numVertices(), graph.vertexData.bind(graph)); + + print(`Filling Edges for ${graph.edgeCollection().name()}`); + fillCollection(graph.edgeCollection(), graph.numEdges(), graph.edgeData.bind(graph)); + + } }; - { - let smartGroup = 0; - fillCollection(vCol, number, (i) => { - if (smartGroup < vertexGroups.length && i >= vertexGroups[smartGroup]) { - // Group full, go to next group; - ++smartGroup; - } - return { - _key: genKey(smartGroup, i), - value1: i, - value2: genSmartValue(smartGroup), - value3: i, - value4: "test" + i, - value5: i, - value6: "test" + i, - value7: i % (number / 100), - value8: "test" + (i % (number / 100)) - }; - }); - } - print("Filling Edges for ", eCol.name()); - { - let smartGroup = 0; - let counter = 0; - // We create degree * vertexes many edges into every vertex group. - // So in average every vertex has degree many edges. - fillCollection(eCol, number * degree, (i) => { - if (smartGroup < vertexGroups.length && Math.floor(i / degree) >= vertexGroups[smartGroup]) { - // All edges for group created, go to next group; - ++smartGroup; - counter = 0; + const addGraphsForScale = (scale) => { + graphs.push(buildGraph(prefix, "comm", "community", scale)); + if (isEnterprise) { + graphs.push(buildGraph(prefix, "smart", "smart", scale)); + if (supportsSatelliteGraphs) { + graphs.push(buildGraph(prefix, "sat", "satellite", scale)); } - const [min, max] = (() => { - if (smartGroup === 0) { - return [0, vertexGroups[smartGroup]]; - } - if (smartGroup === vertexGroups.length) { - return [vertexGroups[smartGroup - 1], number]; - } - return [vertexGroups[smartGroup - 1], vertexGroups[smartGroup]]; - })(); - counter++; - const from = getRandom(min, max); - const to = getRandom(min, max); - return { - _from: genId(smartGroup, from), - _to: genId(smartGroup, to), - value: `${from}-${to}` - }; - }); + if (supportsDisjointSmartGraphs) { + graphs.push(buildGraph(prefix, "disjoint", "disjoint-smart", scale)); + } + } + }; + + if (global.small) { + addGraphsForScale("small"); } - }; - - const createGraphs = (n) => { - const degree = 5; - fillGraph(gc.vertex, gc.edges, n, degree); - fillGraph(sg.vertex, sg.edges, n, degree); - if (supportsSatelliteGraphs) { - fillGraph(satg.vertex, satg.edges, n, degree); + if (global.medium) { + addGraphsForScale("medium"); } - if (supportsDisjointSmartGraphs) { - fillGraph(dsg.vertex, dsg.edges, n, degree); + if (global.big) { + addGraphsForScale("big"); } - } + return graphs; + }; - if (global.small) { - createGraphs(10000); - } + createFullyConnectedGraph(); + return createDisjointGraph(); + + }, - if (global.medium) { - createGraphs(100000); - } + initializePhrasesView = function () { + function createPhrasesView(n) { + if (!supportsAnalyzers) { + return; + } - if (global.big) { - createGraphs(1000000); + let params = { + name: "v_valuesPhrases" + n, + collections: ["valuesPhrases" + n], + analyzers: ["text_en"], + storedValues: [] + }; + + createArangoSearch(params); } - }; - createFullyConnectedGraph(); - createDisjointGraph(); - - }, - - initializePhrasesView = function () { - function createPhrasesView (n) { - if (!supportsAnalyzers) { - return; - } - - let params = { - name: "v_valuesPhrases" + n, - collections: ["valuesPhrases" + n], - analyzers: ["text_en"], - storedValues: [] - }; - - createArangoSearch(params); - } - - function createDocumentsWithPhrases (n) { - let name = "valuesPhrases" + n; - if (db._collection(name) !== null) { - return; - } - db._drop(name); + function createDocumentsWithPhrases(n) { + let name = "valuesPhrases" + n; + if (db._collection(name) !== null) { + return; + } + db._drop(name); + + internal.print("creating collection " + name); + let c = db._create(name, { numberOfShards }), + // Short list. Phrases appear frequently + phrasesHigh = ["Quick ", "Brown ", "Slow ", "Fast "], + highPhraseCounter = 0, + // Long list. Phrases appear less frequent + phrasesLow = [ + "Red ", + "Hot ", + "Chilie ", + "Peppers ", + "Abbey ", + "Road ", + "Earth ", + "World ", + "Planet ", + "Tree ", + "Bee ", + "Yesterday ", + "Book ", + "Pencil ", + "Robot ", + "Wheel " + ], + lowPhraseCounter = 0; - internal.print("creating collection " + name); - let c = db._create(name, {numberOfShards}), - // Short list. Phrases appear frequently - phrasesHigh = ["Quick ", "Brown ", "Slow ", "Fast "], - highPhraseCounter = 0, - // Long list. Phrases appear less frequent - phrasesLow = [ - "Red ", - "Hot ", - "Chilie ", - "Peppers ", - "Abbey ", - "Road ", - "Earth ", - "World ", - "Planet ", - "Tree ", - "Bee ", - "Yesterday ", - "Book ", - "Pencil ", - "Robot ", - "Wheel " - ], - lowPhraseCounter = 0; + for (let i = 0; i < n; ++i) { + c.insert({ + _key: "testPhrase" + i, + value2: + phrasesHigh[highPhraseCounter] + phrasesLow[lowPhraseCounter] + }); + ++highPhraseCounter; + ++lowPhraseCounter; + // loop over our phrases + if (highPhraseCounter >= phrasesHigh.length) { + highPhraseCounter = 0; + } + if (lowPhraseCounter >= phrasesLow.length) { + lowPhraseCounter = 0; + } + } - for (let i = 0; i < n; ++i) { + // And some really low frequent phrase c.insert({ - _key: "testPhrase" + i, - value2: - phrasesHigh[highPhraseCounter] + phrasesLow[lowPhraseCounter] + _key: "testPhrase" + (n + 1), + value2: "Low Phrase" }); - ++highPhraseCounter; - ++lowPhraseCounter; - // loop over our phrases - if (highPhraseCounter >= phrasesHigh.length) { - highPhraseCounter = 0; - } - if (lowPhraseCounter >= phrasesLow.length) { - lowPhraseCounter = 0; - } } - // And some really low frequent phrase - c.insert({ - _key: "testPhrase" + (n + 1), - value2: "Low Phrase" - }); - } - - if (global.small) { - createDocumentsWithPhrases(10000); - createPhrasesView(10000); - } + if (global.small) { + createDocumentsWithPhrases(10000); + createPhrasesView(10000); + } - if (global.medium) { - createDocumentsWithPhrases(100000); - createPhrasesView(100000); - } + if (global.medium) { + createDocumentsWithPhrases(100000); + createPhrasesView(100000); + } - if (global.big) { - createDocumentsWithPhrases(10000000); - createPhrasesView(10000000); - } + if (global.big) { + createDocumentsWithPhrases(10000000); + createPhrasesView(10000000); + } - internal.wal.flush(true, true); - }, + internal.wal.flush(true, true); + }, - initializeStoredValuesView = function () { - function createStoredValuesView (n) { - let params = { - name: "v_stored_values" + n, - collections: ["values" + n], - analyzers: ["identity"], - storedValues: semver.satisfies(serverVersion, "<3.7.0") ? ["value2", ["value1", "value3"]] : [["value2"], ["value1", "value3"]] - }; - createArangoSearch(params); - } + initializeStoredValuesView = function () { + function createStoredValuesView(n) { + let params = { + name: "v_stored_values" + n, + collections: ["values" + n], + analyzers: ["identity"], + storedValues: semver.satisfies(serverVersion, "<3.7.0") ? ["value2", ["value1", "value3"]] : [["value2"], ["value1", "value3"]] + }; + createArangoSearch(params); + } - if (global.small) { - createStoredValuesView(10000); - } + if (global.small) { + createStoredValuesView(10000); + } - if (global.medium) { - createStoredValuesView(100000); - } + if (global.medium) { + createStoredValuesView(100000); + } - if (global.big) { - createStoredValuesView(1000000); - } + if (global.big) { + createStoredValuesView(1000000); + } - internal.wal.flush(true, true); - }, + internal.wal.flush(true, true); + }, - // ///////////////////////////////////////////////////////////////////////////// - // CRUD Helper - // ///////////////////////////////////////////////////////////////////////////// + // ///////////////////////////////////////////////////////////////////////////// + // CRUD Helper + // ///////////////////////////////////////////////////////////////////////////// - drop = function (params) { - let view = params.view; - if (view !== undefined) { - if (db._view(view) !== null) { - db._dropView(view); + drop = function (params) { + let view = params.view; + if (view !== undefined) { + if (db._view(view) !== null) { + db._dropView(view); + } } - } - let name = params.collection; - if (db._collection(name) !== null) { - db._drop(name); - } - }, + let name = params.collection; + if (db._collection(name) !== null) { + db._drop(name); + } + }, - create = function (params) { - let name = params.collection; - db._create(name, {numberOfShards}); - let view = params.view; - if (view !== undefined) { - let viewParams = { - name: view, - collections: [name], - analyzers: [params.analyzers] - }; - createArangoSearch(viewParams); - } - }, + create = function (params) { + let name = params.collection; + db._create(name, { numberOfShards }); + let view = params.view; + if (view !== undefined) { + let viewParams = { + name: view, + collections: [name], + analyzers: [params.analyzers] + }; + createArangoSearch(viewParams); + } + }, - fill = function (params) { - let c = db._collection(params.collection), - n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10), - docSize = parseInt(params.docSize) || 0, - doc = {}; - for (let i = 0; i < docSize; ++i) { - doc["value" + i] = i; - } + fill = function (params) { + let c = db._collection(params.collection), + n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10), + docSize = parseInt(params.docSize) || 0, + doc = {}; + for (let i = 0; i < docSize; ++i) { + doc["value" + i] = i; + } - for (let i = 0; i < n; ++i) { - doc._key = "test" + i; - c.insert(doc); - } - }, + for (let i = 0; i < n; ++i) { + doc._key = "test" + i; + c.insert(doc); + } + }, - // ///////////////////////////////////////////////////////////////////////////// - // CRUD Tests - // ///////////////////////////////////////////////////////////////////////////// + // ///////////////////////////////////////////////////////////////////////////// + // CRUD Tests + // ///////////////////////////////////////////////////////////////////////////// - insert = function (params) { - fill(params); - }, + insert = function (params) { + fill(params); + }, - update = function (params) { - let c = db._collection(params.collection), - n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10); - for (let i = 0; i < n; ++i) { - c.update("test" + i, { value: i + 1, value2: "test" + i, value3: i }); - } - }, + update = function (params) { + let c = db._collection(params.collection), + n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10); + for (let i = 0; i < n; ++i) { + c.update("test" + i, { value: i + 1, value2: "test" + i, value3: i }); + } + }, - replace = function (params) { - let c = db._collection(params.collection), - n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10); - for (let i = 0; i < n; ++i) { - c.replace("test" + i, { value: i + 1, value2: "test" + i, value3: i }); - } - }, + replace = function (params) { + let c = db._collection(params.collection), + n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10); + for (let i = 0; i < n; ++i) { + c.replace("test" + i, { value: i + 1, value2: "test" + i, value3: i }); + } + }, - remove = function (params) { - let c = db._collection(params.collection), - n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10); - for (let i = 0; i < n; ++i) { - c.remove("test" + i); - } - }, + remove = function (params) { + let c = db._collection(params.collection), + n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10); + for (let i = 0; i < n; ++i) { + c.remove("test" + i); + } + }, - count = function (params) { - let c = db._collection(params.collection); - c.count(); - }, + count = function (params) { + let c = db._collection(params.collection); + c.count(); + }, - anyCrud = function (params) { - let c = db._collection(params.collection); - c.any(); - }, + anyCrud = function (params) { + let c = db._collection(params.collection); + c.any(); + }, - all = function (params) { - let c = db._collection(params.collection); - c.toArray(); - }, + all = function (params) { + let c = db._collection(params.collection); + c.toArray(); + }, - truncate = function (params) { - let c = db._collection(params.collection); - c.truncate(); - }, + truncate = function (params) { + let c = db._collection(params.collection); + c.truncate(); + }, - // ///////////////////////////////////////////////////////////////////////////// - // edgeTests - // ///////////////////////////////////////////////////////////////////////////// + // ///////////////////////////////////////////////////////////////////////////// + // edgeTests + // ///////////////////////////////////////////////////////////////////////////// - outbound = function (params) { - db._query( - "WITH @@v FOR i IN 1 .. @loops FOR v, e, p IN @minDepth..@maxDepth OUTBOUND @start @@c RETURN v", - { - "@c": params.collection, - "@v": params.collection.replace("edges", "values"), - minDepth: params.minDepth, - maxDepth: params.maxDepth, - loops: params.loops || 1, - start: params.collection.replace(/edges/, "values") + "/test1" - }, - {}, - { silent } - ); - }, + outbound = function (params) { + db._query( + "WITH @@v FOR i IN 1 .. @loops FOR v, e, p IN @minDepth..@maxDepth OUTBOUND @start @@c RETURN v", + { + "@c": params.collection, + "@v": params.collection.replace("edges", "values"), + minDepth: params.minDepth, + maxDepth: params.maxDepth, + loops: params.loops || 1, + start: params.collection.replace(/edges/, "values") + "/test1" + }, + {}, + { silent } + ); + }, - any = function (params) { - db._query( - "WITH @@v FOR v, e, p IN @minDepth..@maxDepth ANY @start @@c RETURN v", - { - "@c": params.collection, - "@v": params.collection.replace("edges", "values"), - minDepth: params.minDepth, - maxDepth: params.maxDepth, - start: params.collection.replace(/edges/, "values") + "/test1" - }, - {}, - { silent } - ); - }, + any = function (params) { + db._query( + "WITH @@v FOR v, e, p IN @minDepth..@maxDepth ANY @start @@c RETURN v", + { + "@c": params.collection, + "@v": params.collection.replace("edges", "values"), + minDepth: params.minDepth, + maxDepth: params.maxDepth, + start: params.collection.replace(/edges/, "values") + "/test1" + }, + {}, + { silent } + ); + }, - outboundPath = function (params) { - db._query( - "WITH @@v FOR v, e, p IN @minDepth..@maxDepth OUTBOUND @start @@c RETURN p", - { - "@c": params.collection, - "@v": params.collection.replace("edges", "values"), - minDepth: params.minDepth, - maxDepth: params.maxDepth, - start: params.collection.replace(/edges/, "values") + "/test1" - }, - {}, - { silent } - ); - }, + outboundPath = function (params) { + db._query( + "WITH @@v FOR v, e, p IN @minDepth..@maxDepth OUTBOUND @start @@c RETURN p", + { + "@c": params.collection, + "@v": params.collection.replace("edges", "values"), + minDepth: params.minDepth, + maxDepth: params.maxDepth, + start: params.collection.replace(/edges/, "values") + "/test1" + }, + {}, + { silent } + ); + }, - anyPath = function (params) { - db._query( - "WITH @@v FOR v, e, p IN @minDepth..@maxDepth ANY @start @@c RETURN p", - { - "@c": params.collection, - "@v": params.collection.replace("edges", "values"), - minDepth: params.minDepth, - maxDepth: params.maxDepth, - start: params.collection.replace(/edges/, "values") + "/test1" - }, - {}, - { silent } - ); - }, + anyPath = function (params) { + db._query( + "WITH @@v FOR v, e, p IN @minDepth..@maxDepth ANY @start @@c RETURN p", + { + "@c": params.collection, + "@v": params.collection.replace("edges", "values"), + minDepth: params.minDepth, + maxDepth: params.maxDepth, + start: params.collection.replace(/edges/, "values") + "/test1" + }, + {}, + { silent } + ); + }, - shortestOutbound = function (params) { - db._query( - "WITH @@v FOR v IN OUTBOUND SHORTEST_PATH @start TO @dest @@c RETURN v", - { - "@c": params.collection, - "@v": params.collection.replace("edges", "values"), - start: params.collection.replace(/edges/, "values") + "/test1", - dest: params.collection.replace(/edges/, "values") + "/test9999" - }, - {}, - { silent } - ); - }, + shortestOutbound = function (params) { + db._query( + "WITH @@v FOR v IN OUTBOUND SHORTEST_PATH @start TO @dest @@c RETURN v", + { + "@c": params.collection, + "@v": params.collection.replace("edges", "values"), + start: params.collection.replace(/edges/, "values") + "/test1", + dest: params.collection.replace(/edges/, "values") + "/test9999" + }, + {}, + { silent } + ); + }, - shortestAny = function (params) { - db._query( - "WITH @@v FOR v IN ANY SHORTEST_PATH @start TO @dest @@c RETURN v", - { - "@c": params.collection, - "@v": params.collection.replace("edges", "values"), - start: params.collection.replace(/edges/, "values") + "/test1", - dest: params.collection.replace(/edges/, "values") + "/test9999" - }, - {}, - { silent } - ); - }, + shortestAny = function (params) { + db._query( + "WITH @@v FOR v IN ANY SHORTEST_PATH @start TO @dest @@c RETURN v", + { + "@c": params.collection, + "@v": params.collection.replace("edges", "values"), + start: params.collection.replace(/edges/, "values") + "/test1", + dest: params.collection.replace(/edges/, "values") + "/test9999" + }, + {}, + { silent } + ); + }, - // ///////////////////////////////////////////////////////////////////////////// - // documentTests - // ///////////////////////////////////////////////////////////////////////////// + // ///////////////////////////////////////////////////////////////////////////// + // documentTests + // ///////////////////////////////////////////////////////////////////////////// - subquery = function (params) { - db._query( - "FOR c IN @@c LET sub = (FOR s IN @@c FILTER s.@attr == c.@attr RETURN s) RETURN LENGTH(sub)", - { - "@c": params.collection, - attr: params.attr - }, - {}, - { silent } - ); - }, + subquery = function (params) { + db._query( + "FOR c IN @@c LET sub = (FOR s IN @@c FILTER s.@attr == c.@attr RETURN s) RETURN LENGTH(sub)", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); + }, - subqueryExistsPath = function (params) { - const vertices = params.collection.replace("edges", "values"); - // Test if we have a path leading back to values/test2 - // On small this will be 1321 vertices, on medium and big it will be 33976 vertices - db._query(` + subqueryExistsPath = function (params) { + const vertices = params.collection.replace("edges", "values"); + // Test if we have a path leading back to values/test2 + // On small this will be 1321 vertices, on medium and big it will be 33976 vertices + db._query(` FOR v IN @@c LET hasPath = (FOR s IN INBOUND SHORTEST_PATH v TO @source @@e RETURN 1) FILTER LENGTH(hasPath) > 0 RETURN v `, - { - "@c": vertices, - "@e": params.collection, - source: `${vertices}/test2` - }, - {}, - { silent } - ); - }, + { + "@c": vertices, + "@e": params.collection, + source: `${vertices}/test2` + }, + {}, + { silent } + ); + }, - twoStepTraversalGroupByCollect = function (params) { - const vertices = params.collection.replace("edges", "values"); - // Test if we have a path leading back to values/test2 - // On small this will be 1321 vertices, on medium and big it will be 33976 vertices - db._query(` + twoStepTraversalGroupByCollect = function (params) { + const vertices = params.collection.replace("edges", "values"); + // Test if we have a path leading back to values/test2 + // On small this will be 1321 vertices, on medium and big it will be 33976 vertices + db._query(` FOR v IN @@c FOR main IN 1 OUTBOUND v @@e FOR sub IN 1 OUTBOUND main @@e COLLECT m = main INTO group RETURN {main: m, subs: group.sub } `, - { - "@c": vertices, - "@e": params.collection + { + "@c": vertices, + "@e": params.collection + }, + {}, + { silent } + ); }, - {}, - { silent } - ); - }, - twoStepTraversalGroupBySubquery = function (params) { - const vertices = params.collection.replace("edges", "values"); - // Test if we have a path leading back to values/test2 - // On small this will be 1321 vertices, on medium and big it will be 33976 vertices - db._query(` + twoStepTraversalGroupBySubquery = function (params) { + const vertices = params.collection.replace("edges", "values"); + // Test if we have a path leading back to values/test2 + // On small this will be 1321 vertices, on medium and big it will be 33976 vertices + db._query(` FOR v IN @@c FOR main IN 1 OUTBOUND v @@e LET subs = ( @@ -1107,227 +1187,240 @@ exports.test = function (global) { ) RETURN {main, subs} `, - { - "@c": vertices, - "@e": params.collection + { + "@c": vertices, + "@e": params.collection + }, + {}, + { silent } + ); }, - {}, - { silent } - ); - }, - - min = function (params) { - db._query( - "RETURN MIN(FOR c IN @@c RETURN c.@attr)", - { - "@c": params.collection, - attr: params.attr - }, - {}, - { silent } - ); - }, - max = function (params) { - db._query( - "RETURN MAX(FOR c IN @@c RETURN c.@attr)", - { - "@c": params.collection, - attr: params.attr - }, - {}, - { silent } - ); - }, + min = function (params) { + db._query( + "RETURN MIN(FOR c IN @@c RETURN c.@attr)", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); + }, - concat = function (params) { - db._query( - "FOR c IN @@c RETURN CONCAT(c._key, '-', c.@attr)", - { - "@c": params.collection, - attr: params.attr - }, - {}, - { silent } - ); - }, + max = function (params) { + db._query( + "RETURN MAX(FOR c IN @@c RETURN c.@attr)", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); + }, - merge = function (params) { - db._query( - "FOR c IN @@c RETURN MERGE(c, { 'testValue': c.@attr })", - { - "@c": params.collection, - attr: params.attr - }, - {}, - { silent } - ); - }, + concat = function (params) { + db._query( + "FOR c IN @@c RETURN CONCAT(c._key, '-', c.@attr)", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); + }, - keep = function (params) { - db._query( - "FOR c IN @@c RETURN KEEP(c, '_key', '_rev', '_id')", - { - "@c": params.collection - }, - {}, - { silent } - ); - }, + merge = function (params) { + db._query( + "FOR c IN @@c RETURN MERGE(c, { 'testValue': c.@attr })", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); + }, - unset = function (params) { - db._query( - "FOR c IN @@c RETURN UNSET(c, '_key', '_rev', '_id')", - { - "@c": params.collection - }, - {}, - { silent } - ); - }, + keep = function (params) { + db._query( + "FOR c IN @@c RETURN KEEP(c, '_key', '_rev', '_id')", + { + "@c": params.collection + }, + {}, + { silent } + ); + }, - attributes = function (params) { - db._query( - "FOR c IN @@c RETURN ATTRIBUTES(c)", - { - "@c": params.collection - }, - {}, - { silent } - ); - }, + unset = function (params) { + db._query( + "FOR c IN @@c RETURN UNSET(c, '_key', '_rev', '_id')", + { + "@c": params.collection + }, + {}, + { silent } + ); + }, - values = function (params) { - db._query( - "FOR c IN @@c RETURN VALUES(c)", - { - "@c": params.collection - }, - {}, - { silent } - ); - }, + attributes = function (params) { + db._query( + "FOR c IN @@c RETURN ATTRIBUTES(c)", + { + "@c": params.collection + }, + {}, + { silent } + ); + }, - has = function (params) { - db._query( - "FOR c IN @@c RETURN HAS(c, c.@attr)", - { - "@c": params.collection, - attr: params.attr - }, - {}, - { silent } - ); - }, + values = function (params) { + db._query( + "FOR c IN @@c RETURN VALUES(c)", + { + "@c": params.collection + }, + {}, + { silent } + ); + }, - md5 = function (params) { - db._query( - "FOR c IN @@c RETURN MD5(c.@attr)", - { - "@c": params.collection, - attr: params.attr - }, - {}, - { silent } - ); - }, + has = function (params) { + db._query( + "FOR c IN @@c RETURN HAS(c, c.@attr)", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); + }, - sha1 = function (params) { - db._query( - "FOR c IN @@c RETURN SHA1(c.@attr)", - { - "@c": params.collection, - attr: params.attr - }, - {}, - { silent } - ); - }, + md5 = function (params) { + db._query( + "FOR c IN @@c RETURN MD5(c.@attr)", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); + }, - skipIndex = function (params) { - let size = parseInt(params.collection.replace(/[^0-9]/g, "")), - offset = size - params.limit; - db._query( - "FOR c IN @@c SORT c.@attr LIMIT @offset, @limit RETURN c.@attr", - { - "@c": params.collection, - attr: params.attr, - offset: offset, - limit: params.limit - }, - {}, - { silent } - ); - }, + sha1 = function (params) { + db._query( + "FOR c IN @@c RETURN SHA1(c.@attr)", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); + }, - skipDocs = function (params) { - let size = parseInt(params.collection.replace(/[^0-9]/g, "")), - offset = size - params.limit; - db._query( - "FOR c IN @@c SORT c.@attr LIMIT @offset, @limit RETURN c.@attr", - { - "@c": params.collection, - attr: params.attr, - offset: offset, - limit: params.limit - }, - {}, - { silent } - ); - }, + skipIndex = function (params) { + let size = parseInt(params.collection.replace(/[^0-9]/g, "")), + offset = size - params.limit; + db._query( + "FOR c IN @@c SORT c.@attr LIMIT @offset, @limit RETURN c.@attr", + { + "@c": params.collection, + attr: params.attr, + offset: offset, + limit: params.limit + }, + {}, + { silent } + ); + }, - sortAll = function (params) { - // Use a "sort everything" implementation. - db._query( - "FOR c IN @@c SORT c.@attr LIMIT 1 RETURN c.@attr", - { - "@c": params.collection, - attr: params.attr - }, - {}, - { silent, optimizer: { rules: ["-sort-limit"] } } - ); - }, + skipDocs = function (params) { + let size = parseInt(params.collection.replace(/[^0-9]/g, "")), + offset = size - params.limit; + db._query( + "FOR c IN @@c SORT c.@attr LIMIT @offset, @limit RETURN c.@attr", + { + "@c": params.collection, + attr: params.attr, + offset: offset, + limit: params.limit + }, + {}, + { silent } + ); + }, - sortHeap = function (params) { - // Use a heap of size 20 for the sort. - db._query( - "FOR c IN @@c SORT c.@attr LIMIT 20 RETURN c.@attr", - { - "@c": params.collection, - attr: params.attr - }, - {}, - { silent } - ); - }, + sortAll = function (params) { + // Use a "sort everything" implementation. + db._query( + "FOR c IN @@c SORT c.@attr LIMIT 1 RETURN c.@attr", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent, optimizer: { rules: ["-sort-limit"] } } + ); + }, - filter = function (params) { - db._query( - "FOR c IN @@c FILTER c.@attr == @value RETURN c.@attr", - { - "@c": params.collection, - attr: params.attr, - value: params.value - }, - {}, - { silent } - ); - }, + sortHeap = function (params) { + // Use a heap of size 20 for the sort. + db._query( + "FOR c IN @@c SORT c.@attr LIMIT 20 RETURN c.@attr", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); + }, - extract = function (params) { - if (params.attr === undefined) { + filter = function (params) { db._query( - "FOR c IN @@c RETURN c", + "FOR c IN @@c FILTER c.@attr == @value RETURN c.@attr", { - "@c": params.collection + "@c": params.collection, + attr: params.attr, + value: params.value }, {}, { silent } ); - } else { + }, + + extract = function (params) { + if (params.attr === undefined) { + db._query( + "FOR c IN @@c RETURN c", + { + "@c": params.collection + }, + {}, + { silent } + ); + } else { + db._query( + "FOR c IN @@c RETURN c.@attr", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); + } + }, + + join = function (params) { db._query( - "FOR c IN @@c RETURN c.@attr", + "FOR c1 IN @@c FOR c2 IN @@c FILTER c1.@attr == c2.@attr RETURN c1", { "@c": params.collection, attr: params.attr @@ -1335,526 +1428,523 @@ exports.test = function (global) { {}, { silent } ); - } - }, + }, - join = function (params) { - db._query( - "FOR c1 IN @@c FOR c2 IN @@c FILTER c1.@attr == c2.@attr RETURN c1", - { - "@c": params.collection, - attr: params.attr - }, - {}, - { silent } - ); - }, + lookup = function (params) { + let key, + numeric = params.numeric; + for (let i = 0; i < params.n; ++i) { + if (numeric) { + key = i; + } else { + key = "test" + i; + } + db._query( + "FOR c IN @@c FILTER c.@attr == @key RETURN c", + { + "@c": params.collection, + attr: params.attr, + key: key + }, + {}, + { silent } + ); + } + }, - lookup = function (params) { - let key, - numeric = params.numeric; - for (let i = 0; i < params.n; ++i) { - if (numeric) { - key = i; - } else { - key = "test" + i; + lookupIn = function (params) { + let keys = [], + numeric = params.numeric; + for (let i = 0; i < params.n; ++i) { + if (numeric) { + keys.push(i); + } else { + keys.push("test" + i); + } } db._query( - "FOR c IN @@c FILTER c.@attr == @key RETURN c", + "FOR c IN @@c FILTER c.@attr IN @keys RETURN c", { "@c": params.collection, attr: params.attr, - key: key + keys: keys }, {}, { silent } ); - } - }, + }, - lookupIn = function (params) { - let keys = [], - numeric = params.numeric; - for (let i = 0; i < params.n; ++i) { - if (numeric) { - keys.push(i); + collect = function (params) { + if (params.count) { + db._query( + "FOR c IN @@c COLLECT g = c.@attr WITH COUNT INTO l RETURN [ g, l ]", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); } else { - keys.push("test" + i); + db._query( + "FOR c IN @@c COLLECT g = c.@attr RETURN g", + { + "@c": params.collection, + attr: params.attr + }, + {}, + { silent } + ); } - } - db._query( - "FOR c IN @@c FILTER c.@attr IN @keys RETURN c", - { - "@c": params.collection, - attr: params.attr, - keys: keys - }, - {}, - { silent } - ); - }, + }, - collect = function (params) { - if (params.count) { + passthru = function (params) { db._query( - "FOR c IN @@c COLLECT g = c.@attr WITH COUNT INTO l RETURN [ g, l ]", + "FOR c IN @@c RETURN NOOPT(" + params.name + "(@value))", { "@c": params.collection, - attr: params.attr + value: params.values }, {}, { silent } ); - } else { + }, + + numericSequence = function (n) { + let result = []; + for (let i = 0; i < n; ++i) { + result.push(i); + } + return result; + }, + + // ///////////////////////////////////////////////////////////////////////////// + // arangosearchTests + // ///////////////////////////////////////////////////////////////////////////// + + arangosearchLookupByAttribute = function (params) { db._query( - "FOR c IN @@c COLLECT g = c.@attr RETURN g", + "FOR d IN @@v SEARCH d.@attr == @value RETURN d", { - "@c": params.collection, - attr: params.attr + "@v": params.view, + attr: params.attr, + value: params.value }, {}, { silent } ); - } - }, - - passthru = function (params) { - db._query( - "FOR c IN @@c RETURN NOOPT(" + params.name + "(@value))", - { - "@c": params.collection, - value: params.values - }, - {}, - { silent } - ); - }, - - numericSequence = function (n) { - let result = []; - for (let i = 0; i < n; ++i) { - result.push(i); - } - return result; - }, + }, - // ///////////////////////////////////////////////////////////////////////////// - // arangosearchTests - // ///////////////////////////////////////////////////////////////////////////// - - arangosearchLookupByAttribute = function (params) { - db._query( - "FOR d IN @@v SEARCH d.@attr == @value RETURN d", - { - "@v": params.view, - attr: params.attr, - value: params.value - }, - {}, - { silent } - ); - }, + arangosearchRangeLookupOperator = function (params) { + if (params.includeMin && params.includeMax) { + db._query( + "FOR d IN @@v SEARCH d.@attr >= @minValue && d.@attr <= @maxValue RETURN d", + { + "@v": params.view, + attr: params.attr, + minValue: params.minValue, + maxValue: params.maxValue + }, + {}, + { silent } + ); + } else if (params.includeMax) { + db._query( + "FOR d IN @@v SEARCH d.@attr > @minValue && d.@attr <= @maxValue RETURN d", + { + "@v": params.view, + attr: params.attr, + minValue: params.minValue, + maxValue: params.maxValue + }, + {}, + { silent } + ); + } else if (params.includeMin) { + db._query( + "FOR d IN @@v SEARCH d.@attr >= @minValue && d.@attr < @maxValue RETURN d", + { + "@v": params.view, + attr: params.attr, + minValue: params.minValue, + maxValue: params.maxValue + }, + {}, + { silent } + ); + } else { + db._query( + "FOR d IN @@v SEARCH d.@attr > @minValue && d.@attr < @maxValue RETURN d", + { + "@v": params.view, + attr: params.attr, + minValue: params.minValue, + maxValue: params.maxValue + }, + {}, + { silent } + ); + } + }, - arangosearchRangeLookupOperator = function (params) { - if (params.includeMin && params.includeMax) { + arangosearchRangeLookupFunc = function (params) { db._query( - "FOR d IN @@v SEARCH d.@attr >= @minValue && d.@attr <= @maxValue RETURN d", + "FOR d IN @@v SEARCH IN_RANGE(d.@attr, @minValue, @maxValue, @includeMin, @includeMax) RETURN d", { "@v": params.view, attr: params.attr, minValue: params.minValue, - maxValue: params.maxValue + maxValue: params.maxValue, + includeMin: params.includeMin, + includeMax: params.includeMax }, {}, { silent } ); - } else if (params.includeMax) { + }, + + arangosearchBasicConjunction = function (params) { db._query( - "FOR d IN @@v SEARCH d.@attr > @minValue && d.@attr <= @maxValue RETURN d", + "FOR d IN @@v SEARCH d.@attr0 == @value0 && d.@attr1 == @value1 RETURN d", { "@v": params.view, - attr: params.attr, - minValue: params.minValue, - maxValue: params.maxValue + attr0: params.attr0, + value0: params.value0, + attr1: params.attr1, + value1: params.value1 }, {}, { silent } ); - } else if (params.includeMin) { + }, + arangosearchBasicDisjunction = function (params) { + db._query( + "FOR d IN @@v SEARCH d.@attr0 == @value0 || d.@attr1 == @value1 RETURN d", + { + "@v": params.view, + attr0: params.attr0, + value0: params.value0, + attr1: params.attr1, + value1: params.value1 + }, + {}, + { silent } + ); + }, + arangosearchDisjunction = function (params) { db._query( - "FOR d IN @@v SEARCH d.@attr >= @minValue && d.@attr < @maxValue RETURN d", + "FOR d IN @@v SEARCH d.@attr IN @value RETURN d", { "@v": params.view, attr: params.attr, - minValue: params.minValue, - maxValue: params.maxValue + value: params.value }, {}, { silent } ); - } else { + }, + arangosearchPrefix = function (params) { db._query( - "FOR d IN @@v SEARCH d.@attr > @minValue && d.@attr < @maxValue RETURN d", + "FOR d IN @@v SEARCH STARTS_WITH(d.@attr, @value) RETURN d", { "@v": params.view, attr: params.attr, - minValue: params.minValue, - maxValue: params.maxValue + value: params.value }, {}, { silent } ); - } - }, - - arangosearchRangeLookupFunc = function (params) { - db._query( - "FOR d IN @@v SEARCH IN_RANGE(d.@attr, @minValue, @maxValue, @includeMin, @includeMax) RETURN d", - { - "@v": params.view, - attr: params.attr, - minValue: params.minValue, - maxValue: params.maxValue, - includeMin: params.includeMin, - includeMax: params.includeMax - }, - {}, - { silent } - ); - }, - - arangosearchBasicConjunction = function (params) { - db._query( - "FOR d IN @@v SEARCH d.@attr0 == @value0 && d.@attr1 == @value1 RETURN d", - { - "@v": params.view, - attr0: params.attr0, - value0: params.value0, - attr1: params.attr1, - value1: params.value1 - }, - {}, - { silent } - ); - }, - arangosearchBasicDisjunction = function (params) { - db._query( - "FOR d IN @@v SEARCH d.@attr0 == @value0 || d.@attr1 == @value1 RETURN d", - { - "@v": params.view, - attr0: params.attr0, - value0: params.value0, - attr1: params.attr1, - value1: params.value1 - }, - {}, - { silent } - ); - }, - arangosearchDisjunction = function (params) { - db._query( - "FOR d IN @@v SEARCH d.@attr IN @value RETURN d", - { - "@v": params.view, - attr: params.attr, - value: params.value - }, - {}, - { silent } - ); - }, - arangosearchPrefix = function (params) { - db._query( - "FOR d IN @@v SEARCH STARTS_WITH(d.@attr, @value) RETURN d", - { - "@v": params.view, - attr: params.attr, - value: params.value - }, - {}, - { silent } - ); - }, - arangosearchMinMatch2of3 = function (params) { - db._query( - "FOR d IN @@v SEARCH ANALYZER(MIN_MATCH(d.@attr1 == @value1, d.@attr1 == @value2, d.@attr1 == @value3, 2 ), 'text_en') RETURN d", - { - "@v": params.view, - attr1: params.attr1, - value1: params.value1, - value2: params.value2, - value3: params.value3 - }, - {}, - { silent } - ); - }, - arangosearchScoring = function (params) { - db._query( - "FOR d IN @@v SEARCH ANALYZER(d.@attr == @value, 'text_en') SORT " + + }, + arangosearchMinMatch2of3 = function (params) { + db._query( + "FOR d IN @@v SEARCH ANALYZER(MIN_MATCH(d.@attr1 == @value1, d.@attr1 == @value2, d.@attr1 == @value3, 2 ), 'text_en') RETURN d", + { + "@v": params.view, + attr1: params.attr1, + value1: params.value1, + value2: params.value2, + value3: params.value3 + }, + {}, + { silent } + ); + }, + arangosearchScoring = function (params) { + db._query( + "FOR d IN @@v SEARCH ANALYZER(d.@attr == @value, 'text_en') SORT " + params.scorer + "(d) ASC RETURN d", - { - "@v": params.view, - attr: params.attr, - value: params.value - }, - {}, - { silent } - ); - }, - arangosearchPhrase = function (params) { - db._query( - "FOR d IN @@v SEARCH PHRASE(d.@attr , @value, 'text_en') RETURN d", - { - "@v": params.view, - attr: params.attr, - value: params.value - }, - {}, - { silent } - ); - }, - arangosearchCountOnView = function (params) { - db._query( - "FOR d IN @@v COLLECT WITH COUNT INTO c RETURN c", - { - "@v": params.view - }, - {}, - { silent } - ); - }, - arangosearchCountOnViewLimited = function (params) { - db._query( - "FOR d IN @@v LIMIT @offset, @limit COLLECT WITH COUNT INTO c RETURN c", - { - "@v": params.view, - offset: params.offset, - limit: params.limit - }, - {}, - { silent } - ); - }, - arangosearchCountOnViewSearched = function (params) { - db._query( - "FOR d IN @@v SEARCH d.@attr IN @value COLLECT WITH COUNT INTO c RETURN c", - { - "@v": params.view, - attr: params.attr, - value: params.value - }, - {}, - { silent } - ); - }, - arangosearchNoMaterializationWithoutAccessOff = function (params) { - db._query( - "FOR d IN @@v OPTIONS {noMaterialization: false} RETURN 1", - { - "@v": params.view - }, - {}, - { silent } - ); - }, - arangosearchNoMaterializationWithoutAccessOn = function (params) { - db._query( - "FOR d IN @@v OPTIONS {noMaterialization: true} RETURN 1", - { - "@v": params.view - }, - {}, - { silent } - ); - }, - arangosearchNoMaterializationWithReturnOff = function (params) { - db._query( - "FOR d IN @@v OPTIONS {noMaterialization: false} RETURN d.@attr", - { - "@v": params.view, - attr: params.attr - }, - {}, - { silent } - ); - }, - arangosearchNoMaterializationWithReturnOn = function (params) { - db._query( - "FOR d IN @@v OPTIONS {noMaterialization: true} RETURN d.@attr", - { - "@v": params.view, - attr: params.attr - }, - {}, - { silent } - ); - }, - arangosearchNoMaterializationWithSortOff = function (params) { - db._query( - `FOR d IN @@v OPTIONS {noMaterialization: false} + { + "@v": params.view, + attr: params.attr, + value: params.value + }, + {}, + { silent } + ); + }, + arangosearchPhrase = function (params) { + db._query( + "FOR d IN @@v SEARCH PHRASE(d.@attr , @value, 'text_en') RETURN d", + { + "@v": params.view, + attr: params.attr, + value: params.value + }, + {}, + { silent } + ); + }, + arangosearchCountOnView = function (params) { + db._query( + "FOR d IN @@v COLLECT WITH COUNT INTO c RETURN c", + { + "@v": params.view + }, + {}, + { silent } + ); + }, + arangosearchCountOnViewLimited = function (params) { + db._query( + "FOR d IN @@v LIMIT @offset, @limit COLLECT WITH COUNT INTO c RETURN c", + { + "@v": params.view, + offset: params.offset, + limit: params.limit + }, + {}, + { silent } + ); + }, + arangosearchCountOnViewSearched = function (params) { + db._query( + "FOR d IN @@v SEARCH d.@attr IN @value COLLECT WITH COUNT INTO c RETURN c", + { + "@v": params.view, + attr: params.attr, + value: params.value + }, + {}, + { silent } + ); + }, + arangosearchNoMaterializationWithoutAccessOff = function (params) { + db._query( + "FOR d IN @@v OPTIONS {noMaterialization: false} RETURN 1", + { + "@v": params.view + }, + {}, + { silent } + ); + }, + arangosearchNoMaterializationWithoutAccessOn = function (params) { + db._query( + "FOR d IN @@v OPTIONS {noMaterialization: true} RETURN 1", + { + "@v": params.view + }, + {}, + { silent } + ); + }, + arangosearchNoMaterializationWithReturnOff = function (params) { + db._query( + "FOR d IN @@v OPTIONS {noMaterialization: false} RETURN d.@attr", + { + "@v": params.view, + attr: params.attr + }, + {}, + { silent } + ); + }, + arangosearchNoMaterializationWithReturnOn = function (params) { + db._query( + "FOR d IN @@v OPTIONS {noMaterialization: true} RETURN d.@attr", + { + "@v": params.view, + attr: params.attr + }, + {}, + { silent } + ); + }, + arangosearchNoMaterializationWithSortOff = function (params) { + db._query( + `FOR d IN @@v OPTIONS {noMaterialization: false} LET a = d.@attr0 LET b = d.@attr1 SORT CONCAT(a, b) RETURN [a, b, d.@attr2]`, - { - "@v": params.view, - attr0: params.attr0, - attr1: params.attr1, - attr2: params.attr2 - }, - {}, - { silent } - ); - }, - arangosearchNoMaterializationWithSortOn = function (params) { - db._query( - `FOR d IN @@v OPTIONS {noMaterialization: true} + { + "@v": params.view, + attr0: params.attr0, + attr1: params.attr1, + attr2: params.attr2 + }, + {}, + { silent } + ); + }, + arangosearchNoMaterializationWithSortOn = function (params) { + db._query( + `FOR d IN @@v OPTIONS {noMaterialization: true} LET a = d.@attr0 LET b = d.@attr1 SORT CONCAT(a, b) RETURN [a, b, d.@attr2]`, - { - "@v": params.view, - attr0: params.attr0, - attr1: params.attr1, - attr2: params.attr2 - }, - {}, - { silent } - ); - }, - arangosearchNoMaterializationWithSortAndLimitOff = function (params) { - db._query( - `FOR d IN @@v OPTIONS {noMaterialization: false} + { + "@v": params.view, + attr0: params.attr0, + attr1: params.attr1, + attr2: params.attr2 + }, + {}, + { silent } + ); + }, + arangosearchNoMaterializationWithSortAndLimitOff = function (params) { + db._query( + `FOR d IN @@v OPTIONS {noMaterialization: false} LET a = d.@attr0 LET b = d.@attr1 SORT CONCAT(a, b) LIMIT 10 RETURN [a, b, d.@attr2]`, - { - "@v": params.view, - attr0: params.attr0, - attr1: params.attr1, - attr2: params.attr2 - }, - {}, - { silent } - ); - }, - arangosearchNoMaterializationWithSortAndLimitOn = function (params) { - db._query( - `FOR d IN @@v OPTIONS {noMaterialization: true} + { + "@v": params.view, + attr0: params.attr0, + attr1: params.attr1, + attr2: params.attr2 + }, + {}, + { silent } + ); + }, + arangosearchNoMaterializationWithSortAndLimitOn = function (params) { + db._query( + `FOR d IN @@v OPTIONS {noMaterialization: true} LET a = d.@attr0 LET b = d.@attr1 SORT CONCAT(a, b) LIMIT 10 RETURN [a, b, d.@attr2]`, - { - "@v": params.view, - attr0: params.attr0, - attr1: params.attr1, - attr2: params.attr2 - }, - {}, - { silent } - ); - }, + { + "@v": params.view, + attr0: params.attr0, + attr1: params.attr1, + attr2: params.attr2 + }, + {}, + { silent } + ); + }, - // ///////////////////////////////////////////////////////////////////////////// - // subqueryTests - // ///////////////////////////////////////////////////////////////////////////// + // ///////////////////////////////////////////////////////////////////////////// + // subqueryTests + // ///////////////////////////////////////////////////////////////////////////// - // currently unused, useful for validation - subquerySplicingValidation = function (params) { - let spliceoptimizer = { rules: ["+splice-subqueries"] }; - let spliced = db._query( - params.queryString, - { - "@c": params.collection, - attr: params.attr - }, - { optimizer: spliceoptimizer } - ); - let nonspliceoptimizer = { rules: ["-splice-subqueries"] }; - let nonspliced = db._query( - params.queryString, - { - "@c": params.collection, - attr: params.attr - }, - { optimizer: nonspliceoptimizer } - ); - let splicedarray = spliced.toArray(); - let nonsplicedarray = nonspliced.toArray(); - if (splicedarray.length !== nonsplicedarray.length) { - print(spliced); - print(nonspliced); - throw "Results don't match"; - } - if (JSON.stringify(splicedarray.sort()) !== JSON.stringify(nonsplicedarray.sort())) { - print(spliced); - print(nonspliced); - throw "Results do not match"; - } - }, - genericSubquerySplicing = function (params) { - let myOptimizer = { rules: [] }; - let bindParam = { "@c": params.collection }; - if ('bindParamModifier' in params) { - params.bindParamModifier(params, bindParam); - } - if (params.edgesRequired === true) { - bindParam["@e"] = bindParam["@c"].replace("values", "edges"); - } - if (params.splice) { - myOptimizer.rules.push("+splice-subqueries"); - } else { - myOptimizer.rules.push("-splice-subqueries"); - } - let result = db._query( - params.queryString, + // currently unused, useful for validation + subquerySplicingValidation = function (params) { + let spliceoptimizer = { rules: ["+splice-subqueries"] }; + let spliced = db._query( + params.queryString, + { + "@c": params.collection, + attr: params.attr + }, + { optimizer: spliceoptimizer } + ); + let nonspliceoptimizer = { rules: ["-splice-subqueries"] }; + let nonspliced = db._query( + params.queryString, + { + "@c": params.collection, + attr: params.attr + }, + { optimizer: nonspliceoptimizer } + ); + let splicedarray = spliced.toArray(); + let nonsplicedarray = nonspliced.toArray(); + if (splicedarray.length !== nonsplicedarray.length) { + print(spliced); + print(nonspliced); + throw "Results don't match"; + } + if (JSON.stringify(splicedarray.sort()) !== JSON.stringify(nonsplicedarray.sort())) { + print(spliced); + print(nonspliced); + throw "Results do not match"; + } + }, + genericSubquerySplicing = function (params) { + let myOptimizer = { rules: [] }; + let bindParam = { "@c": params.collection }; + if ('bindParamModifier' in params) { + params.bindParamModifier(params, bindParam); + } + if (params.edgesRequired === true) { + bindParam["@e"] = bindParam["@c"].replace("values", "edges"); + } + if (params.splice) { + myOptimizer.rules.push("+splice-subqueries"); + } else { + myOptimizer.rules.push("-splice-subqueries"); + } + let result = db._query( + params.queryString, bindParam, - { optimizer: myOptimizer } - ); - }, + { optimizer: myOptimizer } + ); + }, - // ///////////////////////////////////////////////////////////////////////////// - // subqueryTests - // ///////////////////////////////////////////////////////////////////////////// + // ///////////////////////////////////////////////////////////////////////////// + // subqueryTests + // ///////////////////////////////////////////////////////////////////////////// - genericSatelliteGraph = function (params) { - let bindParam = { - "@c": params.collection, - "g": params.graph, - "v": params.graph + "_vertex", - //"e": params.graph + "_edge" - }; + genericSatelliteGraph = function (params) { + let bindParam = { + "@c": params.collection, + "g": params.graph, + "v": params.graph + "_vertex", + //"e": params.graph + "_edge" + }; - if ('bindParamModifier' in params) { - params.bindParamModifier(params, bindParam); - } + if ('bindParamModifier' in params) { + params.bindParamModifier(params, bindParam); + } - let result = db._query( - params.queryString, + let result = db._query( + params.queryString, bindParam, {} - ); - }, + ); + }, - genericDisjointSmartGraph = function (params) { - let bindParam = { - "@c": params.collection, - "g": params.graph, - "v": params.graph + "_vertex" - }; + genericDisjointSmartGraph = function (params) { + let numVertices = 0; + if (global.small) { + numVertices = 10000; + } else if (global.medium) { + numVertices = 100000; + } else if (global.big) { + numVertices = 1000000; + } + const gen = new GraphGenerator(params.vCol, params.eCol, numVertices) - if ('bindParamModifier' in params) { - params.bindParamModifier(params, bindParam); - } + let bindParam = { + "@c": params.collection, + "g": params.graph, + "startVertices": gen.getRandomStartVertices(100) + }; - db._query( - params.queryString, - bindParam, {} - ); - }, + if ('bindParamModifier' in params) { + params.bindParamModifier(params, bindParam); + } + + db._query( + params.queryString, + bindParam, {} + ); + }, - // ///////////////////////////////////////////////////////////////////////////// - // main - // ///////////////////////////////////////////////////////////////////////////// + // ///////////////////////////////////////////////////////////////////////////// + // main + // ///////////////////////////////////////////////////////////////////////////// - main = function () { - let documentTests = [ + main = function () { + let documentTests = [ { name: "aql-isarray-const", params: { @@ -2080,477 +2170,484 @@ exports.test = function (global) { params: { func: skipDocs, attr: "value1", limit: 10 } } ], - edgeTests = [ - { - name: "traversal-outbound-1", - params: { func: outbound, minDepth: 1, maxDepth: 1, loops: 1000 } - }, - { - name: "traversal-outbound-5", - params: { func: outbound, minDepth: 1, maxDepth: 5 } - }, - { - name: "traversal-any-1", - params: { func: any, minDepth: 1, maxDepth: 1 } - }, - { - name: "traversal-any-5", - params: { func: any, minDepth: 1, maxDepth: 5 } - }, - { - name: "traversal-out-path-5", - params: { func: outboundPath, minDepth: 1, maxDepth: 5 } - }, - { - name: "traversal-any-path-5", - params: { func: anyPath, minDepth: 1, maxDepth: 5 } - }, - { - name: "shortest-outbound", - params: { func: shortestOutbound } - }, - { - name: "shortest-any", - params: { func: shortestAny } - }, - { - name: "subquery-exists-path", - params: { func: subqueryExistsPath } - }, - { - name: "two-step-traversal-group-collect", - params: { func: twoStepTraversalGroupByCollect } - }, - { - name: "two-step-traversal-group-by-subquery", - params: { func: twoStepTraversalGroupBySubquery } - } - ], - arangosearchTests = [ - { - name: "ars-aql-key-lookup", - params: { - func: arangosearchLookupByAttribute, - attr: "_key", - value: "test4242" - } - }, - { - name: "ars-aql-range-lookup-operator", - params: { - func: arangosearchRangeLookupOperator, - attr: "_key", - minValue: "test42", - includeMin: true, - maxValue: "test4242", - includeMax: true - } - }, - { - name: "ars-aql-range-lookup-function", - version: ">= 3.4.5", - params: { - func: arangosearchRangeLookupFunc, - attr: "_key", - minValue: "test42", - includeMin: true, - maxValue: "test4242", - includeMax: true - } - }, - { - name: "ars-aql-basic-conjunction", - params: { - func: arangosearchBasicConjunction, - attr0: "value2", - value0: "test42", - attr1: "value1", - value1: 42 - } - }, - { - name: "ars-aql-basic-disjunction", - params: { - func: arangosearchBasicDisjunction, - attr0: "value2", - value0: "test42", - attr1: "value1", - value1: 4242 - } - }, - { - name: "ars-aql-disjunction", - params: { - func: arangosearchDisjunction, - attr: "value8", - value: [ - "test10", - "test42", - "test37", - "test76", - "test98", - "test2", - "invalid" - ] - } - }, - { - name: "ars-aql-prefix-low", - params: { - func: arangosearchPrefix, - attr: "value2", - value: "test4242" - } - }, - { - name: "ars-aql-prefix-high", - params: { func: arangosearchPrefix, attr: "value2", value: "test4" } - }, - { - name: "ars-aql-collect-count", - params: { - func: arangosearchCountOnView - } - }, - { - name: "ars-aql-collect-count-limited", - params: { - func: arangosearchCountOnViewLimited - } - }, - { - name: "ars-aql-collect-count-searched", - params: { - func: arangosearchCountOnViewSearched, - attr: "value6", - value: "test333" - } - } - ], - arangosearchPhrasesTests = [ - { - name: "ars-aql-phrase-minmatch-low", - analyzers: true, - params: { - func: arangosearchMinMatch2of3, - attr1: "value2", - value1: "low", - value2: "nomatch", - value3: "phrase" - } - }, - { - name: "ars-aql-phrase-minmatch-high", - analyzers: true, - params: { - func: arangosearchMinMatch2of3, - attr1: "value2", - value1: "brown", - value2: "tree", - value3: "nomatch" - } - }, - { - name: "ars-aql-phrase-score-tfidf-low", - analyzers: true, - params: { - func: arangosearchScoring, - attr: "value2", - value: "wheel", - scorer: "TFIDF" - } - }, - { - name: "ars-aql-phrase-score-bm25-low", - analyzers: true, - params: { - func: arangosearchScoring, - attr: "value2", - value: "wheel", - scorer: "BM25" - } - }, - { - name: "ars-aql-phrase-score-tfidf-high", - analyzers: true, - params: { - func: arangosearchScoring, - attr: "value2", - value: "brown", - scorer: "TFIDF" - } - }, - { - name: "ars-aql-phrase-score-bm25-high", - analyzers: true, - params: { - func: arangosearchScoring, - attr: "value2", - value: "brown", - scorer: "BM25" - } - }, - { - name: "ars-aql-phrase-low", - analyzers: true, - params: { - func: arangosearchPhrase, - attr: "value2", - value: "Low Phrase" - } - }, - { - name: "ars-aql-phrase-high", - analyzers: true, - params: { - func: arangosearchPhrase, - attr: "value2", - value: "Brown Planet" - } - } - ], - arangosearchNoMaterializationTests = [ - { - name: "ars-no-materialization-without-access-off", - params: { - func: arangosearchNoMaterializationWithoutAccessOff - } - }, - { - name: "ars-no-materialization-without-access-on", - params: { - func: arangosearchNoMaterializationWithoutAccessOn - } - }, - { - name: "ars-no-materialization-with-return-off", - params: { - func: arangosearchNoMaterializationWithReturnOff, - attr: "value1" - } - }, - { - name: "ars-no-materialization-with-return-on", - params: { - func: arangosearchNoMaterializationWithReturnOn, - attr: "value1" - } - }, - { - name: "ars-no-materialization-with-sort-off", - params: { - func: arangosearchNoMaterializationWithSortOff, - attr0: "value1", - attr1: "value2", - attr2: "value3" - } - }, - { - name: "ars-no-materialization-with-sort-on", - params: { - func: arangosearchNoMaterializationWithSortOn, - attr0: "value1", - attr1: "value2", - attr2: "value3" - } - }, - { - name: "ars-no-materialization-with-sort-and-limit-off", - params: { - func: arangosearchNoMaterializationWithSortAndLimitOff, - attr0: "value1", - attr1: "value2", - attr2: "value3" - } - }, - { - name: "ars-no-materialization-with-sort-and-limit-on", - params: { - func: arangosearchNoMaterializationWithSortAndLimitOn, - attr0: "value1", - attr1: "value2", - attr2: "value3" - } - } - ], - crudTests = [ - { - name: "crud-insert", - params: { - func: insert, - setupEachCall: function (params) { - drop(params); - create(params); - }, - teardown: drop - } - }, - { - name: "crud-insert-size4", - params: { - func: insert, - setupEachCall: function (params) { - drop(params); - create(params); - }, - teardown: drop, - docSize: 4 - } - }, - { - name: "crud-update", - params: { - func: update, - setupEachCall: function (params) { - drop(params); - create(params); - fill(params); - }, - teardown: drop - } - }, - { - name: "crud-replace", - params: { - func: replace, - setupEachCall: function (params) { - drop(params); - create(params); - fill(params); - }, - teardown: drop - } - }, - { - name: "crud-remove", - params: { - func: remove, - setupEachCall: function (params) { - drop(params); - create(params); - fill(params); - }, - teardown: drop - } - }, - { - name: "crud-count", - params: { - func: count, - setup: function (params) { - drop(params); - create(params); - fill(params); - }, - teardown: drop + edgeTests = [ + { + name: "traversal-outbound-1", + params: { func: outbound, minDepth: 1, maxDepth: 1, loops: 1000 } + }, + { + name: "traversal-outbound-5", + params: { func: outbound, minDepth: 1, maxDepth: 5 } + }, + { + name: "traversal-any-1", + params: { func: any, minDepth: 1, maxDepth: 1 } + }, + { + name: "traversal-any-5", + params: { func: any, minDepth: 1, maxDepth: 5 } + }, + { + name: "traversal-out-path-5", + params: { func: outboundPath, minDepth: 1, maxDepth: 5 } + }, + { + name: "traversal-any-path-5", + params: { func: anyPath, minDepth: 1, maxDepth: 5 } + }, + { + name: "shortest-outbound", + params: { func: shortestOutbound } + }, + { + name: "shortest-any", + params: { func: shortestAny } + }, + { + name: "subquery-exists-path", + params: { func: subqueryExistsPath } + }, + { + name: "two-step-traversal-group-collect", + params: { func: twoStepTraversalGroupByCollect } + }, + { + name: "two-step-traversal-group-by-subquery", + params: { func: twoStepTraversalGroupBySubquery } } - }, - { - name: "crud-all", - params: { - func: all, - setup: function (params) { - drop(params); - create(params); - fill(params); - }, - teardown: drop + ], + arangosearchTests = [ + { + name: "ars-aql-key-lookup", + params: { + func: arangosearchLookupByAttribute, + attr: "_key", + value: "test4242" + } + }, + { + name: "ars-aql-range-lookup-operator", + params: { + func: arangosearchRangeLookupOperator, + attr: "_key", + minValue: "test42", + includeMin: true, + maxValue: "test4242", + includeMax: true + } + }, + { + name: "ars-aql-range-lookup-function", + version: ">= 3.4.5", + params: { + func: arangosearchRangeLookupFunc, + attr: "_key", + minValue: "test42", + includeMin: true, + maxValue: "test4242", + includeMax: true + } + }, + { + name: "ars-aql-basic-conjunction", + params: { + func: arangosearchBasicConjunction, + attr0: "value2", + value0: "test42", + attr1: "value1", + value1: 42 + } + }, + { + name: "ars-aql-basic-disjunction", + params: { + func: arangosearchBasicDisjunction, + attr0: "value2", + value0: "test42", + attr1: "value1", + value1: 4242 + } + }, + { + name: "ars-aql-disjunction", + params: { + func: arangosearchDisjunction, + attr: "value8", + value: [ + "test10", + "test42", + "test37", + "test76", + "test98", + "test2", + "invalid" + ] + } + }, + { + name: "ars-aql-prefix-low", + params: { + func: arangosearchPrefix, + attr: "value2", + value: "test4242" + } + }, + { + name: "ars-aql-prefix-high", + params: { func: arangosearchPrefix, attr: "value2", value: "test4" } + }, + { + name: "ars-aql-collect-count", + params: { + func: arangosearchCountOnView + } + }, + { + name: "ars-aql-collect-count-limited", + params: { + func: arangosearchCountOnViewLimited + } + }, + { + name: "ars-aql-collect-count-searched", + params: { + func: arangosearchCountOnViewSearched, + attr: "value6", + value: "test333" + } } - }, - { - name: "crud-truncate", - params: { - func: truncate, - setup: function (params) { - drop(params); - create(params); - fill(params); - }, - teardown: drop + ], + arangosearchPhrasesTests = [ + { + name: "ars-aql-phrase-minmatch-low", + analyzers: true, + params: { + func: arangosearchMinMatch2of3, + attr1: "value2", + value1: "low", + value2: "nomatch", + value3: "phrase" + } + }, + { + name: "ars-aql-phrase-minmatch-high", + analyzers: true, + params: { + func: arangosearchMinMatch2of3, + attr1: "value2", + value1: "brown", + value2: "tree", + value3: "nomatch" + } + }, + { + name: "ars-aql-phrase-score-tfidf-low", + analyzers: true, + params: { + func: arangosearchScoring, + attr: "value2", + value: "wheel", + scorer: "TFIDF" + } + }, + { + name: "ars-aql-phrase-score-bm25-low", + analyzers: true, + params: { + func: arangosearchScoring, + attr: "value2", + value: "wheel", + scorer: "BM25" + } + }, + { + name: "ars-aql-phrase-score-tfidf-high", + analyzers: true, + params: { + func: arangosearchScoring, + attr: "value2", + value: "brown", + scorer: "TFIDF" + } + }, + { + name: "ars-aql-phrase-score-bm25-high", + analyzers: true, + params: { + func: arangosearchScoring, + attr: "value2", + value: "brown", + scorer: "BM25" + } + }, + { + name: "ars-aql-phrase-low", + analyzers: true, + params: { + func: arangosearchPhrase, + attr: "value2", + value: "Low Phrase" + } + }, + { + name: "ars-aql-phrase-high", + analyzers: true, + params: { + func: arangosearchPhrase, + attr: "value2", + value: "Brown Planet" + } } - }, - { - name: "crud-any", - params: { - func: anyCrud, - setup: function (params) { - drop(params); - create(params); - fill(params); - }, - teardown: drop + ], + arangosearchNoMaterializationTests = [ + { + name: "ars-no-materialization-without-access-off", + params: { + func: arangosearchNoMaterializationWithoutAccessOff + } + }, + { + name: "ars-no-materialization-without-access-on", + params: { + func: arangosearchNoMaterializationWithoutAccessOn + } + }, + { + name: "ars-no-materialization-with-return-off", + params: { + func: arangosearchNoMaterializationWithReturnOff, + attr: "value1" + } + }, + { + name: "ars-no-materialization-with-return-on", + params: { + func: arangosearchNoMaterializationWithReturnOn, + attr: "value1" + } + }, + { + name: "ars-no-materialization-with-sort-off", + params: { + func: arangosearchNoMaterializationWithSortOff, + attr0: "value1", + attr1: "value2", + attr2: "value3" + } + }, + { + name: "ars-no-materialization-with-sort-on", + params: { + func: arangosearchNoMaterializationWithSortOn, + attr0: "value1", + attr1: "value2", + attr2: "value3" + } + }, + { + name: "ars-no-materialization-with-sort-and-limit-off", + params: { + func: arangosearchNoMaterializationWithSortAndLimitOff, + attr0: "value1", + attr1: "value2", + attr2: "value3" + } + }, + { + name: "ars-no-materialization-with-sort-and-limit-on", + params: { + func: arangosearchNoMaterializationWithSortAndLimitOn, + attr0: "value1", + attr1: "value2", + attr2: "value3" + } } - } - ], - subqueryTests = [ -/* { - name: "aql-subquery-splicing-compare", - params: { func: subquerySplicingValidation, attr: "value1" } - }, */ - { - name: "aql-subquery-1", - params: { func: genericSubquerySplicing, - queryString: "FOR c IN @@c LET sub = (FOR s IN @@c FILTER s.@attr == c.@attr RETURN s) RETURN LENGTH(sub)", - bindParamModifier: function(param, bindParam) { - bindParam.attr = "value1"; - } - } - }, - { - name: "aql-subquery-2", - params: { func: genericSubquerySplicing, - queryString: "FOR c IN @@c LET sub = (FOR s IN 1..5 LET subsub = (FOR t IN @@c FILTER t.@attr == c.@attr + s RETURN t) FILTER LENGTH(subsub) > 0 RETURN s) RETURN LENGTH(sub)", - bindParamModifier: function(param, bindParam) { - bindParam.attr = "value1"; + ], + crudTests = [ + { + name: "crud-insert", + params: { + func: insert, + setupEachCall: function (params) { + drop(params); + create(params); + }, + teardown: drop + } + }, + { + name: "crud-insert-size4", + params: { + func: insert, + setupEachCall: function (params) { + drop(params); + create(params); + }, + teardown: drop, + docSize: 4 + } + }, + { + name: "crud-update", + params: { + func: update, + setupEachCall: function (params) { + drop(params); + create(params); + fill(params); + }, + teardown: drop + } + }, + { + name: "crud-replace", + params: { + func: replace, + setupEachCall: function (params) { + drop(params); + create(params); + fill(params); + }, + teardown: drop + } + }, + { + name: "crud-remove", + params: { + func: remove, + setupEachCall: function (params) { + drop(params); + create(params); + fill(params); + }, + teardown: drop + } + }, + { + name: "crud-count", + params: { + func: count, + setup: function (params) { + drop(params); + create(params); + fill(params); + }, + teardown: drop + } + }, + { + name: "crud-all", + params: { + func: all, + setup: function (params) { + drop(params); + create(params); + fill(params); + }, + teardown: drop + } + }, + { + name: "crud-truncate", + params: { + func: truncate, + setup: function (params) { + drop(params); + create(params); + fill(params); + }, + teardown: drop + } + }, + { + name: "crud-any", + params: { + func: anyCrud, + setup: function (params) { + drop(params); + create(params); + fill(params); + }, + teardown: drop } } - }, - { - name: "aql-subquery-min", - params: { func: genericSubquerySplicing, - queryString: "RETURN MIN(FOR c IN @@c RETURN c.@attr)", - bindParamModifier: function(param, bindParam) { - bindParam.attr = "value1"; - } - } - }, - { - name: "aql-subquery-min-no-index", - params: { func: genericSubquerySplicing, - queryString: "RETURN MIN(FOR c IN @@c RETURN c.@attr)", - bindParamModifier: function(param, bindParam) { - bindParam.attr = "value6"; - } - } - }, - { - name: "aql-subquery-max", - params: { func: genericSubquerySplicing, - queryString: "RETURN MAX(FOR c IN @@c RETURN c.@attr)", - bindParamModifier: function(param, bindParam) { - bindParam.attr = "value1"; - } - } - }, - { - name: "aql-subquery-shortest-path", - params: { func: genericSubquerySplicing, - queryString: ` + ], + subqueryTests = [ + /* { + name: "aql-subquery-splicing-compare", + params: { func: subquerySplicingValidation, attr: "value1" } + }, */ + { + name: "aql-subquery-1", + params: { + func: genericSubquerySplicing, + queryString: "FOR c IN @@c LET sub = (FOR s IN @@c FILTER s.@attr == c.@attr RETURN s) RETURN LENGTH(sub)", + bindParamModifier: function (param, bindParam) { + bindParam.attr = "value1"; + } + } + }, + { + name: "aql-subquery-2", + params: { + func: genericSubquerySplicing, + queryString: "FOR c IN @@c LET sub = (FOR s IN 1..5 LET subsub = (FOR t IN @@c FILTER t.@attr == c.@attr + s RETURN t) FILTER LENGTH(subsub) > 0 RETURN s) RETURN LENGTH(sub)", + bindParamModifier: function (param, bindParam) { + bindParam.attr = "value1"; + } + } + }, + { + name: "aql-subquery-min", + params: { + func: genericSubquerySplicing, + queryString: "RETURN MIN(FOR c IN @@c RETURN c.@attr)", + bindParamModifier: function (param, bindParam) { + bindParam.attr = "value1"; + } + } + }, + { + name: "aql-subquery-min-no-index", + params: { + func: genericSubquerySplicing, + queryString: "RETURN MIN(FOR c IN @@c RETURN c.@attr)", + bindParamModifier: function (param, bindParam) { + bindParam.attr = "value6"; + } + } + }, + { + name: "aql-subquery-max", + params: { + func: genericSubquerySplicing, + queryString: "RETURN MAX(FOR c IN @@c RETURN c.@attr)", + bindParamModifier: function (param, bindParam) { + bindParam.attr = "value1"; + } + } + }, + { + name: "aql-subquery-shortest-path", + params: { + func: genericSubquerySplicing, + queryString: ` FOR v IN @@c LET hasPath = (FOR s IN INBOUND SHORTEST_PATH v TO @source @@e RETURN 1) FILTER LENGTH(hasPath) > 0 RETURN v `, - edgesRequired: true, - bindParamModifier: function(param, bindParam) { - bindParam.source = `${param.collection}/test2`; - } - } - }, - { + edgesRequired: true, + bindParamModifier: function (param, bindParam) { + bindParam.source = `${param.collection}/test2`; + } + } + }, + { name: "aql-subquery-traversal", - params: { func: genericSubquerySplicing, - queryString: ` + params: { + func: genericSubquerySplicing, + queryString: ` FOR v IN @@c FOR main IN 1 OUTBOUND v @@e LET subs = ( @@ -2559,479 +2656,489 @@ exports.test = function (global) { ) RETURN {main, subs} `, - attr: "value1", - edgesRequired: true, - bindParamModifier: function(param, bindParam) { delete bindParam.attr; } - } - }, - /* - * This test is disabled, because it takes far too long for a simple - * performance test. This is because some of the involved attributes - * are not indexed. - { - name: "aql-multi-subqueries-some-no-index", - params: { func: genericSubquerySplicing, - queryString: `FOR c IN @@c - LET sub1 = (FOR s IN @@c FILTER s.@attr == c.@attr RETURN s) - LET sub2 = (FOR s IN @@c FILTER s.@attr2 == c.@attr RETURN s) - LET sub3 = (FOR s IN @@c FILTER s.@attr3 == c.@attr RETURN s) - LET sub4 = (FOR s IN @@c FILTER s.@attr4 == c.@attr RETURN s) - LET sub5 = (FOR s IN @@c FILTER s.@attr5 == c.@attr RETURN s) - RETURN LENGTH(sub1) + LENGTH(sub2) + LENGTH(sub3) + LENGTH(sub4) + LENGTH(sub5) - `, - bindParamModifier: function(param, bindParam) { - bindParam.attr = "value1"; - bindParam.attr2 = "value2"; - bindParam.attr3 = "value3"; - bindParam.attr4 = "value4"; - bindParam.attr5 = "value5"; - } - } - }, */ - { - name: "aql-smart-graph", - params: { func: genericSubquerySplicing, - queryString: `FOR c IN @@c + attr: "value1", + edgesRequired: true, + bindParamModifier: function (param, bindParam) { delete bindParam.attr; } + } + }, + /* + * This test is disabled, because it takes far too long for a simple + * performance test. This is because some of the involved attributes + * are not indexed. + { + name: "aql-multi-subqueries-some-no-index", + params: { func: genericSubquerySplicing, + queryString: `FOR c IN @@c + LET sub1 = (FOR s IN @@c FILTER s.@attr == c.@attr RETURN s) + LET sub2 = (FOR s IN @@c FILTER s.@attr2 == c.@attr RETURN s) + LET sub3 = (FOR s IN @@c FILTER s.@attr3 == c.@attr RETURN s) + LET sub4 = (FOR s IN @@c FILTER s.@attr4 == c.@attr RETURN s) + LET sub5 = (FOR s IN @@c FILTER s.@attr5 == c.@attr RETURN s) + RETURN LENGTH(sub1) + LENGTH(sub2) + LENGTH(sub3) + LENGTH(sub4) + LENGTH(sub5) + `, + bindParamModifier: function(param, bindParam) { + bindParam.attr = "value1"; + bindParam.attr2 = "value2"; + bindParam.attr3 = "value3"; + bindParam.attr4 = "value4"; + bindParam.attr5 = "value5"; + } + } + }, */ + { + name: "aql-smart-graph", + params: { + func: genericSubquerySplicing, + queryString: `FOR c IN @@c LET sub1 = (FOR s IN @@c FILTER s.@attr == c.@attr RETURN s) LET sub2 = (FOR s IN @@c FILTER s.@attr2 == c.@attr RETURN s) RETURN LENGTH(sub1) + LENGTH(sub2) `, - bindParamModifier: function(param, bindParam) { - bindParam.attr = "value1"; - bindParam.attr2 = "value2"; - } - } - } - ], - satelliteGraphTests = [ - { - name: "aql-traversal-index-join", - params: { func: genericSatelliteGraph, - queryString: ` + bindParamModifier: function (param, bindParam) { + bindParam.attr = "value1"; + bindParam.attr2 = "value2"; + } + } + } + ], + satelliteGraphTests = [ + { + name: "aql-traversal-index-join", + params: { + func: genericSatelliteGraph, + queryString: ` FOR v, e, p IN 1..3 OUTBOUND CONCAT(@v, "/smart0:test0") GRAPH @g FOR doc in @@c FILTER doc.value1 == v.value1 RETURN doc ` } - }, - { - name: "aql-traversal-graph", - params: { func: genericSatelliteGraph, - queryString: ` + }, + { + name: "aql-traversal-graph", + params: { + func: genericSatelliteGraph, + queryString: ` FOR v, e, p IN 1..3 OUTBOUND CONCAT(@v, "/smart0:test0") GRAPH @g return v`, - bindParamModifier: function(param, bindParam) { delete bindParam["@c"]; } - } - }, - { - name: "aql-index-traversal-graph", - params: { func: genericSatelliteGraph, - queryString: ` + bindParamModifier: function (param, bindParam) { delete bindParam["@c"]; } + } + }, + { + name: "aql-index-traversal-graph", + params: { + func: genericSatelliteGraph, + queryString: ` for doc in @@c filter doc.value1 >= 0 and doc.value1 <= 10 let vkey = CONCAT(@v,"/smart", doc.value3, ":test", doc.value3) for v, e, p in 1..4 outbound vkey graph @g return {doc, p} `, - } - }, - { - name: "aql-enum-collection-traversal-graph", - params: { func: genericSatelliteGraph, - queryString: ` + } + }, + { + name: "aql-enum-collection-traversal-graph", + params: { + func: genericSatelliteGraph, + queryString: ` for doc in @@c let vkey = CONCAT(@v,"/smart", doc.value3, ":test", doc.value3) for v, e, p in 1..4 outbound vkey graph @g filter v.value1 <= doc.value1 return {doc, p} `, - } - } - ], - disjointSmartGraphTests = [ - { - name: "aql-traversal-index-join", - params: { func: genericDisjointSmartGraph, - queryString: ` - FOR v, e, p IN 1..3 OUTBOUND CONCAT(@v, "/smart0:test0") GRAPH @g + } + } + ], + disjointSmartGraphTests = [ + { + name: "aql-traversal-index-join", + params: { + func: genericDisjointSmartGraph, + queryString: ` + FOR s IN @startVertices + FOR v, e, p IN 1..3 OUTBOUND s GRAPH @g FOR doc in @@c FILTER doc.value1 == v.value1 RETURN doc ` } - }, - { - name: "aql-traversal-graph", - params: { func: genericDisjointSmartGraph, - queryString: ` + }, + { + name: "aql-traversal-graph", + params: { + func: genericDisjointSmartGraph, + queryString: ` FOR v, e, p IN 1..3 OUTBOUND CONCAT(@v, "/smart0:test0") GRAPH @g return v`, - bindParamModifier: function(param, bindParam) { delete bindParam["@c"]; } - } - }, - { - name: "aql-index-traversal-graph", - params: { func: genericDisjointSmartGraph, - queryString: ` + bindParamModifier: function (param, bindParam) { delete bindParam["@c"]; } + } + }, + { + name: "aql-index-traversal-graph", + params: { + func: genericDisjointSmartGraph, + queryString: ` for doc in @@c filter doc.value1 >= 0 and doc.value1 <= 10 let vkey = CONCAT(@v,"/smart", doc.value3, ":test", doc.value3) for v, e, p in 1..4 outbound vkey graph @g return {doc, p} `, - } - }, - { - name: "aql-enum-collection-traversal-graph", - params: { func: genericDisjointSmartGraph, - queryString: ` + } + }, + { + name: "aql-enum-collection-traversal-graph", + params: { + func: genericDisjointSmartGraph, + queryString: ` for doc in @@c let vkey = CONCAT(@v,"/smart", doc.value3, ":test", doc.value3) for v, e, p in 1..4 outbound vkey graph @g filter v.value1 <= doc.value1 return {doc, p} `, + } } - } - ]; - - const runSatelliteGraphTests = (global.satelliteGraphTests && isEnterprise && isCluster); - const runDisjointSmartGraphTests = (global.disjointSmartGraphTests && isEnterprise && isCluster); - - if (global.documents || global.edges || global.search || - global.noMaterializationSearch || global.subqueryTests || runSatelliteGraphTests || runDisjointSmartGraphTests) { - initializeValuesCollection(); - } - if (global.edges || global.subqueryTests) { - initializeEdgeCollection(); - } - if (runSatelliteGraphTests || runDisjointSmartGraphTests) { - initializeGraphs(); - } - if (global.search) { - initializeView(); - } - if (global.phrase) { - initializePhrasesView(); - } - if (global.noMaterializationSearch) { - initializeStoredValuesView(); - } - - let output = "", - csv = "", - options; - - // document tests - if (global.documents) { - options = { - runs: 5, - digits: 4, - setup: function (params) { - db._collection(params.collection).load(); - }, - teardown: function () {}, - collections: [], - removeFromResult: 1 - }; + ]; + + const runSatelliteGraphTests = (global.satelliteGraphTests && isEnterprise && isCluster); + const runDisjointSmartGraphTests = (global.disjointSmartGraphTests && isEnterprise && isCluster); + let disjointGraphs = []; + if (global.documents || global.edges || global.search || + global.noMaterializationSearch || global.subqueryTests || runSatelliteGraphTests || runDisjointSmartGraphTests) { + initializeValuesCollection(); + } + if (global.edges || global.subqueryTests) { + initializeEdgeCollection(); + } + if (runSatelliteGraphTests || runDisjointSmartGraphTests) { + disjointGraphs = initializeGraphs(); + } + if (global.search) { + initializeView(); + } + if (global.phrase) { + initializePhrasesView(); + } + if (global.noMaterializationSearch) { + initializeStoredValuesView(); + } + + let output = "", + csv = "", + options; + + // document tests + if (global.documents) { + options = { + runs: 5, + digits: 4, + setup: function (params) { + db._collection(params.collection).load(); + }, + teardown: function () { }, + collections: [], + removeFromResult: 1 + }; - if (global.small) { - options.collections.push({ name: "values10000", label: "10k", size: 10000 }); - } + if (global.small) { + options.collections.push({ name: "values10000", label: "10k", size: 10000 }); + } - if (global.medium) { - options.collections.push({ name: "values100000", label: "100k", size: 100000 }); - } + if (global.medium) { + options.collections.push({ name: "values100000", label: "100k", size: 100000 }); + } - if (global.big) { - options.collections.push({ name: "values1000000", label: "1000k", size: 1000000 }); - } + if (global.big) { + options.collections.push({ name: "values1000000", label: "1000k", size: 1000000 }); + } - let documentTestsResult = testRunner(documentTests, options); - output += toString("Documents", documentTestsResult) + "\n\n"; + let documentTestsResult = testRunner(documentTests, options); + output += toString("Documents", documentTestsResult) + "\n\n"; - if (global.outputXml) { - toJUnit(documentTestsResult); - } + if (global.outputXml) { + toJUnit(documentTestsResult); + } - if (global.outputCsv) { - csv += toCsv(documentTestsResult); + if (global.outputCsv) { + csv += toCsv(documentTestsResult); + } } - } - // edge tests - if (global.edges) { - options = { - runs: 5, - digits: 4, - setup: function (params) { - db._collection(params.collection).load(); - }, - teardown: function () {}, - collections: [], - removeFromResult: 1 - }; + // edge tests + if (global.edges) { + options = { + runs: 5, + digits: 4, + setup: function (params) { + db._collection(params.collection).load(); + }, + teardown: function () { }, + collections: [], + removeFromResult: 1 + }; - if (global.small) { - options.collections.push({ name: "edges10000", label: "10k", size: 10000 }); - } + if (global.small) { + options.collections.push({ name: "edges10000", label: "10k", size: 10000 }); + } - if (global.medium) { - options.collections.push({ name: "edges100000", label: "100k", size: 100000 }); - } + if (global.medium) { + options.collections.push({ name: "edges100000", label: "100k", size: 100000 }); + } - if (global.big) { - options.collections.push({ name: "edges1000000", label: "1000k", size: 1000000 }); - } + if (global.big) { + options.collections.push({ name: "edges1000000", label: "1000k", size: 1000000 }); + } - let edgeTestsResult = testRunner(edgeTests, options); - output += toString("Edges", edgeTestsResult) + "\n\n"; + let edgeTestsResult = testRunner(edgeTests, options); + output += toString("Edges", edgeTestsResult) + "\n\n"; - if (global.outputXml) { - toJUnit(edgeTestsResult); - } + if (global.outputXml) { + toJUnit(edgeTestsResult); + } - if (global.outputCsv) { - csv += toCsv(edgeTestsResult); + if (global.outputCsv) { + csv += toCsv(edgeTestsResult); + } } - } - // arangosearch tests - if (global.search) { - options = { - runs: 5, - digits: 4, - setup: function (params) { - params["view"] = "v_" + params.collection; - params["offset"] = params.collectionSize / 10; - params["limit"] = params.collectionSize / 2; - }, - teardown: function () {}, - collections: [], - removeFromResult: 1 - }; + // arangosearch tests + if (global.search) { + options = { + runs: 5, + digits: 4, + setup: function (params) { + params["view"] = "v_" + params.collection; + params["offset"] = params.collectionSize / 10; + params["limit"] = params.collectionSize / 2; + }, + teardown: function () { }, + collections: [], + removeFromResult: 1 + }; - if (global.small) { - options.collections.push({ name: "values10000", label: "10k", size: 10000}); - } + if (global.small) { + options.collections.push({ name: "values10000", label: "10k", size: 10000 }); + } - if (global.medium) { - options.collections.push({ name: "values100000", label: "100k", size: 100000 }); - } + if (global.medium) { + options.collections.push({ name: "values100000", label: "100k", size: 100000 }); + } - if (global.big) { - options.collections.push({ name: "values1000000", label: "1000k", size: 1000000 }); - } + if (global.big) { + options.collections.push({ name: "values1000000", label: "1000k", size: 1000000 }); + } - let arangosearchTestsResult = testRunner(arangosearchTests, options); - output += toString("Arango Search", arangosearchTestsResult) + "\n\n"; + let arangosearchTestsResult = testRunner(arangosearchTests, options); + output += toString("Arango Search", arangosearchTestsResult) + "\n\n"; - if (global.outputXml) { - toJUnit(arangosearchTestsResult); - } + if (global.outputXml) { + toJUnit(arangosearchTestsResult); + } - if (global.outputCsv) { - csv += toCsv(arangosearchTestsResult); + if (global.outputCsv) { + csv += toCsv(arangosearchTestsResult); + } } - } - // arangosearch phrase tests - if (global.phrase) { - options = { - runs: 5, - digits: 4, - setup: function (params) { - params["view"] = "v_" + params.collection; - }, - teardown: function () {}, - collections: [], - removeFromResult: 1 - }; + // arangosearch phrase tests + if (global.phrase) { + options = { + runs: 5, + digits: 4, + setup: function (params) { + params["view"] = "v_" + params.collection; + }, + teardown: function () { }, + collections: [], + removeFromResult: 1 + }; - if (global.small) { - options.collections.push({ - name: "valuesPhrases10000", - label: "10k", - size: 10000 - }); - } + if (global.small) { + options.collections.push({ + name: "valuesPhrases10000", + label: "10k", + size: 10000 + }); + } - if (global.medium) { - options.collections.push({ - name: "valuesPhrases100000", - label: "100k", - size: 100000 - }); - } + if (global.medium) { + options.collections.push({ + name: "valuesPhrases100000", + label: "100k", + size: 100000 + }); + } - if (global.big) { - options.collections.push({ - name: "valuesPhrases10000000", - label: "10000k", - size: 10000000 - }); - } + if (global.big) { + options.collections.push({ + name: "valuesPhrases10000000", + label: "10000k", + size: 10000000 + }); + } - let arangosearchPhrasesTestsResult = testRunner( - arangosearchPhrasesTests, - options - ); - output += - toString("Arango Search Phrases", arangosearchPhrasesTestsResult) + - "\n\n"; + let arangosearchPhrasesTestsResult = testRunner( + arangosearchPhrasesTests, + options + ); + output += + toString("Arango Search Phrases", arangosearchPhrasesTestsResult) + + "\n\n"; - if (global.outputXml) { - toJUnit(arangosearchPhrasesTestsResult); - } + if (global.outputXml) { + toJUnit(arangosearchPhrasesTestsResult); + } - if (global.outputCsv) { - csv += toCsv(arangosearchPhrasesTestsResult); + if (global.outputCsv) { + csv += toCsv(arangosearchPhrasesTestsResult); + } } - } - // arangosearch no materialization tests - if (global.noMaterializationSearch) { - options = { - runs: 5, - digits: 4, - setup: function (params) { - params["view"] = "v_stored_" + params.collection; - }, - teardown: function () {}, - collections: [], - removeFromResult: 1 - }; + // arangosearch no materialization tests + if (global.noMaterializationSearch) { + options = { + runs: 5, + digits: 4, + setup: function (params) { + params["view"] = "v_stored_" + params.collection; + }, + teardown: function () { }, + collections: [], + removeFromResult: 1 + }; - if (global.small) { - options.collections.push({ name: "values10000", label: "10k", size: 10000}); - } + if (global.small) { + options.collections.push({ name: "values10000", label: "10k", size: 10000 }); + } - if (global.medium) { - options.collections.push({ name: "values100000", label: "100k", size: 100000 }); - } + if (global.medium) { + options.collections.push({ name: "values100000", label: "100k", size: 100000 }); + } - if (global.big) { - options.collections.push({ name: "values1000000", label: "1000k", size: 1000000 }); - } + if (global.big) { + options.collections.push({ name: "values1000000", label: "1000k", size: 1000000 }); + } - let arangosearchNoMaterializationTestsResult = testRunner(arangosearchNoMaterializationTests, options); - output += toString("Arango Search No Materialization", arangosearchNoMaterializationTestsResult) + "\n\n"; + let arangosearchNoMaterializationTestsResult = testRunner(arangosearchNoMaterializationTests, options); + output += toString("Arango Search No Materialization", arangosearchNoMaterializationTestsResult) + "\n\n"; - if (global.outputXml) { - toJUnit(arangosearchNoMaterializationTestsResult); - } + if (global.outputXml) { + toJUnit(arangosearchNoMaterializationTestsResult); + } - if (global.outputCsv) { - csv += toCsv(arangosearchNoMaterializationTestsResult); + if (global.outputCsv) { + csv += toCsv(arangosearchNoMaterializationTestsResult); + } } - } - // crud tests - if (global.crud) { - options = { - runs: 5, - digits: 4, - setup: function (/* params */) {}, - teardown: function () {}, - collections: [], - removeFromResult: 1 - }; + // crud tests + if (global.crud) { + options = { + runs: 5, + digits: 4, + setup: function (/* params */) { }, + teardown: function () { }, + collections: [], + removeFromResult: 1 + }; - if (global.small) { - options.collections.push({ name: "crud10000", label: "10k", size: 10000 }); - } + if (global.small) { + options.collections.push({ name: "crud10000", label: "10k", size: 10000 }); + } - if (global.medium) { - options.collections.push({ name: "crud100000", label: "100k", size: 100000 }); - } + if (global.medium) { + options.collections.push({ name: "crud100000", label: "100k", size: 100000 }); + } - if (global.big) { - options.collections.push({ name: "crud1000000", label: "1000k", size: 1000000 }); - } + if (global.big) { + options.collections.push({ name: "crud1000000", label: "1000k", size: 1000000 }); + } - let crudTestsResult = testRunner(crudTests, options); - output += toString("CRUD", crudTestsResult) + "\n\n"; + let crudTestsResult = testRunner(crudTests, options); + output += toString("CRUD", crudTestsResult) + "\n\n"; - if (global.outputXml) { - toJUnit(crudTestsResult); - } + if (global.outputXml) { + toJUnit(crudTestsResult); + } - if (global.outputCsv) { - csv += toCsv(crudTestsResult); + if (global.outputCsv) { + csv += toCsv(crudTestsResult); + } } - } - // arangosearch crud tests - if (global.crudSearch) { - options = { - runs: 5, - digits: 4, - setup: function (params) { - params["view"] = "v_" + params.collection; - }, - teardown: function () {}, - collections: [], - removeFromResult: 1 - }; + // arangosearch crud tests + if (global.crudSearch) { + options = { + runs: 5, + digits: 4, + setup: function (params) { + params["view"] = "v_" + params.collection; + }, + teardown: function () { }, + collections: [], + removeFromResult: 1 + }; - if (global.small) { - options.collections.push({ name: "crud10000", label: "10k + ARS", size: 10000 }); - } + if (global.small) { + options.collections.push({ name: "crud10000", label: "10k + ARS", size: 10000 }); + } - if (global.medium) { - options.collections.push({ name: "crud100000", label: "100k + ARS", size: 100000 }); - } + if (global.medium) { + options.collections.push({ name: "crud100000", label: "100k + ARS", size: 100000 }); + } - if (global.big) { - options.collections.push({ - name: "crud1000000", - label: "1000k + ARS", - size: 1000000 - }); - } + if (global.big) { + options.collections.push({ + name: "crud1000000", + label: "1000k + ARS", + size: 1000000 + }); + } - let arangosearchCrudTestsResult = testRunner(crudTests, options); - output += - toString("Arango Search CRUD", arangosearchCrudTestsResult) + "\n\n"; + let arangosearchCrudTestsResult = testRunner(crudTests, options); + output += + toString("Arango Search CRUD", arangosearchCrudTestsResult) + "\n\n"; - if (global.outputXml) { - toJUnit(arangosearchCrudTestsResult, "ars-", ""); - } + if (global.outputXml) { + toJUnit(arangosearchCrudTestsResult, "ars-", ""); + } - if (global.outputCsv) { - csv += toCsv(arangosearchCrudTestsResult, "ars-", ""); + if (global.outputCsv) { + csv += toCsv(arangosearchCrudTestsResult, "ars-", ""); + } } - } - if (global.subqueryTests) { - options = { - runs: 5, - digits: 4, - setup: function (params) { - db._collection(params.collection).load(); - if (params.edgesRequired === true) { - db._collection(params.collection.replace("vertices", "edges")).load(); - } - }, - teardown: function () {}, - collections: [], - removeFromResult: 1 - }; + if (global.subqueryTests) { + options = { + runs: 5, + digits: 4, + setup: function (params) { + db._collection(params.collection).load(); + if (params.edgesRequired === true) { + db._collection(params.collection.replace("vertices", "edges")).load(); + } + }, + teardown: function () { }, + collections: [], + removeFromResult: 1 + }; - if (global.small) { - options.collections.push({ name: "values10000", label: "10k", size: 10000 }); - } + if (global.small) { + options.collections.push({ name: "values10000", label: "10k", size: 10000 }); + } - if (global.medium) { - options.collections.push({ name: "values100000", label: "100k", size: 100000 }); - } + if (global.medium) { + options.collections.push({ name: "values100000", label: "100k", size: 100000 }); + } - if (global.big) { - options.collections.push({ name: "values1000000", label: "1000k", size: 1000000 }); - } + if (global.big) { + options.collections.push({ name: "values1000000", label: "1000k", size: 1000000 }); + } - /* We run each test case with splicing enabled and with splicing disabled */ - var subqueryTestsCases = []; - subqueryTests.forEach( function(item, index) { + /* We run each test case with splicing enabled and with splicing disabled */ + var subqueryTestsCases = []; + subqueryTests.forEach(function (item, index) { var noSplicingCase = _.cloneDeep(item); noSplicingCase.name = noSplicingCase.name + "-no-splicing"; noSplicingCase.params.splice = false; @@ -3040,80 +3147,97 @@ exports.test = function (global) { yesSplicingCase.name = yesSplicingCase.name + "-yes-splicing"; yesSplicingCase.params.splice = true; subqueryTestsCases.push(yesSplicingCase); - }); + }); - let subqueryTestsResult = testRunner(subqueryTestsCases, options); - output += - toString("Subquery Performance", subqueryTestsResult) + "\n\n"; + let subqueryTestsResult = testRunner(subqueryTestsCases, options); + output += + toString("Subquery Performance", subqueryTestsResult) + "\n\n"; - if (global.outputXml) { - toJUnit(subqueryTestsResult); - } + if (global.outputXml) { + toJUnit(subqueryTestsResult); + } - if (global.outputCsv) { - csv += toCsv(subqueryTestsResult); + if (global.outputCsv) { + csv += toCsv(subqueryTestsResult); + } } - } - if (global.satelliteGraphTests) { - options = { - runs: 5, - digits: 4, - setup: function (params) {}, - teardown: function () {}, - collections: [], - removeFromResult: 1 - }; + if (global.satelliteGraphTests) { + options = { + runs: 5, + digits: 4, + setup: function (params) { }, + teardown: function () { }, + collections: [], + removeFromResult: 1 + }; - if (global.small) { - options.collections.push({ name: "values10000", label: "10k", size: 10000 }); - } + if (global.small) { + options.collections.push({ name: "values10000", label: "10k", size: 10000 }); + } - if (global.medium) { - options.collections.push({ name: "values100000", label: "100k", size: 100000 }); - } + if (global.medium) { + options.collections.push({ name: "values100000", label: "100k", size: 100000 }); + } - if (global.big) { - options.collections.push({ name: "values1000000", label: "1000k", size: 1000000 }); - } - - var satelliteTestsCases = []; - satelliteGraphTests.forEach( function(item, index) { - let communityCase = _.cloneDeep(item); - communityCase.name = communityCase.name + "-community"; - communityCase.params.graph = "comm"; - satelliteTestsCases.push(communityCase); - let smartCase = _.cloneDeep(item); - smartCase.name = smartCase.name + "-smart"; - smartCase.params.graph = "smart"; - satelliteTestsCases.push(smartCase); - if (supportsSatelliteGraphs) { - let satelliteCase = _.cloneDeep(item); - satelliteCase.name = satelliteCase.name + "-satellite"; - satelliteCase.params.graph = "sat"; - satelliteTestsCases.push(satelliteCase); - } + if (global.big) { + options.collections.push({ name: "values1000000", label: "1000k", size: 1000000 }); + } - if (supportsDisjointSmartGraphs) { - let disjointSmartCase = _.cloneDeep(item); - disjointSmartCase.name = disjointSmartCase.name + "-disjointSmart"; - disjointSmartCase.params.graph = "disjointSmartGraph"; - satelliteTestsCases.push(disjointSmartCase); + const satelliteTestsCases = []; + const addSatelliteTestCase = (item, name, graph) => { + let caseItem = _.cloneDeep(item); + caseItem.name += `-${name}`; + caseItem.params.graph = graph; + satelliteTestsCases.push(caseItem); + }; + satelliteGraphTests.forEach((item) => { + addSatelliteTestCase(item, "community", "comm"); + addSatelliteTestCase(item, "smart", "smart"); + if (supportsSatelliteGraphs) { + addSatelliteTestCase(item, "satellite", "sat"); } - }); + }); - let satelliteTestsResult = testRunner(satelliteTestsCases, options); - output += - toString("Satellite Graph Performance", satelliteTestsResult) + "\n\n"; + let satelliteTestsResult = testRunner(satelliteTestsCases, options); + output += + toString("Satellite Graph Performance", satelliteTestsResult) + "\n\n"; + + if (global.outputXml) { + toJUnit(satelliteTestsResult); + } - if (global.outputXml) { - toJUnit(satelliteTestsResult); + if (global.outputCsv) { + csv += toCsv(satelliteTestsResult); + } } + if (global.disjointSmartGraphTests) { + const disjointTestCases = []; + const addDisjointTestCase = (item, graphGen) => { + let caseItem = _.cloneDeep(item); + caseItem.name += `-${graphGen.namePostfix()}`; + caseItem.params.graph = graphGen; + disjointTestCases.push(caseItem); + }; + + for (const g of disjointGraphs) { + for (const item of disjointSmartGraphTests) { + addDisjointTestCase(item, g); + } + } + + let disjointSmartTestsResult = testRunner(disjointTestCases, options); + output += + toString("Disjoint Graph Performance", disjointSmartTestsResult) + "\n\n"; + + if (global.outputXml) { + toJUnit(disjointSmartTestsResult); + } - if (global.outputCsv) { - csv += toCsv(satelliteTestsResult); + if (global.outputCsv) { + csv += toCsv(disjointSmartTestsResult); + } } - } // OneShard Feature ///////////////////////////////////////////////////// if (global.oneshardTests) { From 6eef4016b60d177cef01d49c988277e973e058e1 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Tue, 23 Jun 2020 12:05:44 +0200 Subject: [PATCH 7/8] Further refactoring --- test.js | 105 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 30 deletions(-) diff --git a/test.js b/test.js index bf3947ad..2fd5347e 100644 --- a/test.js +++ b/test.js @@ -43,7 +43,7 @@ exports.test = function (global) { // This is a seedable RandomNumberGenerator // it is not operfect for Random numbers, // but good enough for what we are doing here - function* RandomNumberGenerator(seed) { + function* randomNumberGenerator (seed) { while (true) { const nextVal = Math.cos(seed++) * 10000; yield nextVal - Math.floor(nextVal); @@ -51,9 +51,9 @@ exports.test = function (global) { }; class GraphGenerator { - constructor (nameprefix, type, runnerName, scale) { - this._rand = new RandomNumberGenerator(42); - this._name = `${nameprefix}${type}${runnerName}${scale}`; + constructor(nameprefix, type, runnerName, scale) { + this._resetRand(); + this._name = `${nameprefix}${runnerName}${scale}`; this._runnerName = `${runnerName}-${scale}`; switch (scale) { case "small": @@ -93,7 +93,7 @@ exports.test = function (global) { } _resetRand () { - this._rand = new RandomNumberGenerator(42); + this._rand = randomNumberGenerator(42); } _ensureDatastructure (type) { @@ -108,7 +108,7 @@ exports.test = function (global) { this._graph = this._module._graph(this.name()); this._needsData = false; } else { - const rel = [this.graph_module._relation(edgeCollectionName, vertexCollectionName, vertexCollectionName)]; + const rel = [this._module._relation(edgeCollectionName, vertexCollectionName, vertexCollectionName)]; const options = {}; switch (type) { case "comm": @@ -126,9 +126,12 @@ exports.test = function (global) { this._needsData = true; } this._vCol = this._graph[vertexCollectionName]; - this._eCol = this._graph[edgeCollectionName]; + this._eCol = db[edgeCollectionName]; } + name () { + return this._name; + } vertexCollection () { return this._vCol; } @@ -189,7 +192,7 @@ exports.test = function (global) { // done before. this._resetRand(); // Hihi Javascript - return Array.from({ length }).map(_ => this.genId(this.randomId())); + return Array.from({ length }).map(_ => this.randomId()).map(id => { return { _id: this.genId(id), _key: this.genKey(id) }; } ); } vertexData (i) { @@ -241,7 +244,7 @@ exports.test = function (global) { let sum = function (values) { return values.reduce(function (previous, current) { return previous + current; - }); + }, 0); }; values.sort(function (a, b) { @@ -689,7 +692,7 @@ exports.test = function (global) { } function fillGraphEdges(c, n, vc) { - print("Filling edges for ", c.name()) + print("Filling edges for ", c.name()); let j = 0, k = 50, l = 0; @@ -713,7 +716,7 @@ exports.test = function (global) { } function fillGraphVertexes(c, n, g) { - print("Filling Vertexes for ", c.name()) + print("Filling Vertexes for ", c.name()); fillCollection(c, n, function (i) { return { _key: "smart" + i + ":test" + i, @@ -778,6 +781,7 @@ exports.test = function (global) { fillCollection(graph.edgeCollection(), graph.numEdges(), graph.edgeData.bind(graph)); } + return graph; }; const addGraphsForScale = (scale) => { @@ -1913,20 +1917,10 @@ exports.test = function (global) { }, genericDisjointSmartGraph = function (params) { - let numVertices = 0; - if (global.small) { - numVertices = 10000; - } else if (global.medium) { - numVertices = 100000; - } else if (global.big) { - numVertices = 1000000; - } - const gen = new GraphGenerator(params.vCol, params.eCol, numVertices) - let bindParam = { "@c": params.collection, - "g": params.graph, - "startVertices": gen.getRandomStartVertices(100) + "g": params.graph.name(), + "startVertices": params.graph.getRandomStartVertices(100) }; if ('bindParamModifier' in params) { @@ -2768,11 +2762,40 @@ exports.test = function (global) { params: { func: genericDisjointSmartGraph, queryString: ` - FOR v, e, p IN 1..3 OUTBOUND CONCAT(@v, "/smart0:test0") GRAPH @g + FOR s IN @startVertices + FOR v, e, p IN 1..3 OUTBOUND s GRAPH @g return v`, bindParamModifier: function (param, bindParam) { delete bindParam["@c"]; } } }, + { + name: "aql-traversal-graph-graph", + params: { + func: genericDisjointSmartGraph, + queryString: ` + FOR s IN @startVertices + FOR v, e, p IN 1 OUTBOUND s GRAPH @g + FOR v1, e1, p1 IN 1 OUTBOUND v GRAPH @g + return v1`, + bindParamModifier: function (param, bindParam) { delete bindParam["@c"]; } + } + }, + { + name: "aql-traversal-subquery-graph-graph", + params: { + func: genericDisjointSmartGraph, + queryString: ` + FOR s IN @startVertices + LET sub1 = ( + FOR v, e, p IN 1 OUTBOUND s GRAPH @g + RETURN v._key) + LET sub2 = ( + FOR v, e, p IN 1 INBOUND s GRAPH @g + RETURN v._key) + RETURN [sub1, sub2]`, + bindParamModifier: function (param, bindParam) { delete bindParam["@c"]; } + } + }, { name: "aql-index-traversal-graph", params: { @@ -2780,8 +2803,8 @@ exports.test = function (global) { queryString: ` for doc in @@c filter doc.value1 >= 0 and doc.value1 <= 10 - let vkey = CONCAT(@v,"/smart", doc.value3, ":test", doc.value3) - for v, e, p in 1..4 outbound vkey graph @g + FOR s IN @startVertices + for v, e, p in 1..4 outbound s GRAPH @g return {doc, p} `, } @@ -2792,8 +2815,8 @@ exports.test = function (global) { func: genericDisjointSmartGraph, queryString: ` for doc in @@c - let vkey = CONCAT(@v,"/smart", doc.value3, ":test", doc.value3) - for v, e, p in 1..4 outbound vkey graph @g + FOR s IN @startVertices + for v, e, p in 1..4 outbound s GRAPH @g filter v.value1 <= doc.value1 return {doc, p} `, @@ -2812,6 +2835,7 @@ exports.test = function (global) { initializeEdgeCollection(); } if (runSatelliteGraphTests || runDisjointSmartGraphTests) { + print("Create graphs"); disjointGraphs = initializeGraphs(); } if (global.search) { @@ -3220,12 +3244,33 @@ exports.test = function (global) { disjointTestCases.push(caseItem); }; - for (const g of disjointGraphs) { + for (const graph of disjointGraphs) { for (const item of disjointSmartGraphTests) { - addDisjointTestCase(item, g); + addDisjointTestCase(item, graph); } } + options = { + runs: 5, + digits: 4, + setup: function (params) { }, + teardown: function () { }, + collections: [], + removeFromResult: 1 + }; + + if (global.small) { + options.collections.push({ name: "values10000", label: "10k", size: 10000 }); + } + + if (global.medium) { + options.collections.push({ name: "values100000", label: "100k", size: 100000 }); + } + + if (global.big) { + options.collections.push({ name: "values1000000", label: "1000k", size: 1000000 }); + } + let disjointSmartTestsResult = testRunner(disjointTestCases, options); output += toString("Disjoint Graph Performance", disjointSmartTestsResult) + "\n\n"; From 0d34451b872d8ab3813253362b3f40d44924ed61 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Wed, 11 Aug 2021 13:30:49 +0200 Subject: [PATCH 8/8] Moved test.js and runner to usbfolder as done in main meanwhile --- .../run-small-disjoint-smart-graphs.js | 0 test.js => simple/test.js | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename run-small-disjoint-smart-graphs.js => simple/run-small-disjoint-smart-graphs.js (100%) rename test.js => simple/test.js (100%) diff --git a/run-small-disjoint-smart-graphs.js b/simple/run-small-disjoint-smart-graphs.js similarity index 100% rename from run-small-disjoint-smart-graphs.js rename to simple/run-small-disjoint-smart-graphs.js diff --git a/test.js b/simple/test.js similarity index 100% rename from test.js rename to simple/test.js