1
0
Fork 0

Merge branch 'aql-functions' of https://github.com/triAGENS/ArangoDB into devel

This commit is contained in:
Jan Steemann 2014-11-20 14:49:02 +01:00
commit 5f453b80e5
15 changed files with 1485 additions and 4 deletions

View File

@ -1,6 +1,11 @@
v2.4.0 (XXXX-XX-XX) v2.4.0 (XXXX-XX-XX)
------------------- -------------------
* added AQL list functions `PUSH`, `POP`, `UNSHIFT`, `SHIFT`, `REMOVE_VALUES`,
`REMOVE_VALUE`, `REMOVE_NTH` and `APPEND`
* added AQL functions `CALL` and `APPLY` to dynamically call other functions
v2.3.0 (2014-11-18) v2.3.0 (2014-11-18)
------------------- -------------------

View File

@ -173,6 +173,85 @@ AQL supports the following functions to operate on list values:
Note: Duplicates will be removed. Note: Duplicates will be removed.
- *APPEND(list, values, unique)*: Adds all elements from the list *values* to the list
specified by *list*. If *unique* is set to true, then only those *values* will be added
that are not already contained in *list*.
The modified list is returned. All values are added at the end of the list (right side).
/* [ 1, 2, 3, 5, 6, 9 ] */
APPEND([ 1, 2, 3 ], [ 5, 6, 9 ])
/* [ 1, 2, 3, 4, 5, 9 ] */
APPEND([ 1, 2, 3 ], [ 3, 4, 5, 2, 9 ], true)
- *PUSH(list, value, unique)*: Adds *value* to the list specified by *list*. If
*unique* is set to true, then *value* is not added if already present in the list.
The modified list is returned. The value is added at the end of the list (right side).
Note: non-unique elements will not be removed from the list if they were already present
before the call to `PUSH`. The *unique* flag will only control if the value will
be added again to the list if already present. To make a list unique, use the `UNIQUE`
function.
/* [ 1, 2, 3, 4 ] */
PUSH([ 1, 2, 3 ], 4)
/* [ 1, 2, 3 ] */
PUSH([ 1, 2, 3 ], 2, true)
- *UNSHIFT(list, value, unique)*: Adds *value* to the list specified by *list*. If
*unique* is set to true, then *value* is not added if already present in the list.
The modified list is returned. The value is added at the start of the list (left side).
Note: non-unique elements will not be removed from the list if they were already present
before the call to `UNSHIFT`. The *unique* flag will only control if the value will
be added again to the list if already present. To make a list unique, use the `UNIQUE`
function.
/* [ 4, 1, 2, 3 ] */
UNSHIFT([ 1, 2, 3 ], 4)
/* [ 1, 2, 3 ] */
UNSHIFT([ 1, 2, 3 ], 2, true)
- *POP(list)*: Removes the element at the end (right side) of *list*. The modified list
is returned. If the list is already empty or *null*, an empty list is returned.
/* [ 1, 2, 3 ] */
POP([ 1, 2, 3, 4 ])
- *SHIFT(list)*: Removes the element at the start (left side) of *list*. The modified list
is returned. If the list is already empty or *null*, an empty list is returned.
/* [ 2, 3, 4 ] */
SHIFT([ 1, 2, 3, 4 ])
- *REMOVE_VALUE(list, value, limit)*: Removes all occurrences of *value* in the list
specified by *list*. If the optional *limit* is specified, only *limit* occurrences
will be removed.
/* [ "b", "b", "c" ] */
REMOVE_VALUE([ "a", "b", "b", "a", "c" ], "a")
/* [ "b", "b", "a", "c" ] */
REMOVE_VALUE([ "a", "b", "b", "a", "c" ], "a", 1)
- *REMOVE_VALUES(list, values)*: Removes all occurrences of any of the values specified
in list *values* from the list specified by *list*.
/* [ "b", "c", "e", "g" ] */
REMOVE_VALUES([ "a", "b", "c", "d", "e", "f", "g" ], [ "a", "f", "d" ])
- *REMOVE_NTH(list, position)*: Removes the element at position *position* from the
list specified by *list*. Positions start at 0. Negative positions are supported,
with -1 being the last list element. If *position* is out of bounds, the list is
returned unmodified. Otherwise, the modified list is returned.
/* [ "a", "c", "d", "e" ] */
REMOVE_NTH([ "a", "b", "c", "d", "e" ], 1)
/* [ "a", "b", "c", "e" ] */
REMOVE_NTH([ "a", "b", "c", "d", "e" ], -2)
Apart from these functions, AQL also offers several language constructs (e.g. Apart from these functions, AQL also offers several language constructs (e.g.
*FOR*, *SORT*, *LIMIT*, *COLLECT*) to operate on lists. *FOR*, *SORT*, *LIMIT*, *COLLECT*) to operate on lists.

View File

@ -66,3 +66,17 @@ function categories:
as in the index. as in the index.
If no suitable skiplist index is found, an error will be raised and the query will be aborted. If no suitable skiplist index is found, an error will be raised and the query will be aborted.
- *CALL(function, arg1, ..., argn)*: Dynamically calls the function with name *function*
with the arguments specified. Both built-in and user-defined functions can be called.
Arguments are passed as seperate parameters to the called function.
/* "this" */
CALL('SUBSTRING', 'this is a test', 0, 4)
- *APPLY(function, arguments)*: Dynamically calls the function with name *function*
with the arguments specified. Both built-in and user-defined functions can be called.
Arguments are passed as seperate parameters to the called function.
/* "this is" */
APPLY('SUBSTRING', [ 'this is a test', 0, 7 ])

View File

