diff --git a/CHANGELOG b/CHANGELOG index 469e5378bf69..9094cbe8297b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,11 +1,13 @@ devel ----- +* Added INTERLEAVE AQL function. + * Upgraded bundled RocksDB library to version 6.8.0. * Added AQL function `IN_RANGE`. -* Added startup option `--ssl.prefer-http1-in-alpn` to optionally let the +* Added startup option `--ssl.prefer-http1-in-alpn` to optionally let the server prefer HTTP/1.1 over HTTP/2 in ALPN protocol negotiations. * Compilation issues with wrong cv-qualifiers and unnecessary diff --git a/arangod/Aql/AqlFunctionFeature.cpp b/arangod/Aql/AqlFunctionFeature.cpp index 2c8e54c2dfdb..6b9eee457aa4 100644 --- a/arangod/Aql/AqlFunctionFeature.cpp +++ b/arangod/Aql/AqlFunctionFeature.cpp @@ -316,6 +316,7 @@ void AqlFunctionFeature::addListFunctions() { add({"REMOVE_VALUES", ".,.", flags, &Functions::RemoveValues}); add({"REMOVE_NTH", ".,.", flags, &Functions::RemoveNth}); add({"REPLACE_NTH", ".,.,.|.", flags, &Functions::ReplaceNth}); + add({"INTERLEAVE", ".,.|+", flags, &Functions::Interleave}); // special flags: // CALL and APPLY will always run on the coordinator and are not deterministic diff --git a/arangod/Aql/Functions.cpp b/arangod/Aql/Functions.cpp index 6c63fd3fd29e..c535b9025131 100644 --- a/arangod/Aql/Functions.cpp +++ b/arangod/Aql/Functions.cpp @@ -7523,3 +7523,54 @@ AqlValue Functions::NotImplemented(ExpressionContext* expressionContext, registerError(expressionContext, "UNKNOWN", TRI_ERROR_NOT_IMPLEMENTED); return AqlValue(AqlValueHintNull()); } + +AqlValue Functions::Interleave(arangodb::aql::ExpressionContext* expressionContext, + transaction::Methods* trx, + VPackFunctionParameters const& parameters) { + // cppcheck-suppress variableScope + static char const* AFN = "INTERLEAVE"; + + struct ArrayIteratorPair { + VPackArrayIterator current; + VPackArrayIterator end; + }; + + std::list iters; + std::vector materializers; + materializers.reserve(parameters.size()); + + for (AqlValue const& parameter : parameters) { + auto& materializer = materializers.emplace_back(trx); + VPackSlice slice = materializer.slice(parameter, true); + + if (!slice.isArray()) { + // not an array + registerWarning(expressionContext, AFN, TRI_ERROR_QUERY_ARRAY_EXPECTED); + return AqlValue(AqlValueHintNull()); + } else if (slice.isEmptyArray()) { + continue; // skip empty array here + } + + VPackArrayIterator iter(slice); + ArrayIteratorPair pair{iter.begin(), iter.end()}; + iters.emplace_back(pair); + } + + transaction::BuilderLeaser builder(trx); + builder->openArray(); + + while (!iters.empty()) { // in this loop we only deal with nonempty arrays + for (auto i = iters.begin(); i != iters.end();) { + builder->add(i->current.value()); // thus this will always be valid on the first iteration + i->current++; + if (i->current == i->end) { + i = iters.erase(i); + } else { + i++; + } + } + } + + builder->close(); + return AqlValue(builder.get()); +} diff --git a/arangod/Aql/Functions.h b/arangod/Aql/Functions.h index 6322e65291c0..d9b1c9960a4a 100644 --- a/arangod/Aql/Functions.h +++ b/arangod/Aql/Functions.h @@ -153,7 +153,7 @@ struct Functions { static AqlValue NgramSimilarity(ExpressionContext*, transaction::Methods*, VPackFunctionParameters const&); static AqlValue NgramPositionalSimilarity(ExpressionContext* ctx, - transaction::Methods*, + transaction::Methods*, VPackFunctionParameters const&); static AqlValue NgramMatch(ExpressionContext*, transaction::Methods*, VPackFunctionParameters const&); @@ -427,6 +427,8 @@ struct Functions { transaction::Methods*, VPackFunctionParameters const&); static AqlValue ReplaceNth(arangodb::aql::ExpressionContext*, transaction::Methods*, VPackFunctionParameters const&); + static AqlValue Interleave(arangodb::aql::ExpressionContext*, + transaction::Methods*, VPackFunctionParameters const&); static AqlValue NotNull(arangodb::aql::ExpressionContext*, transaction::Methods*, VPackFunctionParameters const&); static AqlValue CurrentDatabase(arangodb::aql::ExpressionContext*, diff --git a/tests/js/server/aql/aql-functions-list.js b/tests/js/server/aql/aql-functions-list.js index 7de07db1a878..b84879b65974 100644 --- a/tests/js/server/aql/aql-functions-list.js +++ b/tests/js/server/aql/aql-functions-list.js @@ -38,16 +38,16 @@ var assertQueryError = helper.assertQueryError; /// @brief test suite //////////////////////////////////////////////////////////////////////////////// -function ahuacatlListTestSuite () { +function ahuacatlListTestSuite() { var collectionName = "UnitTestList"; - var collection; + var collection; return { - setUpAll : function () { + setUpAll: function () { internal.db._drop(collectionName); collection = internal.db._create(collectionName); - + for (var i = 0; i < 10; ++i) { collection.save({_key: "test" + i}); } @@ -61,38 +61,42 @@ function ahuacatlListTestSuite () { /// @brief test push function //////////////////////////////////////////////////////////////////////////////// - testPush : function () { + testPush: function () { var data = [ - [ [ 1, 2, 3, 4 ], [ [ 1, 2, 3 ], 4 ] ], - [ [ 1, 2, 3, "foo" ], [ [ 1, 2, 3 ], "foo" ] ], - [ [ "foo", "bar", "baz", "foo" ], [ [ "foo", "bar", "baz", ], "foo" ] ], - [ [ "foo" ], [ null, "foo" ] ], - [ null, [ false, "foo" ] ], - [ null, [ 1, "foo" ] ], - [ [ "foo" ], [ [ ], "foo" ] ], - [ null, [ "foo", "foo" ] ], - [ null, [ { }, "foo" ] ], - [ [ "" ], [ [ ], "" ] ], - [ [ false, false ], [ [ false ], false ] ], - [ [ false, null ], [ [ false ], null ] ], - [ [ 0 ], [ [ ], 0, true ] ], - [ [ true, 1 ], [ [ true ], 1, true ] ], - [ [ true ], [ [ true ], true, true ] ], - [ [ true, true ], [ [ true ], true, false ] ], - [ [ "foo", "bar", "foo" ], [ [ "foo", "bar", "foo" ], "foo", true ] ], - [ [ "foo", [ ] ], [ [ "foo" ], [ ], true ] ], - [ [ "foo", [ ] ], [ [ "foo", [ ] ], [ ], true ] ], - [ [ "foo", [ ], [ ] ], [ [ "foo", [ ] ], [ ], false ] ], - [ [ { a: 1 }, { a: 2 }, { b: 1 } ], [ [ { a: 1 }, { a: 2 }, { b: 1 } ], { a: 1 }, true ] ], - [ [ { a: 1 }, { a: 2 }, { b: 1 }, { a: 1 } ], [ [ { a: 1 }, { a: 2 }, { b: 1 } ], { a: 1 }, false ] ], - [ [ { a: 1 }, { a: 2 }, { b: 1 }, { b: 2 } ], [ [ { a: 1 }, { a: 2 }, { b: 1 } ], { b: 2 }, true ] ] + [[1, 2, 3, 4], [[1, 2, 3], 4]], + [[1, 2, 3, "foo"], [[1, 2, 3], "foo"]], + [["foo", "bar", "baz", "foo"], [["foo", "bar", "baz",], "foo"]], + [["foo"], [null, "foo"]], + [null, [false, "foo"]], + [null, [1, "foo"]], + [["foo"], [[], "foo"]], + [null, ["foo", "foo"]], + [null, [{}, "foo"]], + [[""], [[], ""]], + [[false, false], [[false], false]], + [[false, null], [[false], null]], + [[0], [[], 0, true]], + [[true, 1], [[true], 1, true]], + [[true], [[true], true, true]], + [[true, true], [[true], true, false]], + [["foo", "bar", "foo"], [["foo", "bar", "foo"], "foo", true]], + [["foo", []], [["foo"], [], true]], + [["foo", []], [["foo", []], [], true]], + [["foo", [], []], [["foo", []], [], false]], + [[{a: 1}, {a: 2}, {b: 1}], [[{a: 1}, {a: 2}, {b: 1}], {a: 1}, true]], + [[{a: 1}, {a: 2}, {b: 1}, {a: 1}], [[{a: 1}, {a: 2}, {b: 1}], {a: 1}, false]], + [[{a: 1}, {a: 2}, {b: 1}, {b: 2}], [[{a: 1}, {a: 2}, {b: 1}], {b: 2}, true]] ]; data.forEach(function (d) { - var actual = getQueryResults("RETURN PUSH(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")"); + var actual = getQueryResults("RETURN PUSH(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + ")"); assertEqual(d[0], actual[0], d); - actual = getQueryResults("RETURN NOOPT(PUSH(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + "))"); + actual = getQueryResults("RETURN NOOPT(PUSH(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + "))"); assertEqual(d[0], actual[0], d); }); }, @@ -101,7 +105,7 @@ function ahuacatlListTestSuite () { /// @brief test push function //////////////////////////////////////////////////////////////////////////////// - testPushBig : function () { + testPushBig: function () { var l = []; for (var i = 0; i < 2000; i += 2) { l.push(i); @@ -152,7 +156,7 @@ function ahuacatlListTestSuite () { /// @brief test push function //////////////////////////////////////////////////////////////////////////////// - testPushInvalid : function () { + testPushInvalid: function () { assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN PUSH()"); assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN PUSH([ ])"); assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN PUSH([ ], 1, 2, 3)"); @@ -166,41 +170,45 @@ function ahuacatlListTestSuite () { /// @brief test unshift function //////////////////////////////////////////////////////////////////////////////// - testUnshift : function () { + testUnshift: function () { var data = [ - [ [ 4, 1, 2, 3 ], [ [ 1, 2, 3 ], 4 ] ], - [ [ "foo", 1, 2, 3 ], [ [ 1, 2, 3 ], "foo" ] ], - [ [ "foo", "foo", "bar", "baz" ], [ [ "foo", "bar", "baz", ], "foo" ] ], - [ [ "foo" ], [ null, "foo" ] ], - [ null, [ false, "foo" ] ], - [ null, [ 1, "foo" ] ], - [ [ "foo" ], [ [ ], "foo" ] ], - [ null, [ "foo", "foo" ] ], - [ null, [ { }, "foo" ] ], - [ [ "" ], [ [ ], "" ] ], - [ [ false, false ], [ [ false ], false ] ], - [ [ null, false ], [ [ false ], null ] ], - [ [ 0 ], [ [ ], 0, true ] ], - [ [ 1, true ], [ [ true ], 1, true ] ], - [ [ true ], [ [ true ], true, true ] ], - [ [ true, true ], [ [ true ], true, false ] ], - [ [ "foo", "bar", "foo" ], [ [ "foo", "bar", "foo" ], "foo", true ] ], - [ [ "baz", "foo", "bar", "foo" ], [ [ "foo", "bar", "foo" ], "baz", true ] ], - [ [ [ ], "foo" ], [ [ "foo" ], [ ], true ] ], - [ [ "foo", [ ] ], [ [ "foo", [ ] ], [ ], true ] ], - [ [ [ ], "foo" ], [ [ [ ], "foo" ], [ ], true ] ], - [ [ [ ], "foo", [ ] ], [ [ "foo", [ ] ], [ ], false ] ], - [ [ [ ], [ ], "foo" ], [ [ [ ], "foo" ], [ ], false ] ], - [ [ { a: 1 }, { a: 2 }, { b: 1 } ], [ [ { a: 1 }, { a: 2 }, { b: 1 } ], { a: 1 }, true ] ], - [ [ { a: 1 }, { a: 1 }, { a: 2 }, { b: 1 } ], [ [ { a: 1 }, { a: 2 }, { b: 1 } ], { a: 1 }, false ] ], - [ [ { b: 2 }, { a: 1 }, { a: 2 }, { b: 1 } ], [ [ { a: 1 }, { a: 2 }, { b: 1 } ], { b: 2 }, true ] ] + [[4, 1, 2, 3], [[1, 2, 3], 4]], + [["foo", 1, 2, 3], [[1, 2, 3], "foo"]], + [["foo", "foo", "bar", "baz"], [["foo", "bar", "baz",], "foo"]], + [["foo"], [null, "foo"]], + [null, [false, "foo"]], + [null, [1, "foo"]], + [["foo"], [[], "foo"]], + [null, ["foo", "foo"]], + [null, [{}, "foo"]], + [[""], [[], ""]], + [[false, false], [[false], false]], + [[null, false], [[false], null]], + [[0], [[], 0, true]], + [[1, true], [[true], 1, true]], + [[true], [[true], true, true]], + [[true, true], [[true], true, false]], + [["foo", "bar", "foo"], [["foo", "bar", "foo"], "foo", true]], + [["baz", "foo", "bar", "foo"], [["foo", "bar", "foo"], "baz", true]], + [[[], "foo"], [["foo"], [], true]], + [["foo", []], [["foo", []], [], true]], + [[[], "foo"], [[[], "foo"], [], true]], + [[[], "foo", []], [["foo", []], [], false]], + [[[], [], "foo"], [[[], "foo"], [], false]], + [[{a: 1}, {a: 2}, {b: 1}], [[{a: 1}, {a: 2}, {b: 1}], {a: 1}, true]], + [[{a: 1}, {a: 1}, {a: 2}, {b: 1}], [[{a: 1}, {a: 2}, {b: 1}], {a: 1}, false]], + [[{b: 2}, {a: 1}, {a: 2}, {b: 1}], [[{a: 1}, {a: 2}, {b: 1}], {b: 2}, true]] ]; data.forEach(function (d) { - var actual = getQueryResults("RETURN UNSHIFT(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")"); + var actual = getQueryResults("RETURN UNSHIFT(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + ")"); assertEqual(d[0], actual[0], d); - actual = getQueryResults("RETURN NOOPT(UNSHIFT(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + "))"); + actual = getQueryResults("RETURN NOOPT(UNSHIFT(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + "))"); assertEqual(d[0], actual[0], d); }); }, @@ -209,7 +217,7 @@ function ahuacatlListTestSuite () { /// @brief test unshift function //////////////////////////////////////////////////////////////////////////////// - testUnshiftBig : function () { + testUnshiftBig: function () { var l = []; for (var i = 0; i < 2000; i += 2) { l.push(i); @@ -260,56 +268,56 @@ function ahuacatlListTestSuite () { /// @brief test unshift function //////////////////////////////////////////////////////////////////////////////// - testUnshiftInvalid : function () { - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN UNSHIFT()"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN UNSHIFT([ ])"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN UNSHIFT([ ], 1, 2, 3)"); + testUnshiftInvalid: function () { + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN UNSHIFT()"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN UNSHIFT([ ])"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN UNSHIFT([ ], 1, 2, 3)"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(UNSHIFT())"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(UNSHIFT([ ]))"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(UNSHIFT([ ], 1, 2, 3))"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(UNSHIFT())"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(UNSHIFT([ ]))"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(UNSHIFT([ ], 1, 2, 3))"); }, //////////////////////////////////////////////////////////////////////////////// /// @brief test pop function //////////////////////////////////////////////////////////////////////////////// - testPop : function () { + testPop: function () { var data = [ - [ null, null ], - [ null, false ], - [ null, true ], - [ null, 23 ], - [ null, "foo" ], - [ null, { } ], - [ [ ], [ ] ], - [ [ 1, 2 ], [ 1, 2, 3 ] ], - [ [ 1, 2, 3, "foo" ], [ 1, 2, 3, "foo", 4 ] ], - [ [ 1, 2, 3 ], [ 1, 2, 3, "foo" ] ], - [ [ "foo", "bar", "baz" ], [ "foo", "bar", "baz", "foo" ] ], - [ [ null ], [ null, "foo" ] ], - [ [ false ], [ false, "foo" ] ], - [ [ 1 ], [ 1, "foo" ] ], - [ [ [ ] ], [ [ ], "foo" ] ], - [ [ "foo" ], [ "foo", "foo" ] ], - [ [ "foo" ], [ "foo", "bar" ] ], - [ [ { } ], [ { }, "foo" ] ], - [ [ [ ] ], [ [ ], "" ] ], - [ [ [ false ] ], [ [ false ], false ] ], - [ [ [ false ] ], [ [ false ], null ] ], - [ [ [ ], 0 ], [ [ ], 0, true ] ], - [ [ true, 1 ], [ true, 1, true ] ], - [ [ true, true ], [ true, true, true ] ], - [ [ true, false ], [ true, false, true ] ], - [ [ true, false ], [ true, false, false ] ], - [ [ [ true ], true ], [ [ true ], true, false ] ], - [ [ [ "foo", "bar", "foo" ], "foo" ], [ [ "foo", "bar", "foo" ], "foo", true ] ], - [ [ "foo", [ ] ], [ "foo", [ ], true ] ], - [ [ "foo", [ ], [ ] ], [ "foo", [ ], [ ], true ] ], - [ [ "foo", [ ], [ ] ], [ "foo", [ ], [ ], false ] ], - [ [ { a: 1 }, { a: 2 } ], [ { a: 1 }, { a: 2 }, { b: 1 } ] ], - [ [ { a: 1 }, { a: 2 }, { b: 1 } ], [ { a: 1 }, { a: 2 }, { b: 1 }, { a: 1 } ] ], - [ [ { a: 1 }, { a: 2 }, { b: 1 } ], [ { a: 1 }, { a: 2 }, { b: 1 }, { b: 2 } ] ] + [null, null], + [null, false], + [null, true], + [null, 23], + [null, "foo"], + [null, {}], + [[], []], + [[1, 2], [1, 2, 3]], + [[1, 2, 3, "foo"], [1, 2, 3, "foo", 4]], + [[1, 2, 3], [1, 2, 3, "foo"]], + [["foo", "bar", "baz"], ["foo", "bar", "baz", "foo"]], + [[null], [null, "foo"]], + [[false], [false, "foo"]], + [[1], [1, "foo"]], + [[[]], [[], "foo"]], + [["foo"], ["foo", "foo"]], + [["foo"], ["foo", "bar"]], + [[{}], [{}, "foo"]], + [[[]], [[], ""]], + [[[false]], [[false], false]], + [[[false]], [[false], null]], + [[[], 0], [[], 0, true]], + [[true, 1], [true, 1, true]], + [[true, true], [true, true, true]], + [[true, false], [true, false, true]], + [[true, false], [true, false, false]], + [[[true], true], [[true], true, false]], + [[["foo", "bar", "foo"], "foo"], [["foo", "bar", "foo"], "foo", true]], + [["foo", []], ["foo", [], true]], + [["foo", [], []], ["foo", [], [], true]], + [["foo", [], []], ["foo", [], [], false]], + [[{a: 1}, {a: 2}], [{a: 1}, {a: 2}, {b: 1}]], + [[{a: 1}, {a: 2}, {b: 1}], [{a: 1}, {a: 2}, {b: 1}, {a: 1}]], + [[{a: 1}, {a: 2}, {b: 1}], [{a: 1}, {a: 2}, {b: 1}, {b: 2}]] ]; data.forEach(function (d) { @@ -325,7 +333,7 @@ function ahuacatlListTestSuite () { /// @brief test pop function //////////////////////////////////////////////////////////////////////////////// - testPopBig : function () { + testPopBig: function () { var l = []; for (var i = 0; i < 2000; i += 2) { l.push(i); @@ -355,7 +363,7 @@ function ahuacatlListTestSuite () { /// @brief test pop function //////////////////////////////////////////////////////////////////////////////// - testPopInvalid : function () { + testPopInvalid: function () { assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN POP()"); assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN POP([ ], 1)"); assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN POP([ ], 1, 2)"); @@ -369,44 +377,44 @@ function ahuacatlListTestSuite () { /// @brief test shift function //////////////////////////////////////////////////////////////////////////////// - testShift : function () { + testShift: function () { var data = [ - [ null, null ], - [ null, false ], - [ null, true ], - [ null, 23 ], - [ null, "foo" ], - [ null, { } ], - [ [ ], [ ] ], - [ [ 2, 3 ], [ 1, 2, 3 ] ], - [ [ 2, 3, "foo", 4 ], [ 1, 2, 3, "foo", 4 ] ], - [ [ 2, 3, "foo" ], [ 1, 2, 3, "foo" ] ], - [ [ "bar", "baz", "foo" ], [ "foo", "bar", "baz", "foo" ] ], - [ [ "foo" ], [ null, "foo" ] ], - [ [ "foo" ], [ false, "foo" ] ], - [ [ "foo" ], [ 1, "foo" ] ], - [ [ "foo" ], [ [ ], "foo" ] ], - [ [ "foo" ], [ "foo", "foo" ] ], - [ [ "bar" ], [ "foo", "bar" ] ], - [ [ "foo" ], [ { }, "foo" ] ], - [ [ { } ], [ "foo", { } ] ], - [ [ "" ], [ [ ], "" ] ], - [ [ [ ] ], [ "", [ ] ] ], - [ [ false ], [ [ false ], false ] ], - [ [ null ], [ [ false ], null ] ], - [ [ 0, true ], [ [ ], 0, true ] ], - [ [ 1, true ], [ true, 1, true ] ], - [ [ true, true ], [ true, true, true ] ], - [ [ false, true ], [ true, false, true ] ], - [ [ false, false ], [ true, false, false ] ], - [ [ true, false ], [ [ true ], true, false ] ], - [ [ "foo", true ], [ [ "foo", "bar", "foo" ], "foo", true ] ], - [ [ [ ], true ], [ "foo", [ ], true ] ], - [ [ [ ], [ ], true ], [ "foo", [ ], [ ], true ] ], - [ [ [ ], [ ], false ], [ "foo", [ ], [ ], false ] ], - [ [ { a: 2 }, { b: 1 } ], [ { a: 1 }, { a: 2 }, { b: 1 } ] ], - [ [ { a: 2 }, { b: 1 }, { a: 1 } ], [ { a: 1 }, { a: 2 }, { b: 1 }, { a: 1 } ] ], - [ [ { a: 2 }, { b: 1 }, { b: 2 } ], [ { a: 1 }, { a: 2 }, { b: 1 }, { b: 2 } ] ] + [null, null], + [null, false], + [null, true], + [null, 23], + [null, "foo"], + [null, {}], + [[], []], + [[2, 3], [1, 2, 3]], + [[2, 3, "foo", 4], [1, 2, 3, "foo", 4]], + [[2, 3, "foo"], [1, 2, 3, "foo"]], + [["bar", "baz", "foo"], ["foo", "bar", "baz", "foo"]], + [["foo"], [null, "foo"]], + [["foo"], [false, "foo"]], + [["foo"], [1, "foo"]], + [["foo"], [[], "foo"]], + [["foo"], ["foo", "foo"]], + [["bar"], ["foo", "bar"]], + [["foo"], [{}, "foo"]], + [[{}], ["foo", {}]], + [[""], [[], ""]], + [[[]], ["", []]], + [[false], [[false], false]], + [[null], [[false], null]], + [[0, true], [[], 0, true]], + [[1, true], [true, 1, true]], + [[true, true], [true, true, true]], + [[false, true], [true, false, true]], + [[false, false], [true, false, false]], + [[true, false], [[true], true, false]], + [["foo", true], [["foo", "bar", "foo"], "foo", true]], + [[[], true], ["foo", [], true]], + [[[], [], true], ["foo", [], [], true]], + [[[], [], false], ["foo", [], [], false]], + [[{a: 2}, {b: 1}], [{a: 1}, {a: 2}, {b: 1}]], + [[{a: 2}, {b: 1}, {a: 1}], [{a: 1}, {a: 2}, {b: 1}, {a: 1}]], + [[{a: 2}, {b: 1}, {b: 2}], [{a: 1}, {a: 2}, {b: 1}, {b: 2}]] ]; data.forEach(function (d) { @@ -422,7 +430,7 @@ function ahuacatlListTestSuite () { /// @brief test shift function //////////////////////////////////////////////////////////////////////////////// - testShiftBig : function () { + testShiftBig: function () { var l = []; for (var i = 0; i < 2000; i += 2) { l.push(i); @@ -455,21 +463,21 @@ function ahuacatlListTestSuite () { /// @brief test shift function //////////////////////////////////////////////////////////////////////////////// - testShiftInvalid : function () { - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN SHIFT()"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN SHIFT([ ], 1)"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN SHIFT([ ], 1, 2)"); + testShiftInvalid: function () { + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN SHIFT()"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN SHIFT([ ], 1)"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN SHIFT([ ], 1, 2)"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(SHIFT())"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(SHIFT([ ], 1))"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(SHIFT([ ], 1, 2))"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(SHIFT())"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(SHIFT([ ], 1))"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(SHIFT([ ], 1, 2))"); }, //////////////////////////////////////////////////////////////////////////////// /// @brief test push/pop function //////////////////////////////////////////////////////////////////////////////// - testPushPop : function () { + testPushPop: function () { var l = [], i, actual; for (i = 0; i < 1000; ++i) { actual = getQueryResults("RETURN PUSH(" + JSON.stringify(l) + ", " + JSON.stringify(i) + ")"); @@ -504,7 +512,7 @@ function ahuacatlListTestSuite () { /// @brief test unshift/shift function //////////////////////////////////////////////////////////////////////////////// - testUnshiftShift : function () { + testUnshiftShift: function () { var l = [], i, actual; for (i = 0; i < 1000; ++i) { actual = getQueryResults("RETURN UNSHIFT(" + JSON.stringify(l) + ", " + JSON.stringify(i) + ")"); @@ -523,30 +531,34 @@ function ahuacatlListTestSuite () { /// @brief test append function //////////////////////////////////////////////////////////////////////////////// - testAppend : function () { + testAppend: function () { var data = [ - [ [ ], [ [ ], [ ] ] ], - [ [ "foo", "bar", "baz" ], [ [ "foo" ], [ "bar", "baz" ] ] ], - [ [ "foo", "foo", "bar", "baz" ], [ [ "foo" ], [ "foo", "bar", "baz" ] ] ], - [ [ "foo", "bar", "baz" ], [ [ "foo" ], [ "foo", "bar", "baz" ], true ] ], - [ [ "foo", "bar", "baz" ], [ [ "foo" ], [ "foo", "bar", "baz", "foo" ], true ] ], - [ [ "foo", "bar", "baz" ], [ [ "foo", "bar" ], [ "baz" ] ] ], - [ [ "foo", "bar", "baz" ], [ null, [ "foo", "bar", "baz" ] ] ], - [ [ "foo", "bar", "baz" ], [ [ "foo", "bar", "baz" ], null ] ], - [ [ "foo", "bar", "baz" ], [ [ ], [ "foo", "bar", "baz" ] ] ], - [ [ "foo", "bar", "baz" ], [ [ "foo", "bar", "baz" ], [ ] ] ], - [ [ "foo", "bar", "baz", "one", "two", "three" ], [ [ "foo", "bar", "baz" ], [ "one", "two", "three" ] ] ], - [ [ "foo", "bar", "baz", "one", "two", null, "three" ], [ [ "foo", "bar", "baz" ], [ "one", "two", null, "three" ] ] ], - [ [ "two", "one", null, "three", "one", "two", null, "three" ], [ [ "two", "one", null, "three" ], [ "one", "two", null, "three" ] ] ], - [ [ "two", "one", null, "three" ], [ [ "two", "one", null, "three" ], [ "one", "two", null, "three" ], true ] ], - [ [ "two", "one", null, "three", "four" ], [ [ "two", "one", null, "three" ], [ "one", "two", "four", null, "three" ], true ] ] + [[], [[], []]], + [["foo", "bar", "baz"], [["foo"], ["bar", "baz"]]], + [["foo", "foo", "bar", "baz"], [["foo"], ["foo", "bar", "baz"]]], + [["foo", "bar", "baz"], [["foo"], ["foo", "bar", "baz"], true]], + [["foo", "bar", "baz"], [["foo"], ["foo", "bar", "baz", "foo"], true]], + [["foo", "bar", "baz"], [["foo", "bar"], ["baz"]]], + [["foo", "bar", "baz"], [null, ["foo", "bar", "baz"]]], + [["foo", "bar", "baz"], [["foo", "bar", "baz"], null]], + [["foo", "bar", "baz"], [[], ["foo", "bar", "baz"]]], + [["foo", "bar", "baz"], [["foo", "bar", "baz"], []]], + [["foo", "bar", "baz", "one", "two", "three"], [["foo", "bar", "baz"], ["one", "two", "three"]]], + [["foo", "bar", "baz", "one", "two", null, "three"], [["foo", "bar", "baz"], ["one", "two", null, "three"]]], + [["two", "one", null, "three", "one", "two", null, "three"], [["two", "one", null, "three"], ["one", "two", null, "three"]]], + [["two", "one", null, "three"], [["two", "one", null, "three"], ["one", "two", null, "three"], true]], + [["two", "one", null, "three", "four"], [["two", "one", null, "three"], ["one", "two", "four", null, "three"], true]] ]; data.forEach(function (d) { - var actual = getQueryResults("RETURN APPEND(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")"); + var actual = getQueryResults("RETURN APPEND(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + ")"); assertEqual(d[0], actual[0], d); - actual = getQueryResults("RETURN NOOPT(APPEND(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + "))"); + actual = getQueryResults("RETURN NOOPT(APPEND(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + "))"); assertEqual(d[0], actual[0], d); }); }, @@ -555,8 +567,8 @@ function ahuacatlListTestSuite () { /// @brief test append function //////////////////////////////////////////////////////////////////////////////// - testAppendBig : function () { - var l1 = [], l2 = [ ]; + testAppendBig: function () { + var l1 = [], l2 = []; for (var i = 0; i < 2000; i += 4) { l1.push(i); l2.push(i + 1); @@ -570,7 +582,7 @@ function ahuacatlListTestSuite () { var lx = l.concat(l1); assertEqual(1500, actual[0].length); assertEqual(lx, actual[0]); - + actual = getQueryResults("RETURN NOOPT(APPEND(" + JSON.stringify(l) + ", " + JSON.stringify(l1) + "))"); assertEqual(1500, actual[0].length); assertEqual(lx, actual[0]); @@ -578,7 +590,7 @@ function ahuacatlListTestSuite () { actual = getQueryResults("RETURN APPEND(" + JSON.stringify(l) + ", " + JSON.stringify(l1) + ", true)"); assertEqual(1000, actual[0].length); assertEqual(l1.concat(l2), actual[0]); - + actual = getQueryResults("RETURN NOOPT(APPEND(" + JSON.stringify(l) + ", " + JSON.stringify(l1) + ", true))"); assertEqual(1000, actual[0].length); assertEqual(l1.concat(l2), actual[0]); @@ -598,13 +610,20 @@ function ahuacatlListTestSuite () { assertEqual(l, actual[0]); }, - testAppendDocuments : function () { - var bindVars = {"@collection" : collectionName}; + testAppendDocuments: function () { + var bindVars = {"@collection": collectionName}; var actual = getQueryResults("LET tmp = (FOR x IN @@collection RETURN x) RETURN APPEND([], tmp)", bindVars); assertEqual(actual.length, 1); actual = actual[0]; assertEqual(actual.length, 10); - actual = actual.sort(function(l, r) { if (l._key < r._key) { return -1;} else if (l._key > r._key) { return 1;} return 0; }); + actual = actual.sort(function (l, r) { + if (l._key < r._key) { + return -1; + } else if (l._key > r._key) { + return 1; + } + return 0; + }); var i; for (i = 0; i < 10; ++i) { assertEqual(actual[i]._key, "test" + i); @@ -614,17 +633,24 @@ function ahuacatlListTestSuite () { assertEqual(actual.length, 1); actual = actual[0]; assertEqual(actual.length, 10); - actual = actual.sort(function(l, r) { if (l._key < r._key) { return -1;} else if (l._key > r._key) { return 1;} return 0; }); + actual = actual.sort(function (l, r) { + if (l._key < r._key) { + return -1; + } else if (l._key > r._key) { + return 1; + } + return 0; + }); for (i = 0; i < 10; ++i) { assertEqual(actual[i]._key, "test" + i); } - + actual = getQueryResults("LET doc = DOCUMENT('nonexistantCollection/nonexistantDocument') RETURN append(doc.t,[1,2,2], true)"); - assertEqual(actual[0], [1,2,2]); + assertEqual(actual[0], [1, 2, 2]); }, - testAppendDocuments2 : function () { - var bindVars = {"@collection" : collectionName}; + testAppendDocuments2: function () { + var bindVars = {"@collection": collectionName}; var actual = getQueryResults("LET tmp = (FOR x IN @@collection SORT x._key RETURN x) RETURN APPEND(tmp, 'stringvalue')", bindVars); assertEqual(actual.length, 1); actual = actual[0]; @@ -634,36 +660,43 @@ function ahuacatlListTestSuite () { for (i = 0; i < 10; ++i) { assertEqual(actual[i]._key, "test" + i); } - + actual = getQueryResults("LET tmp = (FOR x IN @@collection RETURN x) RETURN APPEND('stringvalue', tmp)", bindVars); assertEqual(actual.length, 1); assertNull(actual[0]); }, - testAppendDocuments3 : function () { - var bindVars = {"@collection" : collectionName}; + testAppendDocuments3: function () { + var bindVars = {"@collection": collectionName}; var actual = getQueryResults("LET tmp = (FOR x IN @@collection RETURN x._id) RETURN APPEND(tmp, 'stringvalue')", bindVars); assertEqual(actual.length, 1); actual = actual[0]; assertEqual(actual.length, 11); - actual = actual.sort(function(l, r) { if (l < r) { return -1;} else if (l > r) { return 1;} return 0; }); + actual = actual.sort(function (l, r) { + if (l < r) { + return -1; + } else if (l > r) { + return 1; + } + return 0; + }); assertEqual('stringvalue', actual[10]); var i; for (i = 0; i < 10; ++i) { assertEqual(actual[i], collectionName + "/test" + i); } - + actual = getQueryResults("LET tmp = (FOR x IN @@collection RETURN x._id) RETURN APPEND('stringvalue', tmp)", bindVars); assertEqual(actual.length, 1); assertNull(actual[0]); }, - testAppendSecondUnique : function () { + testAppendSecondUnique: function () { var actual = getQueryResults("RETURN APPEND('stringvalue', [1,1,1,1,1,1], true)"); assertEqual(actual.length, 1); actual = actual[0]; assertNull(actual); - + actual = getQueryResults("RETURN APPEND([1,1,1,1,1,1], 'stringvalue', true)"); assertEqual(actual.length, 1); assertEqual([1, 'stringvalue'], actual[0]); @@ -673,53 +706,57 @@ function ahuacatlListTestSuite () { /// @brief test append function //////////////////////////////////////////////////////////////////////////////// - testAppendInvalid : function () { - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN APPEND()"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN APPEND([ ])"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN APPEND([ ], [ ], false, [ ])"); + testAppendInvalid: function () { + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN APPEND()"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN APPEND([ ])"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN APPEND([ ], [ ], false, [ ])"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(APPEND())"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(APPEND([ ]))"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(APPEND([ ], [ ], false, [ ]))"); - - assertEqual([ null ], getQueryResults("RETURN APPEND('foo', [1])")); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(APPEND())"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(APPEND([ ]))"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(APPEND([ ], [ ], false, [ ]))"); + + assertEqual([null], getQueryResults("RETURN APPEND('foo', [1])")); }, //////////////////////////////////////////////////////////////////////////////// /// @brief test removeValues function //////////////////////////////////////////////////////////////////////////////// - testRemoveValues : function () { + testRemoveValues: function () { var data = [ - [ [ ], [ [ ], [ ] ] ], - [ [ ], [ [ ], [ "1", "2" ] ] ], - [ [ "1", "2" ], [ [ "1", "2" ], [ ] ] ], - [ [ "1", "2" ], [ [ "1", "2" ], [ 1, 2 ] ] ], - [ [ 1, 2 ], [ [ 1, 2 ], [ "1", "2" ] ] ], - [ [ 2 ], [ [ 1, 2 ], [ "1", "2", 1 ] ] ], - [ [ "1", "2" ], [ [ "1", "2" ], [ "foo", 1] ] ], - [ [ "foo" ], [ [ "foo" ], [ "bar", "baz" ] ] ], - [ [ ], [ [ "foo" ], [ "foo", "bar", "baz" ] ] ], - [ [ ], [ [ "foo" ], [ "foo", "bar", "baz" ] ] ], - [ [ ], [ [ "foo" ], [ "foo", "bar", "baz", "foo" ] ] ], - [ [ "foo", "bar" ], [ [ "foo", "bar" ], [ "baz" ] ] ], - [ [ ], [ null, [ "foo", "bar", "baz" ] ] ], - [ [ "foo", "bar", "baz" ], [ [ "foo", "bar", "baz" ], null ] ], - [ [ ], [ [ ], [ "foo", "bar", "baz" ] ] ], - [ [ "foo", "bar", "baz" ], [ [ "foo", "bar", "baz" ], [ ] ] ], - [ [ "foo", "bar", "baz" ], [ [ "foo", "bar", "baz" ], [ "one", "two", "three" ] ] ], - [ [ "foo", "bar", "baz" ], [ [ "foo", null, "bar", "baz" ], [ "one", "two", null, "three" ] ] ], - [ [ ], [ [ "two", "one", null, "three" ], [ "one", "two", null, "three" ] ] ], - [ [ null ], [ [ "two", "one", null, "three" ], [ "one", "two", "three" ] ] ], - [ [ "four", "five" ], [ [ "two", "four", "one", null, "three", "five" ], [ "one", "two", null, "three" ] ] ], - [ [ ], [ [ "two", "one", null, "three" ], [ "one", "two", "four", null, "three" ] ] ] + [[], [[], []]], + [[], [[], ["1", "2"]]], + [["1", "2"], [["1", "2"], []]], + [["1", "2"], [["1", "2"], [1, 2]]], + [[1, 2], [[1, 2], ["1", "2"]]], + [[2], [[1, 2], ["1", "2", 1]]], + [["1", "2"], [["1", "2"], ["foo", 1]]], + [["foo"], [["foo"], ["bar", "baz"]]], + [[], [["foo"], ["foo", "bar", "baz"]]], + [[], [["foo"], ["foo", "bar", "baz"]]], + [[], [["foo"], ["foo", "bar", "baz", "foo"]]], + [["foo", "bar"], [["foo", "bar"], ["baz"]]], + [[], [null, ["foo", "bar", "baz"]]], + [["foo", "bar", "baz"], [["foo", "bar", "baz"], null]], + [[], [[], ["foo", "bar", "baz"]]], + [["foo", "bar", "baz"], [["foo", "bar", "baz"], []]], + [["foo", "bar", "baz"], [["foo", "bar", "baz"], ["one", "two", "three"]]], + [["foo", "bar", "baz"], [["foo", null, "bar", "baz"], ["one", "two", null, "three"]]], + [[], [["two", "one", null, "three"], ["one", "two", null, "three"]]], + [[null], [["two", "one", null, "three"], ["one", "two", "three"]]], + [["four", "five"], [["two", "four", "one", null, "three", "five"], ["one", "two", null, "three"]]], + [[], [["two", "one", null, "three"], ["one", "two", "four", null, "three"]]] ]; data.forEach(function (d) { - var actual = getQueryResults("RETURN REMOVE_VALUES(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")"); + var actual = getQueryResults("RETURN REMOVE_VALUES(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + ")"); assertEqual(d[0], actual[0], d); - actual = getQueryResults("RETURN NOOPT(REMOVE_VALUES(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + "))"); + actual = getQueryResults("RETURN NOOPT(REMOVE_VALUES(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + "))"); assertEqual(d[0], actual[0], d); }); }, @@ -728,56 +765,60 @@ function ahuacatlListTestSuite () { /// @brief test removeValues function //////////////////////////////////////////////////////////////////////////////// - testRemoveValuesInvalid : function () { - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUES()"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUES([ ])"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUES([ ], [ ], true)"); + testRemoveValuesInvalid: function () { + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUES()"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUES([ ])"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUES([ ], [ ], true)"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUES())"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUES([ ]))"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUES([ ], [ ], true))"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUES())"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUES([ ]))"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUES([ ], [ ], true))"); }, //////////////////////////////////////////////////////////////////////////////// /// @brief test removeValue function //////////////////////////////////////////////////////////////////////////////// - testRemoveValue : function () { + testRemoveValue: function () { var data = [ - [ [ ], [ [ ], null ] ], - [ [ ], [ [ ], false ] ], - [ [ ], [ [ ], 1 ] ], - [ [ ], [ [ ], "1" ] ], - [ [ ], [ [ ], [ ] ] ], - [ [ ], [ [ ], [ "1", "2" ] ] ], - [ [ "1", "2" ], [ [ "1", "2" ], [ ] ] ], - [ [ "1", "2" ], [ [ "1", "2" ], 1 ] ], - [ [ "1", "2" ], [ [ "1", "2" ], 2 ] ], - [ [ "2" ], [ [ "1", "2" ], "1" ] ], - [ [ "1" ], [ [ "1", "2" ], "2" ] ], - [ [ "1", "1", "1", "3" ], [ [ "1", "1", "1", "2", "2", "3" ], "2" ] ], - [ [ "1", "1", "1", "2", "3" ], [ [ "1", "1", "1", "2", "2", "3" ], "2", 1 ] ], - [ [ ], [ [ "foo" ], "foo" ] ], - [ [ "bar" ], [ [ "bar" ], "foo" ] ], - [ [ "foo" ], [ [ "foo" ], "bar" ] ], - [ [ ], [ [ "foo", "foo", "foo" ], "foo" ] ], - [ [ "foo", "foo" ], [ [ "foo", "foo", "foo" ], "foo", 1 ] ], - [ [ "foo" ], [ [ "foo", "foo", "foo" ], "foo", 2 ] ], - [ [ ], [ [ "foo", "foo", "foo" ], "foo", 3 ] ], - [ [ ], [ [ "foo", "foo", "foo" ], "foo", 496 ] ], - [ [ "bar", "foo", "bam", "foo", "baz" ], [ [ "bar", "foo", "foo", "bam", "foo", "baz" ], "foo", 1 ] ], - [ [ "bar", "bam", "baz", "foo" ], [ [ "bar", "bam", "baz", "foo", "foo" ], "foo", 1 ] ], - [ [ "bar", "bam", "baz" ], [ [ "bar", "bam", "baz", "foo", "foo" ], "foo", 2 ] ], - [ [ [ 1, 2, 3 ] ], [ [ [ 1, 2, 3 ] ], [ 1, 2 ] ] ], - [ [ [ 1, 2, 3 ] ], [ [ [ 1, 2, 3 ] ], [ 1, 3, 2 ] ] ], - [ [ ], [ [ [ 1, 2, 3 ] ], [ 1, 2, 3] ] ] + [[], [[], null]], + [[], [[], false]], + [[], [[], 1]], + [[], [[], "1"]], + [[], [[], []]], + [[], [[], ["1", "2"]]], + [["1", "2"], [["1", "2"], []]], + [["1", "2"], [["1", "2"], 1]], + [["1", "2"], [["1", "2"], 2]], + [["2"], [["1", "2"], "1"]], + [["1"], [["1", "2"], "2"]], + [["1", "1", "1", "3"], [["1", "1", "1", "2", "2", "3"], "2"]], + [["1", "1", "1", "2", "3"], [["1", "1", "1", "2", "2", "3"], "2", 1]], + [[], [["foo"], "foo"]], + [["bar"], [["bar"], "foo"]], + [["foo"], [["foo"], "bar"]], + [[], [["foo", "foo", "foo"], "foo"]], + [["foo", "foo"], [["foo", "foo", "foo"], "foo", 1]], + [["foo"], [["foo", "foo", "foo"], "foo", 2]], + [[], [["foo", "foo", "foo"], "foo", 3]], + [[], [["foo", "foo", "foo"], "foo", 496]], + [["bar", "foo", "bam", "foo", "baz"], [["bar", "foo", "foo", "bam", "foo", "baz"], "foo", 1]], + [["bar", "bam", "baz", "foo"], [["bar", "bam", "baz", "foo", "foo"], "foo", 1]], + [["bar", "bam", "baz"], [["bar", "bam", "baz", "foo", "foo"], "foo", 2]], + [[[1, 2, 3]], [[[1, 2, 3]], [1, 2]]], + [[[1, 2, 3]], [[[1, 2, 3]], [1, 3, 2]]], + [[], [[[1, 2, 3]], [1, 2, 3]]] ]; data.forEach(function (d) { - var actual = getQueryResults("RETURN REMOVE_VALUE(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")"); + var actual = getQueryResults("RETURN REMOVE_VALUE(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + ")"); assertEqual(d[0], actual[0], d); - actual = getQueryResults("RETURN NOOPT(REMOVE_VALUE(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + "))"); + actual = getQueryResults("RETURN NOOPT(REMOVE_VALUE(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + "))"); assertEqual(d[0], actual[0], d); }); }, @@ -786,58 +827,62 @@ function ahuacatlListTestSuite () { /// @brief test removeValue function //////////////////////////////////////////////////////////////////////////////// - testRemoveValueInvalid : function () { - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUE()"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUE([ ])"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUE([ ], [ ], true, true)"); + testRemoveValueInvalid: function () { + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUE()"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUE([ ])"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_VALUE([ ], [ ], true, true)"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUE())"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUE([ ]))"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUE([ ], [ ], true, true))"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUE())"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUE([ ]))"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_VALUE([ ], [ ], true, true))"); }, //////////////////////////////////////////////////////////////////////////////// /// @brief test removeNth function //////////////////////////////////////////////////////////////////////////////// - testRemoveNth : function () { + testRemoveNth: function () { var data = [ - [ [ ], [ [ ], 0 ] ], - [ [ ], [ [ ], -1 ] ], - [ [ ], [ [ ], -2 ] ], - [ [ ], [ [ ], 99 ] ], - [ [ ], [ [ ], null ] ], - [ [ "2" ], [ [ "1", "2" ], 0 ] ], - [ [ "1" ], [ [ "1", "2" ], 1 ] ], - [ [ "1", "2" ], [ [ "1", "2" ], 2 ] ], - [ [ "1", "2" ], [ [ "1", "2" ], -3 ] ], - [ [ "2" ], [ [ "1", "2" ], -2 ] ], - [ [ "1" ], [ [ "1", "2" ], -1 ] ], - [ [ "1b", "1c", "2a", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], 0 ] ], - [ [ "1a", "1c", "2a", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], 1 ] ], - [ [ "1a", "1b", "2a", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], 2 ] ], - [ [ "1a", "1b", "2a", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], 2.2 ] ], - [ [ "1a", "1b", "2a", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], 2.8 ] ], - [ [ "1a", "1b", "1c", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], 3 ] ], - [ [ "1a", "1b", "1c", "2a", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], 4 ] ], - [ [ "1a", "1b", "1c", "2a", "2b" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], 5 ] ], - [ [ "1a", "1b", "1c", "2a", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], 6 ] ], - [ [ "1a", "1b", "1c", "2a", "2b" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], -1 ] ], - [ [ "1a", "1b", "1c", "2a", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], -2 ] ], - [ [ "1a", "1b", "1c", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], -2.2 ] ], - [ [ "1a", "1b", "1c", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], -2.8 ] ], - [ [ "1a", "1b", "1c", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], -3 ] ], - [ [ "1a", "1b", "2a", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], -4 ] ], - [ [ "1a", "1c", "2a", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], -5 ] ], - [ [ "1b", "1c", "2a", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], -6 ] ], - [ [ "1a", "1b", "1c", "2a", "2b", "3" ], [ [ "1a", "1b", "1c", "2a", "2b", "3" ], -7 ] ] + [[], [[], 0]], + [[], [[], -1]], + [[], [[], -2]], + [[], [[], 99]], + [[], [[], null]], + [["2"], [["1", "2"], 0]], + [["1"], [["1", "2"], 1]], + [["1", "2"], [["1", "2"], 2]], + [["1", "2"], [["1", "2"], -3]], + [["2"], [["1", "2"], -2]], + [["1"], [["1", "2"], -1]], + [["1b", "1c", "2a", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], 0]], + [["1a", "1c", "2a", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], 1]], + [["1a", "1b", "2a", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], 2]], + [["1a", "1b", "2a", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], 2.2]], + [["1a", "1b", "2a", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], 2.8]], + [["1a", "1b", "1c", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], 3]], + [["1a", "1b", "1c", "2a", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], 4]], + [["1a", "1b", "1c", "2a", "2b"], [["1a", "1b", "1c", "2a", "2b", "3"], 5]], + [["1a", "1b", "1c", "2a", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], 6]], + [["1a", "1b", "1c", "2a", "2b"], [["1a", "1b", "1c", "2a", "2b", "3"], -1]], + [["1a", "1b", "1c", "2a", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], -2]], + [["1a", "1b", "1c", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], -2.2]], + [["1a", "1b", "1c", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], -2.8]], + [["1a", "1b", "1c", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], -3]], + [["1a", "1b", "2a", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], -4]], + [["1a", "1c", "2a", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], -5]], + [["1b", "1c", "2a", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], -6]], + [["1a", "1b", "1c", "2a", "2b", "3"], [["1a", "1b", "1c", "2a", "2b", "3"], -7]] ]; data.forEach(function (d) { - var actual = getQueryResults("RETURN REMOVE_NTH(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")"); + var actual = getQueryResults("RETURN REMOVE_NTH(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + ")"); assertEqual(d[0], actual[0], d); - actual = getQueryResults("RETURN NOOPT(REMOVE_NTH(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + "))"); + actual = getQueryResults("RETURN NOOPT(REMOVE_NTH(" + d[1].map(function (v) { + return JSON.stringify(v); + }).join(", ") + "))"); assertEqual(d[0], actual[0], d); }); }, @@ -846,26 +891,53 @@ function ahuacatlListTestSuite () { /// @brief test removeNth function //////////////////////////////////////////////////////////////////////////////// - testRemoveNthInvalid : function () { - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_NTH()"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_NTH([ ])"); - assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_NTH([ ], 1, true)"); + testRemoveNthInvalid: function () { + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_NTH()"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_NTH([ ])"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REMOVE_NTH([ ], 1, true)"); assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_NTH())"); assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_NTH([ ]))"); assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(REMOVE_NTH([ ], 1, true))"); - } + }, + + + testInterleave: function () { + const data = [ + {input: [[], []], expected: []}, + {input: [[1, 1], [2, 2]], expected: [1, 2, 1, 2]}, + {input: [[1, 3, 5], [2, 4, 6]], expected: [1, 2, 3, 4, 5, 6]}, + {input: [[1, 3, 5], [2]], expected: [1, 2, 3, 5]}, + {input: [[1, 1, 1], [2, 2], [3]], expected: [1, 2, 3, 1, 2, 1]}, + {input: [[1, 4, 7], [2, 5], [3]], expected: [1, 2, 3, 4, 5, 7]}, + {input: [[1], [1], [1], [1], [1], [1], [1]], expected: [1, 1, 1, 1, 1, 1, 1]}, + {input: [[1], [2, 2, 2], [3, 3]], expected: [1, 2, 3, 2, 3, 2]}, + {input: [[1, 1], [2], [3, 3, 3]], expected: [1, 2, 3, 1, 3, 3]}, + {input: [[1], [], [3]], expected: [1, 3]}, + + {input: [2, [], [2]], expected: null}, + {input: [[], {}, [2]], expected: null}, + {input: [[], [1], [2, 2], [3, 3, 3]], expected: [1, 2, 3, 2, 3, 3]}, + ]; + + data.forEach(function (d) { + const actual = getQueryResults("RETURN INTERLEAVE(" + d.input.map(function (v) { + return JSON.stringify(v); + }).join(", ") + ")"); + assertEqual(d.expected, actual[0], d); + }); + }, }; } -function ahuacatlDocumentAppendTestSuite () { +function ahuacatlDocumentAppendTestSuite() { var collectionName = "UnitTestList"; - var collection; + var collection; return { - setUpAll : function () { + setUpAll: function () { internal.db._drop(collectionName); collection = internal.db._create(collectionName); }, @@ -874,9 +946,9 @@ function ahuacatlDocumentAppendTestSuite () { internal.db._drop(collectionName); }, - testAppendWithDocuments : function () { + testAppendWithDocuments: function () { for (let i = 0; i < 2000; ++i) { - collection.insert({ _key: "test" + i, value: i }); + collection.insert({_key: "test" + i, value: i}); } let query = "LET results = APPEND((FOR doc IN " + collectionName + " FILTER doc.value < 1000 RETURN doc), (FOR doc IN " + collectionName + " FILTER doc.value >= 500 RETURN doc), true) FOR doc IN results SORT doc.updated LIMIT 2000 RETURN doc";