/*jshint globalstrict:false, strict:false, maxlen: 500 */ /*global assertEqual, AQL_EXPLAIN */ //////////////////////////////////////////////////////////////////////////////// /// @brief tests for query language, limit optimizations /// /// @file /// /// DISCLAIMER /// /// Copyright 2010-2012 triagens GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Jan Steemann /// @author Copyright 2012, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// var jsunity = require("jsunity"); var internal = require("internal"); var db = internal.db; var helper = require("@arangodb/aql-helper"); var getQueryResults = helper.getQueryResults; //////////////////////////////////////////////////////////////////////////////// /// @brief test suite //////////////////////////////////////////////////////////////////////////////// function ahuacatlQueryOptimizerLimitTestSuite () { var collection = null; var cn = "UnitTestsAhuacatlOptimizerLimit"; var explain = function (query) { return helper.getCompactPlan(AQL_EXPLAIN(query)).map(function(node) { return node.type; }); }; return { //////////////////////////////////////////////////////////////////////////////// /// @brief set up //////////////////////////////////////////////////////////////////////////////// setUp : function () { internal.db._drop(cn); collection = internal.db._create(cn); for (var i = 0; i < 100; ++i) { collection.save({ "value" : i }); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief tear down //////////////////////////////////////////////////////////////////////////////// tearDown : function () { internal.db._drop(cn); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization for non-collection access, limit > 0 //////////////////////////////////////////////////////////////////////////////// testLimitNonCollectionNoRestriction : function () { var i; var list = [ ]; for (i = 0; i < 100; ++i) { list.push(i); } var tests = [ { offset: 0, limit: 500, expectedLength: 100 }, { offset: 0, limit: 50, expectedLength: 50 }, { offset: 0, limit: 5, expectedLength: 5 }, { offset: 0, limit: 1, expectedLength: 1 }, { offset: 1, limit: 50, expectedLength: 50 }, { offset: 1, limit: 1, expectedLength: 1 }, { offset: 10, limit: 50, expectedLength: 50 }, { offset: 95, limit: 5, expectedLength: 5 }, { offset: 95, limit: 50, expectedLength: 5 }, { offset: 98, limit: 50, expectedLength: 2 }, { offset: 98, limit: 2, expectedLength: 2 }, { offset: 99, limit: 1, expectedLength: 1 }, { offset: 99, limit: 2, expectedLength: 1 }, { offset: 100, limit: 2, expectedLength: 0 } ]; for (i = 0; i < tests.length; ++i) { var test = tests[i]; var query = "FOR c IN " + JSON.stringify(list) + " LIMIT " + test.offset + ", " + test.limit + " RETURN c"; var actual = getQueryResults(query); assertEqual(test.expectedLength, actual.length); assertEqual([ "SingletonNode", "CalculationNode", "EnumerateListNode", "LimitNode", "ReturnNode" ], explain(query)); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization for full collection access, limit > 0 //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionNoRestriction : function () { var tests = [ { offset: 0, limit: 500, expectedLength: 100 }, { offset: 0, limit: 50, expectedLength: 50 }, { offset: 0, limit: 5, expectedLength: 5 }, { offset: 0, limit: 1, expectedLength: 1 }, { offset: 1, limit: 50, expectedLength: 50 }, { offset: 1, limit: 1, expectedLength: 1 }, { offset: 10, limit: 50, expectedLength: 50 }, { offset: 95, limit: 5, expectedLength: 5 }, { offset: 95, limit: 50, expectedLength: 5 }, { offset: 98, limit: 50, expectedLength: 2 }, { offset: 98, limit: 2, expectedLength: 2 }, { offset: 99, limit: 1, expectedLength: 1 }, { offset: 99, limit: 2, expectedLength: 1 }, { offset: 100, limit: 2, expectedLength: 0 } ]; for (var i = 0; i < tests.length; ++i) { var test = tests[i]; var query = "FOR c IN " + cn + " LIMIT " + test.offset + ", " + test.limit + " RETURN c"; var actual = getQueryResults(query); assertEqual(test.expectedLength, actual.length); assertEqual([ "SingletonNode", "EnumerateCollectionNode", "RemoteNode", "GatherNode", "LimitNode", "ReturnNode" ], explain(query)); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization for non collection access, limit 0 //////////////////////////////////////////////////////////////////////////////// testLimitNonCollectionNoRestrictionEmpty : function () { var i; var list = [ ]; for (i = 0; i < 100; ++i) { list.push(i); } var tests = [ { offset: 0, limit: 0 }, { offset: 1, limit: 0 }, { offset: 10, limit: 0 }, { offset: 95, limit: 0 }, { offset: 98, limit: 0 }, { offset: 99, limit: 0 }, { offset: 100, limit: 0 } ]; for (i = 0; i < tests.length; ++i) { var test = tests[i]; var query = "FOR c IN " + JSON.stringify(list) + " LIMIT " + test.offset + ", " + test.limit + " RETURN c"; var actual = getQueryResults(query); assertEqual(0, actual.length); assertEqual([ "SingletonNode", "CalculationNode", "EnumerateListNode", "LimitNode", "ReturnNode" ], explain(query)); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization for full collection access, limit 0 //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionNoRestrictionEmpty : function () { var tests = [ { offset: 0, limit: 0 }, { offset: 1, limit: 0 }, { offset: 10, limit: 0 }, { offset: 95, limit: 0 }, { offset: 98, limit: 0 }, { offset: 99, limit: 0 }, { offset: 100, limit: 0 } ]; for (var i = 0; i < tests.length; ++i) { var test = tests[i]; var query = "FOR c IN " + cn + " LIMIT " + test.offset + ", " + test.limit + " RETURN c"; var actual = getQueryResults(query); assertEqual(0, actual.length); assertEqual([ "SingletonNode", "EnumerateCollectionNode", "RemoteNode", "GatherNode", "LimitNode", "ReturnNode" ], explain(query)); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization for non-collection access, limit 0 //////////////////////////////////////////////////////////////////////////////// testLimitNonCollectionDoubleLimitEmpty : function () { var list = [ ]; for (var i = 0; i < 100; ++i) { list.push(i); } var query = "FOR c IN " + JSON.stringify(list) + " LIMIT 10 LIMIT 0 RETURN c"; var actual = getQueryResults(query); assertEqual(0, actual.length); assertEqual([ "SingletonNode", "CalculationNode", "EnumerateListNode", "LimitNode", "LimitNode", "ReturnNode" ], explain(query)); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization for full collection access, limit 0 //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionDoubleLimitEmpty : function () { var query = "FOR c IN " + cn + " LIMIT 10 LIMIT 0 RETURN c"; var actual = getQueryResults(query); assertEqual(0, actual.length); assertEqual([ "SingletonNode", "EnumerateCollectionNode", "RemoteNode", "GatherNode", "LimitNode", "LimitNode", "ReturnNode" ], explain(query)); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with 2 limits //////////////////////////////////////////////////////////////////////////////// testLimitNonCollectionLimitLimit : function () { var i; var list = [ ]; for (i = 0; i < 100; ++i) { list.push(i); } var tests = [ { offset: 0, limit: 500, offset2: 0, limit2: 1, expectedLength: 1 }, { offset: 10, limit: 5, offset2: 0, limit2: 1, expectedLength: 1 }, { offset: 10, limit: 5, offset2: 0, limit2: 20, expectedLength: 5 }, { offset: 10, limit: 50, offset2: 1, limit2: 20, expectedLength: 20 }, { offset: 10, limit: 90, offset2: 10, limit2: 20, expectedLength: 20 }, { offset: 90, limit: 10, offset2: 9, limit2: 20, expectedLength: 1 }, { offset: 50, limit: 50, offset2: 0, limit2: 50, expectedLength: 50 }, { offset: 50, limit: 50, offset2: 10, limit2: 50, expectedLength: 40 }, { offset: 50, limit: 50, offset2: 50, limit2: 50, expectedLength: 0 } ]; for (i = 0; i < tests.length; ++i) { var test = tests[i]; var query = "FOR c IN " + JSON.stringify(list) + " LIMIT " + test.offset + ", " + test.limit + " LIMIT " + test.offset2 + ", " + test.limit2 + " RETURN c"; var actual = getQueryResults(query); assertEqual(test.expectedLength, actual.length); assertEqual([ "SingletonNode", "CalculationNode", "EnumerateListNode", "LimitNode", "LimitNode", "ReturnNode" ], explain(query)); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with 2 limits //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionLimitLimit : function () { var tests = [ { offset: 0, limit: 500, offset2: 0, limit2: 1, expectedLength: 1 }, { offset: 10, limit: 5, offset2: 0, limit2: 1, expectedLength: 1 }, { offset: 10, limit: 5, offset2: 0, limit2: 20, expectedLength: 5 }, { offset: 10, limit: 50, offset2: 1, limit2: 20, expectedLength: 20 }, { offset: 10, limit: 90, offset2: 10, limit2: 20, expectedLength: 20 }, { offset: 90, limit: 10, offset2: 9, limit2: 20, expectedLength: 1 }, { offset: 50, limit: 50, offset2: 0, limit2: 50, expectedLength: 50 }, { offset: 50, limit: 50, offset2: 10, limit2: 50, expectedLength: 40 }, { offset: 50, limit: 50, offset2: 50, limit2: 50, expectedLength: 0 } ]; for (var i = 0; i < tests.length; ++i) { var test = tests[i]; var query = "FOR c IN " + cn + " SORT c.value LIMIT " + test.offset + ", " + test.limit + " LIMIT " + test.offset2 + ", " + test.limit2 + " RETURN c"; var actual = getQueryResults(query); assertEqual(test.expectedLength, actual.length); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization for non-collection access, limit > 0 and /// filter conditions //////////////////////////////////////////////////////////////////////////////// testLimitNonCollectionFilter : function () { var i; var list = [ ]; for (i = 0; i < 100; ++i) { list.push(i); } var tests = [ { offset: 0, limit: 500, value: 0, expectedLength: 100 }, { offset: 0, limit: 50, value: 0, expectedLength: 50 }, { offset: 0, limit: 5, value: 0, expectedLength: 5 }, { offset: 0, limit: 1, value: 0, expectedLength: 1 }, { offset: 1, limit: 50, value: 0, expectedLength: 50 }, { offset: 1, limit: 1, value: 0, expectedLength: 1 }, { offset: 10, limit: 50, value: 0, expectedLength: 50 }, { offset: 95, limit: 5, value: 0, expectedLength: 5 }, { offset: 95, limit: 50, value: 0, expectedLength: 5 }, { offset: 98, limit: 50, value: 0, expectedLength: 2 }, { offset: 98, limit: 2, value: 0, expectedLength: 2 }, { offset: 99, limit: 1, value: 0, expectedLength: 1 }, { offset: 99, limit: 2, value: 0, expectedLength: 1 }, { offset: 100, limit: 2, value: 0, expectedLength: 0 }, { offset: 0, limit: 500, value: 10, expectedLength: 90 }, { offset: 0, limit: 50, value: 10, expectedLength: 50 }, { offset: 0, limit: 5, value: 10, expectedLength: 5 }, { offset: 0, limit: 1, value: 10, expectedLength: 1 }, { offset: 50, limit: 1, value: 10, expectedLength: 1 }, { offset: 90, limit: 1, value: 0, expectedLength: 1 }, { offset: 89, limit: 1, value: 10, expectedLength: 1 }, { offset: 89, limit: 2, value: 10, expectedLength: 1 }, { offset: 90, limit: 1, value: 10, expectedLength: 0 }, { offset: 50, limit: 5, value: 40, expectedLength: 5 }, { offset: 50, limit: 5, value: 50, expectedLength: 0 } ]; for (i = 0; i < tests.length; ++i) { var test = tests[i]; var query = "FOR c IN " + JSON.stringify(list) + " FILTER c >= " + test.value + " LIMIT " + test.offset + ", " + test.limit + " RETURN c"; var actual = getQueryResults(query); assertEqual(test.expectedLength, actual.length); assertEqual([ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "FilterNode", "LimitNode", "ReturnNode" ], explain(query)); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization for full collection access, limit > 0 and /// filter conditions //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionFilter : function () { var tests = [ { offset: 0, limit: 500, value: 0, expectedLength: 100 }, { offset: 0, limit: 50, value: 0, expectedLength: 50 }, { offset: 0, limit: 5, value: 0, expectedLength: 5 }, { offset: 0, limit: 1, value: 0, expectedLength: 1 }, { offset: 1, limit: 50, value: 0, expectedLength: 50 }, { offset: 1, limit: 1, value: 0, expectedLength: 1 }, { offset: 10, limit: 50, value: 0, expectedLength: 50 }, { offset: 95, limit: 5, value: 0, expectedLength: 5 }, { offset: 95, limit: 50, value: 0, expectedLength: 5 }, { offset: 98, limit: 50, value: 0, expectedLength: 2 }, { offset: 98, limit: 2, value: 0, expectedLength: 2 }, { offset: 99, limit: 1, value: 0, expectedLength: 1 }, { offset: 99, limit: 2, value: 0, expectedLength: 1 }, { offset: 100, limit: 2, value: 0, expectedLength: 0 }, { offset: 0, limit: 500, value: 10, expectedLength: 90 }, { offset: 0, limit: 50, value: 10, expectedLength: 50 }, { offset: 0, limit: 5, value: 10, expectedLength: 5 }, { offset: 0, limit: 1, value: 10, expectedLength: 1 }, { offset: 50, limit: 1, value: 10, expectedLength: 1 }, { offset: 90, limit: 1, value: 0, expectedLength: 1 }, { offset: 89, limit: 1, value: 10, expectedLength: 1 }, { offset: 89, limit: 2, value: 10, expectedLength: 1 }, { offset: 90, limit: 1, value: 10, expectedLength: 0 }, { offset: 50, limit: 5, value: 40, expectedLength: 5 }, { offset: 50, limit: 5, value: 50, expectedLength: 0 } ]; for (var i = 0; i < tests.length; ++i) { var test = tests[i]; var query = "FOR c IN " + cn + " FILTER c.value >= " + test.value + " LIMIT " + test.offset + ", " + test.limit + " RETURN c"; var actual = getQueryResults(query); assertEqual(test.expectedLength, actual.length); assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "FilterNode", "RemoteNode", "GatherNode", "LimitNode", "ReturnNode" ], explain(query)); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization for full collection access, limit > 0 and /// filter conditions //////////////////////////////////////////////////////////////////////////////// testLimitFilterFilterCollectionFilter : function () { var tests = [ { offset: 0, limit: 500, value: 0, expectedLength: 100 }, { offset: 0, limit: 50, value: 0, expectedLength: 50 }, { offset: 0, limit: 5, value: 0, expectedLength: 5 }, { offset: 0, limit: 1, value: 0, expectedLength: 1 }, { offset: 1, limit: 50, value: 0, expectedLength: 50 }, { offset: 1, limit: 1, value: 0, expectedLength: 1 }, { offset: 10, limit: 50, value: 0, expectedLength: 50 }, { offset: 95, limit: 5, value: 0, expectedLength: 5 }, { offset: 95, limit: 50, value: 0, expectedLength: 5 }, { offset: 98, limit: 50, value: 0, expectedLength: 2 }, { offset: 98, limit: 2, value: 0, expectedLength: 2 }, { offset: 99, limit: 1, value: 0, expectedLength: 1 }, { offset: 99, limit: 2, value: 0, expectedLength: 1 }, { offset: 100, limit: 2, value: 0, expectedLength: 0 }, { offset: 0, limit: 500, value: 10, expectedLength: 90 }, { offset: 0, limit: 50, value: 10, expectedLength: 50 }, { offset: 0, limit: 5, value: 10, expectedLength: 5 }, { offset: 0, limit: 1, value: 10, expectedLength: 1 }, { offset: 50, limit: 1, value: 10, expectedLength: 1 }, { offset: 90, limit: 1, value: 0, expectedLength: 1 }, { offset: 89, limit: 1, value: 10, expectedLength: 1 }, { offset: 89, limit: 2, value: 10, expectedLength: 1 }, { offset: 90, limit: 1, value: 10, expectedLength: 0 }, { offset: 50, limit: 5, value: 40, expectedLength: 5 }, { offset: 50, limit: 5, value: 50, expectedLength: 0 } ]; for (var i = 0; i < tests.length; ++i) { var test = tests[i]; var query = "FOR c IN " + cn + " FILTER c.value >= " + test.value + " FILTER c.value <= 9999 LIMIT " + test.offset + ", " + test.limit + " RETURN c"; var actual = getQueryResults(query); assertEqual(test.expectedLength, actual.length); assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "FilterNode", "RemoteNode", "GatherNode", "LimitNode", "ReturnNode" ], explain(query)); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with index //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionHashIndex1 : function () { collection.ensureHashIndex("value"); var query = "FOR c IN " + cn + " FILTER c.value == 23 || c.value == 24 LIMIT 0, 10 SORT c.value RETURN c"; var actual = getQueryResults(query); assertEqual(2, actual.length); assertEqual(23, actual[0].value); assertEqual(24, actual[1].value); assertEqual([ "SingletonNode", "IndexNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "SortNode", "ReturnNode" ], explain(query)); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with index //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionHashIndex2 : function () { collection.ensureHashIndex("value"); var query = "FOR c IN " + cn + " FILTER c.value >= 20 && c.value < 30 LIMIT 0, 10 SORT c.value RETURN c"; var actual = getQueryResults(query); assertEqual(10, actual.length); assertEqual(20, actual[0].value); assertEqual(21, actual[1].value); assertEqual(29, actual[9].value); if (db._engine().name !== "rocksdb") { assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "FilterNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "SortNode", "ReturnNode" ], explain(query)); } else { // RocksDB HashIndex can be used for range queries. assertEqual([ "SingletonNode", "IndexNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "SortNode", "ReturnNode" ], explain(query)); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with index //////////////////////////////////////////////////////////////////////////////// testLimitFilterFilterCollectionHashIndex : function () { collection.ensureHashIndex("value"); var query = "FOR c IN " + cn + " FILTER c.value >= 20 && c.value < 30 FILTER c.value <= 9999 LIMIT 0, 10 SORT c.value RETURN c"; var actual = getQueryResults(query); assertEqual(10, actual.length); assertEqual(20, actual[0].value); assertEqual(21, actual[1].value); assertEqual(29, actual[9].value); if (db._engine().name !== "rocksdb") { assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "FilterNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "SortNode", "ReturnNode" ], explain(query)); } else { // RocksDB HashIndex can be used for range queries. assertEqual([ "SingletonNode", "IndexNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "SortNode", "ReturnNode" ], explain(query)); } }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with index //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionSkiplistIndex1 : function () { collection.ensureSkiplist("value"); var query = "FOR c IN " + cn + " FILTER c.value == 23 || c.value == 24 LIMIT 0, 10 SORT c.value RETURN c"; var actual = getQueryResults(query); assertEqual(2, actual.length); assertEqual(23, actual[0].value); assertEqual(24, actual[1].value); assertEqual([ "SingletonNode", "IndexNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "SortNode", "ReturnNode" ], explain(query)); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with index //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionSkiplistIndex2 : function () { collection.ensureSkiplist("value"); var query = "FOR c IN " + cn + " FILTER c.value >= 20 && c.value < 30 LIMIT 0, 10 SORT c.value RETURN c"; var actual = getQueryResults(query); assertEqual(10, actual.length); assertEqual(20, actual[0].value); assertEqual(21, actual[1].value); assertEqual(29, actual[9].value); assertEqual([ "SingletonNode", "IndexNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "SortNode", "ReturnNode" ], explain(query)); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with index //////////////////////////////////////////////////////////////////////////////// testLimitFilterFilterSkiplistIndex : function () { collection.ensureSkiplist("value"); var query = "FOR c IN " + cn + " FILTER c.value >= 20 && c.value < 30 FILTER c.value <= 9999 LIMIT 0, 10 SORT c.value RETURN c"; var actual = getQueryResults(query); assertEqual(10, actual.length); assertEqual(20, actual[0].value); assertEqual(21, actual[1].value); assertEqual(29, actual[9].value); assertEqual([ "SingletonNode", "IndexNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "SortNode", "ReturnNode" ], explain(query)); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with sort //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionSort1 : function () { var query = "FOR c IN " + cn + " FILTER c.value >= 20 && c.value < 30 LIMIT 0, 10 SORT c.value RETURN c"; var actual = getQueryResults(query); assertEqual(10, actual.length); assertEqual(20, actual[0].value); assertEqual(21, actual[1].value); assertEqual(29, actual[9].value); assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "FilterNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "SortNode", "ReturnNode" ], explain(query)); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with sort //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionSort2 : function () { var query = "FOR c IN " + cn + " FILTER c.value >= 20 && c.value < 30 LIMIT 0, 10 SORT c.value RETURN c"; var actual = getQueryResults(query); assertEqual(10, actual.length); assertEqual(20, actual[0].value); assertEqual(21, actual[1].value); assertEqual(22, actual[2].value); assertEqual(29, actual[9].value); assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "FilterNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "SortNode", "ReturnNode" ], explain(query)); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with sort //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionSort3 : function () { var query = "FOR c IN " + cn + " SORT c.value LIMIT 0, 10 FILTER c.value >= 20 && c.value < 30 RETURN c"; var actual = getQueryResults(query); assertEqual(0, actual.length); assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "CalculationNode", "SortNode", "RemoteNode", "GatherNode", "LimitNode", "FilterNode", "ReturnNode" ], explain(query)); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit optimization with sort //////////////////////////////////////////////////////////////////////////////// testLimitFullCollectionSort4 : function () { var query = "FOR c IN " + cn + " FILTER c.value >= 20 && c.value < 30 SORT c.value LIMIT 0, 10 RETURN c"; var actual = getQueryResults(query); assertEqual(10, actual.length); assertEqual(20, actual[0].value); assertEqual(21, actual[1].value); assertEqual(22, actual[2].value); assertEqual(29, actual[9].value); assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "FilterNode", "CalculationNode", "SortNode", "RemoteNode", "GatherNode", "LimitNode", "ReturnNode" ], explain(query)); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit in nested loops //////////////////////////////////////////////////////////////////////////////// testLimitNested1 : function () { var query = "FOR o IN [ 1, 2, 3 ] FOR i IN [ 5, 6, 7 ] LIMIT 2 RETURN { o: o, i: i }"; var actual = getQueryResults(query); assertEqual([ { i: 5, o: 1 }, { i: 6, o: 1 } ], actual); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit in nested loops //////////////////////////////////////////////////////////////////////////////// testLimitNested2 : function () { var query = "FOR o IN [ 1, 2, 3 ] FOR i IN [ 5, 6, 7 ] LIMIT 0, 1 RETURN { o: o, i: i }"; var actual = getQueryResults(query); assertEqual([ { i: 5, o: 1 } ], actual); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit in nested loops //////////////////////////////////////////////////////////////////////////////// testLimitNested3 : function () { var query = "FOR o IN [ 1, 2, 3 ] FOR i IN [ 5, 6, 7 ] SORT o, i LIMIT 1, 1 RETURN { o: o, i: i }"; var actual = getQueryResults(query); assertEqual([ { i: 6, o: 1 } ], actual); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit in nested loops //////////////////////////////////////////////////////////////////////////////// testLimitNested4 : function () { var query = "FOR o IN [ 1, 2, 3 ] LIMIT 1 FOR i IN [ 5, 6, 7 ] RETURN { o: o, i: i }"; var actual = getQueryResults(query); assertEqual([ { i: 5, o: 1 }, { i: 6, o: 1 }, { i: 7, o: 1 } ], actual); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit in nested loops //////////////////////////////////////////////////////////////////////////////// testLimitNested5 : function () { var query = "FOR o IN [ 1, 2, 3 ] LIMIT 1, 1 FOR i IN [ 5, 6, 7 ] RETURN { o: o, i: i }"; var actual = getQueryResults(query); assertEqual([ { i: 5, o: 2 }, { i: 6, o: 2 }, { i: 7, o: 2 } ], actual); }, //////////////////////////////////////////////////////////////////////////////// /// @brief check limit in nested loops //////////////////////////////////////////////////////////////////////////////// testLimitNested6 : function () { var query = "FOR o IN [ 1, 2, 3 ] LIMIT 1 FOR i IN [ 5, 6, 7 ] LIMIT 2 RETURN { o: o, i: i }"; var actual = getQueryResults(query); assertEqual([ { i: 5, o: 1 }, { i: 6, o: 1 } ], actual); }, testLimitProcessingWithFilter : function () { var query = "FOR doc IN " + cn + " FILTER doc.value >= 50 LIMIT 10 RETURN doc.value"; var actual = getQueryResults(query); assertEqual(10, actual.length); assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "FilterNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "ReturnNode" ], explain(query)); }, testLimitProcessingWithoutFilter : function () { var query = "FOR doc IN " + cn + " LIMIT 10 RETURN doc.value"; var actual = getQueryResults(query); assertEqual(10, actual.length); assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "ReturnNode" ], explain(query)); }, }; } //////////////////////////////////////////////////////////////////////////////// /// @brief executes the test suite //////////////////////////////////////////////////////////////////////////////// jsunity.run(ahuacatlQueryOptimizerLimitTestSuite); return jsunity.done();