@ -533,6 +533,7 @@ unittests-shell-server-ahuacatl:
SHELL_SERVER_AQL = @top_srcdir@/js/server/tests/aql-arithmetic.js \ SHELL_SERVER_AQL = @top_srcdir@/js/server/tests/aql-arithmetic.js \
@top_srcdir@/js/server/tests/aql-bind.js \ @top_srcdir@/js/server/tests/aql-bind.js \
@top_srcdir@/js/server/tests/aql-call-apply.js \
@top_srcdir@/js/server/tests/aql-complex.js \ @top_srcdir@/js/server/tests/aql-complex.js \
@top_srcdir@/js/server/tests/aql-cross.js \ @top_srcdir@/js/server/tests/aql-cross.js \
@top_srcdir@/js/server/tests/aql-edges-noncluster.js \ @top_srcdir@/js/server/tests/aql-edges-noncluster.js \
@ -540,6 +541,7 @@ SHELL_SERVER_AQL = @top_srcdir@/js/server/tests/aql-arithmetic.js \
@top_srcdir@/js/server/tests/aql-explain-noncluster.js \ @top_srcdir@/js/server/tests/aql-explain-noncluster.js \
@top_srcdir@/js/server/tests/aql-functions.js \ @top_srcdir@/js/server/tests/aql-functions.js \
@top_srcdir@/js/server/tests/aql-functions-date.js \ @top_srcdir@/js/server/tests/aql-functions-date.js \
@top_srcdir@/js/server/tests/aql-functions-list.js \
@top_srcdir@/js/server/tests/aql-functions-misc.js \ @top_srcdir@/js/server/tests/aql-functions-misc.js \
@top_srcdir@/js/server/tests/aql-functions-numeric.js \ @top_srcdir@/js/server/tests/aql-functions-numeric.js \
@top_srcdir@/js/server/tests/aql-functions-string.js \ @top_srcdir@/js/server/tests/aql-functions-string.js \

View File

@ -155,6 +155,17 @@ std::unordered_map<std::string, Function const> const Executor::FunctionNames{
{ "LAST", Function("LAST", "AQL_LAST", "l", true, false, true) }, { "LAST", Function("LAST", "AQL_LAST", "l", true, false, true) },
{ "NTH", Function("NTH", "AQL_NTH", "l,n", true, false, true) }, { "NTH", Function("NTH", "AQL_NTH", "l,n", true, false, true) },
{ "POSITION", Function("POSITION", "AQL_POSITION", "l,.|b", true, false, true) }, { "POSITION", Function("POSITION", "AQL_POSITION", "l,.|b", true, false, true) },
{ "CALL", Function("CALL", "AQL_CALL", "s|.+", false, true, false) },
{ "APPLY", Function("APPLY", "AQL_APPLY", "s|l", false, true, false) },
{ "PUSH", Function("PUSH", "AQL_PUSH", "l,.|b", true, false, false) },
{ "APPEND", Function("APPEND", "AQL_APPEND", "l,lz|b", true, false, false) },
{ "POP", Function("POP", "AQL_POP", "l", true, false, false) },
{ "POP", Function("POP", "AQL_POP", "l", true, false, false) },
{ "SHIFT", Function("SHIFT", "AQL_SHIFT", "l", true, false, false) },
{ "UNSHIFT", Function("UNSHIFT", "AQL_UNSHIFT", "l,.|b", true, false, false) },
{ "REMOVE_VALUE", Function("REMOVE_VALUE", "AQL_REMOVE_VALUE", "l,.|n", true, false, false) },
{ "REMOVE_VALUES", Function("REMOVE_VALUES", "AQL_REMOVE_VALUES", "l,lz", true, false, false) },
{ "REMOVE_NTH", Function("REMOVE_NTH", "AQL_REMOVE_NTH", "l,n", true, false, false) },
// document functions // document functions
{ "HAS", Function("HAS", "AQL_HAS", "az,s", true, false, true) }, { "HAS", Function("HAS", "AQL_HAS", "az,s", true, false, true) },

View File

@ -177,7 +177,7 @@ namespace triagens {
/// @brief maximum number of function arguments that can be used /// @brief maximum number of function arguments that can be used
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static size_t const MaxArguments = 1024; static size_t const MaxArguments = 65536;
}; };

View File

@ -177,6 +177,7 @@
"ERROR_QUERY_COMPILE_TIME_OPTIONS" : { "code" : 1575, "message" : "query options must be readable at query compile time" }, "ERROR_QUERY_COMPILE_TIME_OPTIONS" : { "code" : 1575, "message" : "query options must be readable at query compile time" },
"ERROR_QUERY_EXCEPTION_OPTIONS" : { "code" : 1576, "message" : "query options expected" }, "ERROR_QUERY_EXCEPTION_OPTIONS" : { "code" : 1576, "message" : "query options expected" },
"ERROR_QUERY_COLLECTION_USED_IN_EXPRESSION" : { "code" : 1577, "message" : "collection '%s' used as expression operand" }, "ERROR_QUERY_COLLECTION_USED_IN_EXPRESSION" : { "code" : 1577, "message" : "collection '%s' used as expression operand" },
"ERROR_QUERY_DISALLOWED_DYNAMIC_CALL" : { "code" : 1578, "message" : "disallowed dynamic call to '%s'" },
"ERROR_QUERY_FUNCTION_INVALID_NAME" : { "code" : 1580, "message" : "invalid user function name" }, "ERROR_QUERY_FUNCTION_INVALID_NAME" : { "code" : 1580, "message" : "invalid user function name" },
"ERROR_QUERY_FUNCTION_INVALID_CODE" : { "code" : 1581, "message" : "invalid user function code" }, "ERROR_QUERY_FUNCTION_INVALID_CODE" : { "code" : 1581, "message" : "invalid user function code" },
"ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function '%s()' not found" }, "ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function '%s()' not found" },

View File

