mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'aql-functions' of https://github.com/triAGENS/ArangoDB into devel
This commit is contained in:
commit
5f453b80e5
|
@ -1,6 +1,11 @@
|
|||
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)
|
||||
-------------------
|
||||
|
|
|
@ -173,6 +173,85 @@ AQL supports the following functions to operate on list values:
|
|||
|
||||
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.
|
||||
*FOR*, *SORT*, *LIMIT*, *COLLECT*) to operate on lists.
|
||||
|
|
|
@ -66,3 +66,17 @@ function categories:
|
|||
as in the index.
|
||||
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 ])
|
||||
|
||||
|
|
|
@ -533,6 +533,7 @@ unittests-shell-server-ahuacatl:
|
|||
|
||||
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-call-apply.js \
|
||||
@top_srcdir@/js/server/tests/aql-complex.js \
|
||||
@top_srcdir@/js/server/tests/aql-cross.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-functions.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-numeric.js \
|
||||
@top_srcdir@/js/server/tests/aql-functions-string.js \
|
||||
|
|
|
@ -155,6 +155,17 @@ std::unordered_map<std::string, Function const> const Executor::FunctionNames{
|
|||
{ "LAST", Function("LAST", "AQL_LAST", "l", true, false, true) },
|
||||
{ "NTH", Function("NTH", "AQL_NTH", "l,n", 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
|
||||
{ "HAS", Function("HAS", "AQL_HAS", "az,s", true, false, true) },
|
||||
|
|
|
@ -177,7 +177,7 @@ namespace triagens {
|
|||
/// @brief maximum number of function arguments that can be used
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static size_t const MaxArguments = 1024;
|
||||
static size_t const MaxArguments = 65536;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -177,6 +177,7 @@
|
|||
"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_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_CODE" : { "code" : 1581, "message" : "invalid user function code" },
|
||||
"ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function '%s()' not found" },
|
||||
|
|
|
@ -177,6 +177,7 @@
|
|||
"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_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_CODE" : { "code" : 1581, "message" : "invalid user function code" },
|
||||
"ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function '%s()' not found" },
|
||||
|
|
|
@ -544,8 +544,7 @@ function FCALL_USER (name, parameters) {
|
|||
|
||||
if (UserFunctions[prefix].hasOwnProperty(name)) {
|
||||
try {
|
||||
var result = UserFunctions[prefix][name].func.apply(null, parameters);
|
||||
return FIX_VALUE(result);
|
||||
return FIX_VALUE(UserFunctions[prefix][name].func.apply(null, parameters));
|
||||
}
|
||||
catch (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));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2525,6 +2594,323 @@ function AQL_UNION_DISTINCT () {
|
|||
|
||||
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
|
||||
|
@ -7148,6 +7534,16 @@ exports.AQL_RANGE = AQL_RANGE;
|
|||
exports.AQL_UNIQUE = AQL_UNIQUE;
|
||||
exports.AQL_UNION = AQL_UNION;
|
||||
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_MINUS = AQL_MINUS;
|
||||
exports.AQL_INTERSECTION = AQL_INTERSECTION;
|
||||
|
|
|
@ -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:
|
|
@ -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:
|
|
@ -32,7 +32,6 @@ var errors = internal.errors;
|
|||
var jsunity = require("jsunity");
|
||||
var helper = require("org/arangodb/aql-helper");
|
||||
var getQueryResults = helper.getQueryResults;
|
||||
var getQueryResults = helper.getQueryResults;
|
||||
var assertQueryError = helper.assertQueryError;
|
||||
var assertQueryWarningAndNull = helper.assertQueryWarningAndNull;
|
||||
|
||||
|
|
|
@ -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_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_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
|
||||
|
|
|
@ -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_EXCEPTION_OPTIONS, "query options expected");
|
||||
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_CODE, "invalid user function code");
|
||||
REG_ERROR(ERROR_QUERY_FUNCTION_NOT_FOUND, "user function '%s()' not found");
|
||||
|
|
|
@ -427,6 +427,9 @@
|
|||
/// - 1577: @LIT{collection '\%s' used as expression operand}
|
||||
/// "Will be raised when a collection is used as an operand in an AQL
|
||||
/// 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}
|
||||
/// Will be raised when a user function with an invalid name is registered.
|
||||
/// - 1581: @LIT{invalid user function code}
|
||||
|
@ -2352,6 +2355,17 @@ void TRI_InitialiseErrorMessages ();
|
|||
|
||||
#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
|
||||
///
|
||||
|
|
Loading…
Reference in New Issue