@ -177,6 +177,7 @@
"ERROR_QUERY_COMPILE_TIME_OPTIONS" : { "code" : 1575, "message" : "query options must be readable at query compile time" }, "ERROR_QUERY_COMPILE_TIME_OPTIONS" : { "code" : 1575, "message" : "query options must be readable at query compile time" },
"ERROR_QUERY_EXCEPTION_OPTIONS" : { "code" : 1576, "message" : "query options expected" }, "ERROR_QUERY_EXCEPTION_OPTIONS" : { "code" : 1576, "message" : "query options expected" },
"ERROR_QUERY_COLLECTION_USED_IN_EXPRESSION" : { "code" : 1577, "message" : "collection '%s' used as expression operand" }, "ERROR_QUERY_COLLECTION_USED_IN_EXPRESSION" : { "code" : 1577, "message" : "collection '%s' used as expression operand" },
"ERROR_QUERY_DISALLOWED_DYNAMIC_CALL" : { "code" : 1578, "message" : "disallowed dynamic call to '%s'" },
"ERROR_QUERY_FUNCTION_INVALID_NAME" : { "code" : 1580, "message" : "invalid user function name" }, "ERROR_QUERY_FUNCTION_INVALID_NAME" : { "code" : 1580, "message" : "invalid user function name" },
"ERROR_QUERY_FUNCTION_INVALID_CODE" : { "code" : 1581, "message" : "invalid user function code" }, "ERROR_QUERY_FUNCTION_INVALID_CODE" : { "code" : 1581, "message" : "invalid user function code" },
"ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function '%s()' not found" }, "ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function '%s()' not found" },

View File

@ -544,8 +544,7 @@ function FCALL_USER (name, parameters) {
if (UserFunctions[prefix].hasOwnProperty(name)) { if (UserFunctions[prefix].hasOwnProperty(name)) {
try { try {
var result = UserFunctions[prefix][name].func.apply(null, parameters); return FIX_VALUE(UserFunctions[prefix][name].func.apply(null, parameters));
return FIX_VALUE(result);
} }
catch (err) { catch (err) {
WARN(name, INTERNAL.errors.ERROR_QUERY_FUNCTION_RUNTIME_ERROR, AQL_TO_STRING(err)); WARN(name, INTERNAL.errors.ERROR_QUERY_FUNCTION_RUNTIME_ERROR, AQL_TO_STRING(err));
@ -556,6 +555,76 @@ function FCALL_USER (name, parameters) {
THROW(null, INTERNAL.errors.ERROR_QUERY_FUNCTION_NOT_FOUND, NORMALIZE_FNAME(name)); THROW(null, INTERNAL.errors.ERROR_QUERY_FUNCTION_NOT_FOUND, NORMALIZE_FNAME(name));
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief dynamically call a function
////////////////////////////////////////////////////////////////////////////////
function FCALL_DYNAMIC (func, applyDirect, values, name, args) {
var toCall;
name = AQL_TO_STRING(name).toUpperCase();
if (name.indexOf('::') > 0) {
// user-defined function
var prefix = DB_PREFIX();
if (! UserFunctions.hasOwnProperty(prefix)) {
reloadUserFunctions();
}
if (! UserFunctions.hasOwnProperty(prefix) ||
! UserFunctions[prefix].hasOwnProperty(name)) {
THROW(func, INTERNAL.errors.ERROR_QUERY_FUNCTION_NOT_FOUND, NORMALIZE_FNAME(name));
}
toCall = UserFunctions[prefix][name].func;
}
else {
// built-in function
if (name === "CALL" || name === "APPLY") {
THROW(func, INTERNAL.errors.ERROR_QUERY_DISALLOWED_DYNAMIC_CALL, NORMALIZE_FNAME(name));
}
if (! exports.hasOwnProperty("AQL_" + name)) {
THROW(func, INTERNAL.errors.ERROR_QUERY_FUNCTION_NOT_FOUND, NORMALIZE_FNAME(name));
}
toCall = exports["AQL_" + name];
}
if (applyDirect) {
try {
return FIX_VALUE(toCall.apply(null, args));
}
catch (err) {
WARN(name, INTERNAL.errors.ERROR_QUERY_FUNCTION_RUNTIME_ERROR, AQL_TO_STRING(err));
return null;
}
}
var type = TYPEWEIGHT(values), result, i;
if (type === TYPEWEIGHT_DOCUMENT) {
result = { };
for (i in values) {
if (values.hasOwnProperty(i)) {
args[0] = values[i];
result[i] = FIX_VALUE(toCall.apply(null, args));
}
}
return result;
}
else if (type === TYPEWEIGHT_LIST) {
result = [ ];
for (i = 0; i < values.length; ++i) {
args[0] = values[i];
result[i] = FIX_VALUE(toCall.apply(null, args));
}
return result;
}
WARN(func, INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return null;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief return the numeric value or undefined if it is out of range /// @brief return the numeric value or undefined if it is out of range
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -2525,6 +2594,323 @@ function AQL_UNION_DISTINCT () {
return result; return result;
} }
/*
////////////////////////////////////////////////////////////////////////////////
/// @brief call a function for each element in the input list
////////////////////////////////////////////////////////////////////////////////
function AQL_CALL (values, name) {
"use strict";
var args = [ null ], i;
for (i = 2; i < arguments.length; ++i) {
args.push(arguments[i]);
}
return FCALL_DYNAMIC("CALL", false, values, name, args);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief call a function for each element in the input list
////////////////////////////////////////////////////////////////////////////////
function AQL_APPLY (values, name, parameters) {
"use strict";
var args = [ null ], i;
if (Array.isArray(parameters)) {
args = args.concat(parameters);
}
return FCALL_DYNAMIC("APPLY", false, values, name, args);
}
*/
////////////////////////////////////////////////////////////////////////////////
/// @brief call a function for each element in the input list
////////////////////////////////////////////////////////////////////////////////
function AQL_CALL (name) {
"use strict";
var args = [ ], i;
for (i = 1; i < arguments.length; ++i) {
args.push(arguments[i]);
}
return FCALL_DYNAMIC("CALL", true, null, name, args);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief call a function for each element in the input list
////////////////////////////////////////////////////////////////////////////////
function AQL_APPLY (name, parameters) {
"use strict";
var args = [ ], i;
if (Array.isArray(parameters)) {
args = args.concat(parameters);
}
return FCALL_DYNAMIC("APPLY", true, null, name, args);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes elements from a list
////////////////////////////////////////////////////////////////////////////////
function AQL_REMOVE_VALUES (list, values) {
"use strict";
var type = TYPEWEIGHT(values);
if (type === TYPEWEIGHT_NULL) {
return list;
}
else if (type !== TYPEWEIGHT_LIST) {
WARN("REMOVE_VALUES", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return null;
}
type = TYPEWEIGHT(list);
if (type === TYPEWEIGHT_NULL) {
return [ ];
}
else if (type === TYPEWEIGHT_LIST) {
var copy = [ ], i;
for (i = 0; i < list.length; ++i) {
if (RELATIONAL_IN(list[i], values)) {
continue;
}
copy.push(CLONE(list[i]));
}
return copy;
}
WARN("REMOVE_VALUES", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return null;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an element from a list
////////////////////////////////////////////////////////////////////////////////
function AQL_REMOVE_VALUE (list, value, limit) {
"use strict";
var type = TYPEWEIGHT(list);
if (type === TYPEWEIGHT_NULL) {
return [ ];
}
else if (type === TYPEWEIGHT_LIST) {
if (TYPEWEIGHT(limit) === TYPEWEIGHT_NULL) {
limit = -1;
}
var copy = [ ], i;
for (i = 0; i < list.length; ++i) {
if (limit === -1 && RELATIONAL_CMP(list[i], value) === 0) {
continue;
}
else if (limit > 0 && RELATIONAL_CMP(list[i], value) === 0) {
--limit;
continue;
}
copy.push(CLONE(list[i]));
}
return copy;
}
WARN("REMOVE_VALUE", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return null;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an element from a list
////////////////////////////////////////////////////////////////////////////////
function AQL_REMOVE_NTH (list, position) {
"use strict";
var type = TYPEWEIGHT(list);
if (type === TYPEWEIGHT_NULL) {
return [ ];
}
else if (type === TYPEWEIGHT_LIST) {
position = AQL_TO_NUMBER(position);
if (position >= list.length || position < - list.length) {
return list;
}
if (position === 0) {
return list.slice(1);
}
else if (position === - list.length) {
return list.slice(position + 1);
}
else if (position === list.length - 1) {
return list.slice(0, position);
}
else if (position < 0) {
return list.slice(0, list.length + position).concat(list.slice(list.length + position + 1));
}
return list.slice(0, position).concat(list.slice(position + 1));
}
WARN("REMOVE_NTH", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return null;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adds an element to a list
////////////////////////////////////////////////////////////////////////////////
function AQL_PUSH (list, value, unique) {
"use strict";
var type = TYPEWEIGHT(list);
if (type === TYPEWEIGHT_NULL) {
return [ value ];
}
else if (type === TYPEWEIGHT_LIST) {
if (AQL_TO_BOOL(unique)) {
if (RELATIONAL_IN(value, list)) {
return list;
}
}
var copy = CLONE(list);
copy.push(value);
return copy;
}
WARN("PUSH", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return null;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adds elements to a list
////////////////////////////////////////////////////////////////////////////////
function AQL_APPEND (list, values, unique) {
"use strict";
var type = TYPEWEIGHT(values);
if (type === TYPEWEIGHT_NULL) {
return list;
}
else if (type !== TYPEWEIGHT_LIST) {
WARN("APPEND", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return null;
}
if (values.length === 0) {
return list;
}
unique = AQL_TO_BOOL(unique);
if (values.length > 1 && unique) {
// make values unique themselves
values = AQL_UNIQUE(values);
}
type = TYPEWEIGHT(list);
if (type === TYPEWEIGHT_NULL) {
return values;
}
else if (type === TYPEWEIGHT_LIST) {
var copy = CLONE(list);
if (unique) {
var i;
for (i = 0; i < values.length; ++i) {
if (RELATIONAL_IN(values[i], list)) {
continue;
}
copy.push(values[i]);
}
return copy;
}
return copy.concat(values);
}
WARN("APPEND", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return null;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief pops an element from a list
////////////////////////////////////////////////////////////////////////////////
function AQL_POP (list) {
"use strict";
var type = TYPEWEIGHT(list);
if (type === TYPEWEIGHT_NULL) {
return null;
}
else if (type === TYPEWEIGHT_LIST) {
if (list.length === 0) {
return [ ];
}
var copy = CLONE(list);
copy.pop();
return copy;
}
WARN("POP", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return null;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief insert an element into a list
////////////////////////////////////////////////////////////////////////////////
function AQL_UNSHIFT (list, value, unique) {
"use strict";
var type = TYPEWEIGHT(list);
if (type === TYPEWEIGHT_NULL) {
return [ value ];
}
else if (type === TYPEWEIGHT_LIST) {
if (unique) {
if (RELATIONAL_IN(value, list)) {
return list;
}
}
var copy = CLONE(list);
copy.unshift(value);
return copy;
}
WARN("UNSHIFT", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief pops an element from a list
////////////////////////////////////////////////////////////////////////////////
function AQL_SHIFT (list) {
"use strict";
var type = TYPEWEIGHT(list);
if (type === TYPEWEIGHT_NULL) {
return null;
}
else if (type === TYPEWEIGHT_LIST) {
if (list.length === 0) {
return [ ];
}
var copy = CLONE(list);
copy.shift();
return copy;
}
WARN("SHIFT", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return null;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief extract a slice from a list /// @brief extract a slice from a list
@ -7148,6 +7534,16 @@ exports.AQL_RANGE = AQL_RANGE;
exports.AQL_UNIQUE = AQL_UNIQUE; exports.AQL_UNIQUE = AQL_UNIQUE;
exports.AQL_UNION = AQL_UNION; exports.AQL_UNION = AQL_UNION;
exports.AQL_UNION_DISTINCT = AQL_UNION_DISTINCT; exports.AQL_UNION_DISTINCT = AQL_UNION_DISTINCT;
exports.AQL_CALL = AQL_CALL;
exports.AQL_APPLY = AQL_APPLY;
exports.AQL_REMOVE_VALUE = AQL_REMOVE_VALUE;
exports.AQL_REMOVE_VALUES = AQL_REMOVE_VALUES;
exports.AQL_REMOVE_NTH = AQL_REMOVE_NTH;
exports.AQL_PUSH = AQL_PUSH;
exports.AQL_APPEND = AQL_APPEND;
exports.AQL_POP = AQL_POP;
exports.AQL_SHIFT = AQL_SHIFT;
exports.AQL_UNSHIFT = AQL_UNSHIFT;
exports.AQL_SLICE = AQL_SLICE; exports.AQL_SLICE = AQL_SLICE;
exports.AQL_MINUS = AQL_MINUS; exports.AQL_MINUS = AQL_MINUS;
exports.AQL_INTERSECTION = AQL_INTERSECTION; exports.AQL_INTERSECTION = AQL_INTERSECTION;

View File

@ -0,0 +1,340 @@
/*jshint strict: false, maxlen: 500 */
/*global require, assertEqual */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, functions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var internal = require("internal");
var errors = internal.errors;
var jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper");
var getQueryResults = helper.getQueryResults;
var assertQueryError = helper.assertQueryError;
var assertQueryWarningAndNull = helper.assertQueryWarningAndNull;
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function ahuacatlCallApplyTestSuite () {
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief test call function
////////////////////////////////////////////////////////////////////////////////
testCall : function () {
var data = [
[ "foo bar", [ "TRIM", " foo bar " ] ],
[ "foo bar", [ "TRIM", " foo bar ", "\r\n \t" ] ],
[ "..foo bar..", [ "TRIM", " ..foo bar.. " ] ],
[ "foo bar", [ "TRIM", " ..foo bar.. ", ". " ] ],
[ "foo", [ "LEFT", "foobarbaz", 3 ] ],
[ "fooba", [ "LEFT", "foobarbaz", 5 ] ],
[ "foob", [ "SUBSTRING", "foobarbaz", 0, 4 ] ],
[ "oob", [ "SUBSTRING", "foobarbaz", 1, 3 ] ],
[ "barbaz", [ "SUBSTRING", "foobarbaz", 3 ] ],
[ "FOOBARBAZ", [ "UPPER", "foobarbaz" ] ],
[ "foobarbaz", [ "lower", "FOOBARBAZ" ] ],
[ "abcfood", [ "concat", "a", "b", "c", "foo", "d" ] ],
[ 1, [ "flOoR", 1.6 ] ],
[ 17, [ "MIN", [ 23, 42, 17 ] ] ],
[ [ 1, 2, 3, 4, 7, 9, 10, 12 ], [ "UNION_DISTINCT", [ 1, 2, 3, 4 ], [ 9, 12 ], [ 2, 9, 7, 10 ] ] ],
[ { a: true, b: false, c: null }, [ "ZIP", [ "a", "b", "c" ], [ true, false, null ] ] ]
];
data.forEach(function (d) {
var actual = getQueryResults("RETURN CALL(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test call function
////////////////////////////////////////////////////////////////////////////////
testCallDynamic1 : function () {
var actual = getQueryResults("FOR func IN [ 'TRIM', 'LOWER', 'UPPER' ] RETURN CALL(func, ' foObAr ')");
assertEqual(actual, [ 'foObAr', ' foobar ', ' FOOBAR ' ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test call function
////////////////////////////////////////////////////////////////////////////////
testCallDynamic2 : function () {
var actual = getQueryResults("FOR doc IN [ { value: ' foobar', func: 'TRIM' }, { value: 'FOOBAR', func: 'LOWER' }, { value: 'foobar', func: 'UPPER' } ] RETURN CALL(doc.func, doc.value)");
assertEqual(actual, [ 'foobar', 'foobar', 'FOOBAR' ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test call function
////////////////////////////////////////////////////////////////////////////////
testCallNonExisting : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN CALL()");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN CALL('nono-existing', [ 'baz' ])");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN CALL('foobar', 'baz')");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN CALL(' trim', 'baz')");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN CALL('foo::bar::baz', 'baz')");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN CALL(123, 'baz')");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN CALL([ ], 'baz')");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test call function
////////////////////////////////////////////////////////////////////////////////
testCallDisallowed : function () {
assertQueryError(errors.ERROR_QUERY_DISALLOWED_DYNAMIC_CALL.code, "RETURN CALL('CALL')");
assertQueryError(errors.ERROR_QUERY_DISALLOWED_DYNAMIC_CALL.code, "RETURN CALL('APPLY')");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test apply function
////////////////////////////////////////////////////////////////////////////////
testApply : function () {
var data = [
[ "foo bar", [ "TRIM", " foo bar " ] ],
[ "foo bar", [ "TRIM", " foo bar ", "\r\n \t" ] ],
[ "..foo bar..", [ "TRIM", " ..foo bar.. " ] ],
[ "foo bar", [ "TRIM", " ..foo bar.. ", ". " ] ],
[ "foo", [ "LEFT", "foobarbaz", 3 ] ],
[ "fooba", [ "LEFT", "foobarbaz", 5 ] ],
[ "foob", [ "SUBSTRING", "foobarbaz", 0, 4 ] ],
[ "oob", [ "SUBSTRING", "foobarbaz", 1, 3 ] ],
[ "barbaz", [ "SUBSTRING", "foobarbaz", 3 ] ],
[ "FOOBARBAZ", [ "UPPER", "foobarbaz" ] ],
[ "foobarbaz", [ "lower", "FOOBARBAZ" ] ],
[ "abcfood", [ "concat", "a", "b", "c", "foo", "d" ] ],
[ 1, [ "flOoR", 1.6 ] ],
[ 17, [ "MIN", [ 23, 42, 17 ] ] ],
[ [ 1, 2, 3, 4, 7, 9, 10, 12 ], [ "UNION_DISTINCT", [ 1, 2, 3, 4 ], [ 9, 12 ], [ 2, 9, 7, 10 ] ] ],
[ { a: true, b: false, c: null }, [ "ZIP", [ "a", "b", "c" ], [ true, false, null ] ] ]
];
data.forEach(function (d) {
var args = [ ];
for (var i = 1; i < d[1].length; ++i) {
args.push(d[1][i]);
}
var actual = getQueryResults("RETURN APPLY(" + JSON.stringify(d[1][0]) + ", " + JSON.stringify(args) + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test apply function
////////////////////////////////////////////////////////////////////////////////
testApplyDynamic1 : function () {
var actual = getQueryResults("FOR func IN [ 'TRIM', 'LOWER', 'UPPER' ] RETURN APPLY(func, [ ' foObAr ' ])");
assertEqual(actual, [ 'foObAr', ' foobar ', ' FOOBAR ' ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test apply function
////////////////////////////////////////////////////////////////////////////////
testApplyDynamic2 : function () {
var actual = getQueryResults("FOR doc IN [ { value: ' foobar', func: 'TRIM' }, { value: 'FOOBAR', func: 'LOWER' }, { value: 'foobar', func: 'UPPER' } ] RETURN APPLY(doc.func, [ doc.value ])");
assertEqual(actual, [ 'foobar', 'foobar', 'FOOBAR' ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test apply function
////////////////////////////////////////////////////////////////////////////////
testApplyNonExisting : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN APPLY()");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN APPLY('TRIM', 1, 2)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN APPLY('nono-existing', [ 'baz' ])");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN APPLY('foobar', [ 'baz' ])");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN APPLY(' trim', [ 'baz' ])");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN APPLY('foo::bar::baz', [ 'baz' ])");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN APPLY(123, [ 'baz' ])");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN APPLY([ ], [ 'baz' ])");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test apply function
////////////////////////////////////////////////////////////////////////////////
testApplyDisallowed : function () {
assertQueryError(errors.ERROR_QUERY_DISALLOWED_DYNAMIC_CALL.code, "RETURN APPLY('CALL')");
assertQueryError(errors.ERROR_QUERY_DISALLOWED_DYNAMIC_CALL.code, "RETURN APPLY('APPLY')");
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function ahuacatlCallUserDefinedTestSuite () {
var aqlfunctions = require("org/arangodb/aql/functions");
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
[ "add3", "add2", "call", "throwing" ].forEach(function (f) {
try {
aqlfunctions.unregister("UnitTests::func::" + f);
}
catch (err) {
}
});
aqlfunctions.register("UnitTests::func::add3", function (a, b, c) {
return a + b + c;
});
aqlfunctions.register("UnitTests::func::add2", function (a, b) {
return a + b;
});
aqlfunctions.register("UnitTests::func::call", function () {
return undefined;
});
aqlfunctions.register("UnitTests::func::throwing", function () {
throw "doh!";
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
[ "add3", "add2", "call", "throwing" ].forEach(function (f) {
try {
aqlfunctions.unregister("UnitTests::func::" + f);
}
catch (err) {
}
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test call function
////////////////////////////////////////////////////////////////////////////////
testCall : function () {
var data = [
[ null, [ "UnitTests::func::call", 1234 ] ],
[ null, [ "UnitTests::func::call", "foo", "bar" ] ],
[ null, [ "UnitTests::func::add2" ] ],
[ null, [ "UnitTests::func::add2", 23 ] ],
[ 23, [ "UnitTests::func::add2", 23, null ] ],
[ 65, [ "UnitTests::func::add2", 23, 42 ] ],
[ null, [ "UnitTests::func::add3", 23 ] ],
[ null, [ "UnitTests::func::add3", 23, 42 ] ],
[ 65, [ "UnitTests::func::add3", 23, 42, null ] ],
[ 120, [ "UnitTests::func::add3", 23, 42, 55 ] ],
[ "65foo", [ "UnitTests::func::add3", 23, 42, "foo" ] ],
[ "bar4213", [ "UnitTests::func::add3", "bar", 42, 13 ] ],
[ 96, [ "UNITTESTS::FUNC::aDD3", -1, 42, 55 ] ],
[ 96, [ "unittests::func::ADD3", -1, 42, 55 ] ]
];
data.forEach(function (d) {
var actual = getQueryResults("RETURN CALL(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test apply function
////////////////////////////////////////////////////////////////////////////////
testApply : function () {
var data = [
[ null, [ "UnitTests::func::call", 1234 ] ],
[ null, [ "UnitTests::func::call", "foo", "bar" ] ],
[ null, [ "UnitTests::func::add2" ] ],
[ null, [ "UnitTests::func::add2", 23 ] ],
[ 23, [ "UnitTests::func::add2", 23, null ] ],
[ 65, [ "UnitTests::func::add2", 23, 42 ] ],
[ null, [ "UnitTests::func::add3", 23 ] ],
[ null, [ "UnitTests::func::add3", 23, 42 ] ],
[ 65, [ "UnitTests::func::add3", 23, 42, null ] ],
[ 120, [ "UnitTests::func::add3", 23, 42, 55 ] ],
[ "65foo", [ "UnitTests::func::add3", 23, 42, "foo" ] ],
[ "bar4213", [ "UnitTests::func::add3", "bar", 42, 13 ] ],
[ 96, [ "UNITTESTS::FUNC::aDD3", -1, 42, 55 ] ],
[ 96, [ "unittests::func::ADD3", -1, 42, 55 ] ]
];
data.forEach(function (d) {
var args = [ ];
for (var i = 1; i < d[1].length; ++i) {
args.push(d[1][i]);
}
var actual = getQueryResults("RETURN APPLY(" + JSON.stringify(d[1][0]) + ", " + JSON.stringify(args) + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test non-existing functions
////////////////////////////////////////////////////////////////////////////////
testNonExisting : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN CALL('UNITTESTS::FUNC::MEOW', 'baz')");
assertQueryError(errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code, "RETURN APPLY('UNITTESTS::FUNC::MEOW', [ 'baz' ])");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test throwing function
////////////////////////////////////////////////////////////////////////////////
testThrows : function () {
assertQueryWarningAndNull(errors.ERROR_QUERY_FUNCTION_RUNTIME_ERROR.code, "RETURN CALL('UNITTESTS::FUNC::THROWING')");
assertQueryWarningAndNull(errors.ERROR_QUERY_FUNCTION_RUNTIME_ERROR.code, "RETURN APPLY('UNITTESTS::FUNC::THROWING', [ ])");
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsunity.run(ahuacatlCallApplyTestSuite);
jsunity.run(ahuacatlCallUserDefinedTestSuite);
return jsunity.done();
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -0,0 +1,617 @@
/*jshint strict: false, maxlen: 500 */
/*global require, assertEqual */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, functions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var internal = require("internal");
var errors = internal.errors;
var jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper");
var getQueryResults = helper.getQueryResults;
var assertQueryError = helper.assertQueryError;
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function ahuacatlListTestSuite () {
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief test push 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 ] ]
];
data.forEach(function (d) {
var actual = getQueryResults("RETURN PUSH(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test push function
////////////////////////////////////////////////////////////////////////////////
testPushBig : function () {
var l = [];
for (var i = 0; i < 2000; i += 2) {
l.push(i);
}
var actual = getQueryResults("RETURN PUSH(" + JSON.stringify(l) + ", 1000, true)");
assertEqual(l, actual[0]);
assertEqual(1000, actual[0].length);
actual = getQueryResults("RETURN PUSH(" + JSON.stringify(l) + ", 1000, true)");
assertEqual(l, actual[0]);
assertEqual(1000, actual[0].length);
actual = getQueryResults("RETURN PUSH(" + JSON.stringify(l) + ", 1000, false)");
l.push(1000);
assertEqual(l, actual[0]);
assertEqual(1001, actual[0].length);
actual = getQueryResults("RETURN PUSH(" + JSON.stringify(l) + ", 1001, true)");
l.push(1001);
assertEqual(l, actual[0]);
assertEqual(1002, actual[0].length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test push 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)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test unshift 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 ] ]
];
data.forEach(function (d) {
var actual = getQueryResults("RETURN UNSHIFT(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test unshift function
////////////////////////////////////////////////////////////////////////////////
testUnshiftBig : function () {
var l = [];
for (var i = 0; i < 2000; i += 2) {
l.push(i);
}
var actual = getQueryResults("RETURN UNSHIFT(" + JSON.stringify(l) + ", 1000, true)");
assertEqual(l, actual[0]);
assertEqual(1000, actual[0].length);
actual = getQueryResults("RETURN UNSHIFT(" + JSON.stringify(l) + ", 1000, true)");
assertEqual(l, actual[0]);
assertEqual(1000, actual[0].length);
actual = getQueryResults("RETURN UNSHIFT(" + JSON.stringify(l) + ", 1000, false)");
l.unshift(1000);
assertEqual(l, actual[0]);
assertEqual(1001, actual[0].length);
actual = getQueryResults("RETURN UNSHIFT(" + JSON.stringify(l) + ", 1001, true)");
l.unshift(1001);
assertEqual(l, actual[0]);
assertEqual(1002, actual[0].length);
},
////////////////////////////////////////////////////////////////////////////////
/// @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)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test pop 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 } ] ]
];
data.forEach(function (d) {
var actual = getQueryResults("RETURN POP(" + JSON.stringify(d[1]) + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test pop function
////////////////////////////////////////////////////////////////////////////////
testPopBig : function () {
var l = [];
for (var i = 0; i < 2000; i += 2) {
l.push(i);
}
var actual = getQueryResults("RETURN POP(" + JSON.stringify(l) + ")");
l.pop();
assertEqual(l, actual[0]);
assertEqual(999, actual[0].length);
actual = getQueryResults("RETURN POP(" + JSON.stringify(l) + ")");
l.pop();
assertEqual(l, actual[0]);
assertEqual(998, actual[0].length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test pop 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)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test shift 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 } ] ]
];
data.forEach(function (d) {
var actual = getQueryResults("RETURN SHIFT(" + JSON.stringify(d[1]) + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test shift function
////////////////////////////////////////////////////////////////////////////////
testShiftBig : function () {
var l = [];
for (var i = 0; i < 2000; i += 2) {
l.push(i);
}
var actual = getQueryResults("RETURN SHIFT(" + JSON.stringify(l) + ")");
l.shift();
assertEqual(l, actual[0]);
assertEqual(999, actual[0].length);
actual = getQueryResults("RETURN SHIFT(" + JSON.stringify(l) + ")");
l.shift();
assertEqual(l, actual[0]);
assertEqual(998, actual[0].length);
},
////////////////////////////////////////////////////////////////////////////////
/// @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)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test push/pop function
////////////////////////////////////////////////////////////////////////////////
testPushPop : function () {
var l = [], i, actual;
for (i = 0; i < 1000; ++i) {
actual = getQueryResults("RETURN PUSH(" + JSON.stringify(l) + ", " + JSON.stringify(i) + ")");
l.push(i);
assertEqual(l, actual[0]);
}
for (i = 0; i < 1000; ++i) {
actual = getQueryResults("RETURN POP(" + JSON.stringify(l) + ")");
l.pop();
assertEqual(l, actual[0]);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test unshift/shift function
////////////////////////////////////////////////////////////////////////////////
testUnshiftShift : function () {
var l = [], i, actual;
for (i = 0; i < 1000; ++i) {
actual = getQueryResults("RETURN UNSHIFT(" + JSON.stringify(l) + ", " + JSON.stringify(i) + ")");
l.unshift(i);
assertEqual(l, actual[0]);
}
for (i = 0; i < 1000; ++i) {
actual = getQueryResults("RETURN SHIFT(" + JSON.stringify(l) + ")");
l.shift();
assertEqual(l, actual[0]);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test append 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 ] ]
];
data.forEach(function (d) {
var actual = getQueryResults("RETURN APPEND(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test append function
////////////////////////////////////////////////////////////////////////////////
testAppendBig : function () {
var l1 = [], l2 = [ ];
for (var i = 0; i < 2000; i += 4) {
l1.push(i);
l2.push(i + 1);
}
var actual = getQueryResults("RETURN APPEND(" + JSON.stringify(l1) + ", " + JSON.stringify(l2) + ")");
var l = l1.concat(l2);
assertEqual(l, actual[0]);
assertEqual(1000, actual[0].length);
actual = getQueryResults("RETURN APPEND(" + JSON.stringify(l) + ", " + JSON.stringify(l1) + ")");
l = l.concat(l1);
assertEqual(l, actual[0]);
assertEqual(1500, actual[0].length);
actual = getQueryResults("RETURN APPEND(" + JSON.stringify(l) + ", " + JSON.stringify(l1) + ", true)");
assertEqual(l, actual[0]);
assertEqual(1500, actual[0].length);
},
////////////////////////////////////////////////////////////////////////////////
/// @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, [ ])");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test removeValues 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" ] ] ]
];
data.forEach(function (d) {
var actual = getQueryResults("RETURN REMOVE_VALUES(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @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)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test removeValue 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] ] ]
];
data.forEach(function (d) {
var actual = getQueryResults("RETURN REMOVE_VALUE(" + d[1].map(function (v) { return JSON.stringify(v); }).join(", ") + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @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)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test removeNth 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", "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" ], -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(", ") + ")");
assertEqual(d[0], actual[0], d);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @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)");
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsunity.run(ahuacatlListTestSuite);
return jsunity.done();
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -32,7 +32,6 @@ var errors = internal.errors;
var jsunity = require("jsunity"); var jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper"); var helper = require("org/arangodb/aql-helper");
var getQueryResults = helper.getQueryResults; var getQueryResults = helper.getQueryResults;
var getQueryResults = helper.getQueryResults;
var assertQueryError = helper.assertQueryError; var assertQueryError = helper.assertQueryError;
var assertQueryWarningAndNull = helper.assertQueryWarningAndNull; var assertQueryWarningAndNull = helper.assertQueryWarningAndNull;

View File

@ -218,6 +218,7 @@ ERROR_QUERY_MODIFY_IN_SUBQUERY,1574,"modify operation in subquery", "Will be rai
ERROR_QUERY_COMPILE_TIME_OPTIONS,1575,"query options must be readable at query compile time", "Will be raised when an AQL data-modification query contains options that cannot be figured out at query compile time." ERROR_QUERY_COMPILE_TIME_OPTIONS,1575,"query options must be readable at query compile time", "Will be raised when an AQL data-modification query contains options that cannot be figured out at query compile time."
ERROR_QUERY_EXCEPTION_OPTIONS,1576,"query options expected", "Will be raised when an AQL data-modification query contains an invalid options specification." ERROR_QUERY_EXCEPTION_OPTIONS,1576,"query options expected", "Will be raised when an AQL data-modification query contains an invalid options specification."
ERROR_QUERY_COLLECTION_USED_IN_EXPRESSION,1577,"collection '%s' used as expression operand", "Will be raised when a collection is used as an operand in an AQL expression." ERROR_QUERY_COLLECTION_USED_IN_EXPRESSION,1577,"collection '%s' used as expression operand", "Will be raised when a collection is used as an operand in an AQL expression."
ERROR_QUERY_DISALLOWED_DYNAMIC_CALL,1578,"disallowed dynamic call to '%s'", "Will be raised when a dynamic function call is made to a function that cannot be called dynamically."
################################################################################ ################################################################################
## AQL user functions ## AQL user functions

View File

@ -173,6 +173,7 @@ void TRI_InitialiseErrorMessages () {
REG_ERROR(ERROR_QUERY_COMPILE_TIME_OPTIONS, "query options must be readable at query compile time"); REG_ERROR(ERROR_QUERY_COMPILE_TIME_OPTIONS, "query options must be readable at query compile time");
REG_ERROR(ERROR_QUERY_EXCEPTION_OPTIONS, "query options expected"); REG_ERROR(ERROR_QUERY_EXCEPTION_OPTIONS, "query options expected");
REG_ERROR(ERROR_QUERY_COLLECTION_USED_IN_EXPRESSION, "collection '%s' used as expression operand"); REG_ERROR(ERROR_QUERY_COLLECTION_USED_IN_EXPRESSION, "collection '%s' used as expression operand");
REG_ERROR(ERROR_QUERY_DISALLOWED_DYNAMIC_CALL, "disallowed dynamic call to '%s'");
REG_ERROR(ERROR_QUERY_FUNCTION_INVALID_NAME, "invalid user function name"); REG_ERROR(ERROR_QUERY_FUNCTION_INVALID_NAME, "invalid user function name");
REG_ERROR(ERROR_QUERY_FUNCTION_INVALID_CODE, "invalid user function code"); REG_ERROR(ERROR_QUERY_FUNCTION_INVALID_CODE, "invalid user function code");
REG_ERROR(ERROR_QUERY_FUNCTION_NOT_FOUND, "user function '%s()' not found"); REG_ERROR(ERROR_QUERY_FUNCTION_NOT_FOUND, "user function '%s()' not found");

View File

@ -427,6 +427,9 @@
/// - 1577: @LIT{collection '\%s' used as expression operand} /// - 1577: @LIT{collection '\%s' used as expression operand}
/// "Will be raised when a collection is used as an operand in an AQL /// "Will be raised when a collection is used as an operand in an AQL
/// expression." /// expression."
/// - 1578: @LIT{disallowed dynamic call to '\%s'}
/// "Will be raised when a dynamic function call is made to a function that
/// cannot be called dynamically."
/// - 1580: @LIT{invalid user function name} /// - 1580: @LIT{invalid user function name}
/// Will be raised when a user function with an invalid name is registered. /// Will be raised when a user function with an invalid name is registered.
/// - 1581: @LIT{invalid user function code} /// - 1581: @LIT{invalid user function code}
@ -2352,6 +2355,17 @@ void TRI_InitialiseErrorMessages ();
#define TRI_ERROR_QUERY_COLLECTION_USED_IN_EXPRESSION (1577) #define TRI_ERROR_QUERY_COLLECTION_USED_IN_EXPRESSION (1577)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1578: ERROR_QUERY_DISALLOWED_DYNAMIC_CALL
///
/// disallowed dynamic call to '%s'
///
/// "Will be raised when a dynamic function call is made to a function that
/// cannot be called dynamically."
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_QUERY_DISALLOWED_DYNAMIC_CALL (1578)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief 1580: ERROR_QUERY_FUNCTION_INVALID_NAME /// @brief 1580: ERROR_QUERY_FUNCTION_INVALID_NAME
/// ///