From 14c3863a17d883e7060acc6a1a704dc92aab2de9 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Thu, 28 Feb 2013 09:38:03 +0100 Subject: [PATCH] added tests for LEFT(), RIGHT() --- CHANGELOG | 7 +- arangod/Ahuacatl/ahuacatl-functions.c | 11 +- js/server/modules/org/arangodb/ahuacatl.js | 288 +++++++++++++++++++-- js/server/tests/ahuacatl-functions.js | 75 +++++- 4 files changed, 352 insertions(+), 29 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8e074a1059..4a6a961441 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,14 @@ v1.3 (XXXX-XX-XX) ----------------- +* added AQL functions VARIANCE_POPULATION(), VARIANCE_SAMPLE(), STDDEV_POPULATION(), + STDDEV_SAMPLE(), AVERAGE(), MEDIAN() to calculate stastical values for lists + +* added AQL LEFT() and RIGHT() string functions + * fixed issue #436: GET /_api/document on edge -* make AQL REVERSE() function work on strings, too +* make AQL REVERSE() and LENGTH() functions work on strings, too * disabled DOT generation in `make doxygen`. this speeds up docs generation diff --git a/arangod/Ahuacatl/ahuacatl-functions.c b/arangod/Ahuacatl/ahuacatl-functions.c index f0cc66595f..b0249524c9 100644 --- a/arangod/Ahuacatl/ahuacatl-functions.c +++ b/arangod/Ahuacatl/ahuacatl-functions.c @@ -599,6 +599,8 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) { REGISTER_FUNCTION("SUBSTRING", "STRING_SUBSTRING", true, false, "s,n|n", NULL); REGISTER_FUNCTION("CONTAINS", "STRING_CONTAINS", true, false, "s,s|b", NULL); REGISTER_FUNCTION("LIKE", "STRING_LIKE", true, false, "s,r|b", NULL); + REGISTER_FUNCTION("LEFT", "STRING_LEFT", true, false, "s,n", NULL); + REGISTER_FUNCTION("RIGHT", "STRING_RIGHT", true, false, "s,n", NULL); // numeric functions REGISTER_FUNCTION("FLOOR", "NUMBER_FLOOR", true, false, "n", NULL); @@ -606,13 +608,20 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) { REGISTER_FUNCTION("ROUND", "NUMBER_ROUND", true, false, "n", NULL); REGISTER_FUNCTION("ABS", "NUMBER_ABS", true, false, "n", NULL); REGISTER_FUNCTION("RAND", "NUMBER_RAND", false, false, "", NULL); + REGISTER_FUNCTION("SQRT", "NUMBER_SQRT", true, false, "n", NULL); // list functions REGISTER_FUNCTION("UNION", "UNION", true, false, "l,l|+", NULL); - REGISTER_FUNCTION("LENGTH", "LENGTH", true, true, "la", NULL); + REGISTER_FUNCTION("LENGTH", "LENGTH", true, true, "las", NULL); REGISTER_FUNCTION("MIN", "MIN", true, true, "l", NULL); REGISTER_FUNCTION("MAX", "MAX", true, true, "l", NULL); REGISTER_FUNCTION("SUM", "SUM", true, true, "l", NULL); + REGISTER_FUNCTION("MEDIAN", "MEDIAN", true, true, "l", NULL); + REGISTER_FUNCTION("AVERAGE", "AVERAGE", true, true, "l", NULL); + REGISTER_FUNCTION("VARIANCE_SAMPLE", "VARIANCE_SAMPLE", true, true, "l", NULL); + REGISTER_FUNCTION("VARIANCE_POPULATION", "VARIANCE_POPULATION", true, true, "l", NULL); + REGISTER_FUNCTION("STDDEV_SAMPLE", "STDDEV_SAMPLE", true, true, "l", NULL); + REGISTER_FUNCTION("STDDEV_POPULATION", "STDDEV_POPULATION", true, true, "l", NULL); REGISTER_FUNCTION("UNIQUE", "UNIQUE", true, false, "l", NULL); // note: REVERSE() can be applied on strings, too REGISTER_FUNCTION("REVERSE", "REVERSE", true, false, "ls", NULL); diff --git a/js/server/modules/org/arangodb/ahuacatl.js b/js/server/modules/org/arangodb/ahuacatl.js index 44182f595f..c4736b183d 100644 --- a/js/server/modules/org/arangodb/ahuacatl.js +++ b/js/server/modules/org/arangodb/ahuacatl.js @@ -28,6 +28,8 @@ /// @author Copyright 2012, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// +"use strict"; + var INTERNAL = require("internal"); var TRAVERSAL = require("org/arangodb/graph/traversal"); var ArangoError = require("org/arangodb/arango-error").ArangoError; @@ -256,6 +258,7 @@ function COMPILE_REGEX (regex, modifiers) { var i, n = regex.length; var escaped = false; var pattern = ''; + var specialChar = /^([.*+?\^=!:${}()|\[\]\/\\])$/; ARG_CHECK(regex, TYPEWEIGHT_STRING, "LIKE"); @@ -290,7 +293,7 @@ function COMPILE_REGEX (regex, modifiers) { pattern += '.'; } } - else if (c.match(/^([.*+?\^=!:${}()|\[\]\/\\])$/)) { + else if (c.match(specialChar)) { // character with special meaning in a regex pattern += '\\' + c; } @@ -1627,6 +1630,50 @@ function STRING_LIKE (value, regex, caseInsensitive) { } } +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns the leftmost parts of a string +//////////////////////////////////////////////////////////////////////////////// + +function STRING_LEFT (value, length) { + ARG_CHECK(value, TYPEWEIGHT_STRING, "LEFT"); + ARG_CHECK(length, TYPEWEIGHT_NUMBER, "LEFT"); + + if (length < 0) { + THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "LEFT"); + ARG_CHECK(length, TYPEWEIGHT_NUMBER, "LEFT"); + } + length = parseInt(length, 10); + if (length === 0) { + return ""; + } + + return value.substr(0, length); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns the rightmost parts of a string +//////////////////////////////////////////////////////////////////////////////// + +function STRING_RIGHT (value, length) { + ARG_CHECK(value, TYPEWEIGHT_STRING, "RIGHT"); + ARG_CHECK(length, TYPEWEIGHT_NUMBER, "RIGHT"); + + if (length < 0) { + THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "RIGHT"); + ARG_CHECK(length, TYPEWEIGHT_NUMBER, "RIGHT"); + } + length = parseInt(length, 10); + if (length === 0) { + return ""; + } + + var len = value.length; + if (length > len) { + length = len; + } + return value.substr(value.length - length, length); +} + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// @@ -1822,7 +1869,7 @@ function NUMBER_FLOOR (value) { THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "FLOOR"); } - return Math.floor(value); + return NUMERIC_VALUE(Math.floor(value)); } //////////////////////////////////////////////////////////////////////////////// @@ -1834,7 +1881,7 @@ function NUMBER_CEIL (value) { THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "CEIL"); } - return Math.ceil(value); + return NUMERIC_VALUE(Math.ceil(value)); } //////////////////////////////////////////////////////////////////////////////// @@ -1846,7 +1893,7 @@ function NUMBER_ROUND (value) { THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "ROUND"); } - return Math.round(value); + return NUMERIC_VALUE(Math.round(value)); } //////////////////////////////////////////////////////////////////////////////// @@ -1858,7 +1905,7 @@ function NUMBER_ABS (value) { THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "ABS"); } - return Math.abs(value); + return NUMERIC_VALUE(Math.abs(value)); } //////////////////////////////////////////////////////////////////////////////// @@ -1869,6 +1916,22 @@ function NUMBER_RAND () { return Math.random(); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief square root +//////////////////////////////////////////////////////////////////////////////// + +function NUMBER_SQRT (value) { + if (TYPEWEIGHT(value) === TYPEWEIGHT_NULL) { + return null; + } + + if (! IS_NUMBER(value)) { + THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "SQRT"); + } + + return NUMERIC_VALUE(Math.sqrt(value)); +} + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// @@ -1970,16 +2033,16 @@ function LIMIT (value, offset, count) { //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -/// @brief get the length of a list +/// @brief get the length of a list, document or string //////////////////////////////////////////////////////////////////////////////// function LENGTH (value) { - var result; - - if (TYPEWEIGHT(value) === TYPEWEIGHT_LIST) { + var result, typeWeight = TYPEWEIGHT(value); + + if (typeWeight === TYPEWEIGHT_LIST || typeWeight === TYPEWEIGHT_STRING) { result = value.length; } - else if (TYPEWEIGHT(value) === TYPEWEIGHT_DOCUMENT) { + else if (typeWeight === TYPEWEIGHT_DOCUMENT) { result = KEYS(value, false).length; } else { @@ -2044,6 +2107,7 @@ function UNIQUE (values) { var normalized = NORMALIZE(value); keys[JSON.stringify(normalized)] = normalized; }); + for (a in keys) { if (keys.hasOwnProperty(a)) { result.push(keys[a]); @@ -2084,17 +2148,19 @@ function UNION () { //////////////////////////////////////////////////////////////////////////////// function MAX (values) { - var result = null; - LIST(values); - values.forEach(function (value) { - if (TYPEWEIGHT(value) !== TYPEWEIGHT_NULL) { + var value, result = null; + var i, n; + + for (i = 0, n = values.length; i < n; ++i) { + value = values[i]; + if (TYPEWEIGHT(value) !== TYPEWEIGHT_NULL) { if (result === null || RELATIONAL_GREATER(value, result)) { result = value; } } - }); + } return result; } @@ -2104,17 +2170,19 @@ function MAX (values) { //////////////////////////////////////////////////////////////////////////////// function MIN (values) { - var result = null; - LIST(values); + + var value, result = null; + var i, n; - values.forEach(function (value) { - if (TYPEWEIGHT(value) !== TYPEWEIGHT_NULL) { + for (i = 0, n = values.length; i < n; ++i) { + value = values[i]; + if (TYPEWEIGHT(value) !== TYPEWEIGHT_NULL) { if (result === null || RELATIONAL_LESS(value, result)) { result = value; } } - }); + } return result; } @@ -2124,13 +2192,17 @@ function MIN (values) { //////////////////////////////////////////////////////////////////////////////// function SUM (values) { - var result = null; - LIST(values); - values.forEach(function (value) { - if (TYPEWEIGHT(value) !== TYPEWEIGHT_NULL) { - if (TYPEWEIGHT(value) !== TYPEWEIGHT_NUMBER) { + var i, n; + var value, typeWeight, result = null; + + for (i = 0, n = values.length; i < n; ++i) { + value = values[i]; + typeWeight = TYPEWEIGHT(value); + + if (typeWeight !== TYPEWEIGHT_NULL) { + if (typeWeight !== TYPEWEIGHT_NUMBER) { THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "SUM"); } @@ -2141,11 +2213,166 @@ function SUM (values) { result += value; } } - }); + } return NUMERIC_VALUE(result); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief average of all values +//////////////////////////////////////////////////////////////////////////////// + +function AVERAGE (values) { + LIST(values); + + var current, typeWeight, sum = 0; + var i, j, n; + + for (i = 0, j = 0, n = values.length; i < n; ++i) { + current = values[i]; + typeWeight = TYPEWEIGHT(current); + + if (typeWeight !== TYPEWEIGHT_NULL) { + if (typeWeight !== TYPEWEIGHT_NUMBER) { + THROW(INTERNAL.errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE); + } + + sum += current; + j++; + } + } + + if (j === 0) { + return null; + } + + return NUMERIC_VALUE(sum / j); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief median of all values +//////////////////////////////////////////////////////////////////////////////// + +function MEDIAN (values) { + LIST(values); + + var copy = [ ], current, typeWeight; + var i, n; + + for (i = 0, n = values.length; i < n; ++i) { + current = values[i]; + typeWeight = TYPEWEIGHT(current); + + if (typeWeight !== TYPEWEIGHT_NULL) { + if (typeWeight !== TYPEWEIGHT_NUMBER) { + THROW(INTERNAL.errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE); + } + + copy.push(current); + } + } + + if (copy.length === 0) { + return null; + } + + copy.sort(RELATIONAL_CMP); + + var midpoint = copy.length / 2; + if (copy.length % 2 === 0) { + return NUMERIC_VALUE((copy[midpoint - 1] + copy[midpoint]) / 2); + } + + return NUMERIC_VALUE(copy[Math.floor(midpoint)]); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief variance of all values +//////////////////////////////////////////////////////////////////////////////// + +function VARIANCE (values) { + LIST(values); + + var mean = 0, m2 = 0, current, typeWeight, delta; + var i, j, n; + + for (i = 0, j = 0, n = values.length; i < n; ++i) { + current = values[i]; + typeWeight = TYPEWEIGHT(current); + + if (typeWeight !== TYPEWEIGHT_NULL) { + if (typeWeight !== TYPEWEIGHT_NUMBER) { + THROW(INTERNAL.errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE); + } + + delta = current - mean; + mean += delta / ++j; + m2 += delta * (current - mean); + } + } + + return { + n: j, + value: m2 + }; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief sample variance of all values +//////////////////////////////////////////////////////////////////////////////// + +function VARIANCE_SAMPLE (values) { + var result = VARIANCE(values); + + if (result.n < 2) { + return null; + } + + return NUMERIC_VALUE(result.value / (result.n - 1)); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief population variance of all values +//////////////////////////////////////////////////////////////////////////////// + +function VARIANCE_POPULATION (values) { + var result = VARIANCE(values); + + if (result.n < 1) { + return null; + } + + return NUMERIC_VALUE(result.value / result.n); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief standard deviation of all values +//////////////////////////////////////////////////////////////////////////////// + +function STDDEV_SAMPLE (values) { + var result = VARIANCE(values); + + if (result.n < 2) { + return null; + } + + return NUMERIC_VALUE(Math.sqrt(result.value / (result.n - 1))); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief standard deviation of all values +//////////////////////////////////////////////////////////////////////////////// + +function STDDEV_POPULATION (values) { + var result = VARIANCE(values); + + if (result.n < 1) { + return null; + } + + return NUMERIC_VALUE(Math.sqrt(result.value / result.n)); +} + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// @@ -3021,6 +3248,8 @@ exports.STRING_UPPER = STRING_UPPER; exports.STRING_SUBSTRING = STRING_SUBSTRING; exports.STRING_CONTAINS = STRING_CONTAINS; exports.STRING_LIKE = STRING_LIKE; +exports.STRING_LEFT = STRING_LEFT; +exports.STRING_RIGHT = STRING_RIGHT; exports.CAST_BOOL = CAST_BOOL; exports.CAST_NUMBER = CAST_NUMBER; exports.CAST_STRING = CAST_STRING; @@ -3036,6 +3265,7 @@ exports.NUMBER_CEIL = NUMBER_CEIL; exports.NUMBER_ROUND = NUMBER_ROUND; exports.NUMBER_ABS = NUMBER_ABS; exports.NUMBER_RAND = NUMBER_RAND; +exports.NUMBER_SQRT = NUMBER_SQRT; exports.SORT = SORT; exports.GROUP = GROUP; exports.LIMIT = LIMIT; @@ -3048,6 +3278,12 @@ exports.UNION = UNION; exports.MAX = MAX; exports.MIN = MIN; exports.SUM = SUM; +exports.AVERAGE = AVERAGE; +exports.MEDIAN = MEDIAN; +exports.VARIANCE_SAMPLE = VARIANCE_SAMPLE; +exports.VARIANCE_POPULATION = VARIANCE_POPULATION; +exports.STDDEV_SAMPLE = STDDEV_SAMPLE; +exports.STDDEV_POPULATION = STDDEV_POPULATION; exports.GEO_NEAR = GEO_NEAR; exports.GEO_WITHIN = GEO_WITHIN; exports.FULLTEXT = FULLTEXT; diff --git a/js/server/tests/ahuacatl-functions.js b/js/server/tests/ahuacatl-functions.js index ae9df1988b..9f544ef5d9 100644 --- a/js/server/tests/ahuacatl-functions.js +++ b/js/server/tests/ahuacatl-functions.js @@ -493,6 +493,70 @@ function ahuacatlFunctionsTestSuite () { assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN UNIQUE({ })"); } )); }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test left function +//////////////////////////////////////////////////////////////////////////////// + + testLeft : function () { + var expected = [ 'fo', 'f', '', 'foo', 'foo', '', '', '', 'mö', 'mötö' ]; + var actual = getQueryResults("FOR t IN [ [ 'foo', 2 ], [ 'foo', 1 ], [ 'foo', 0 ], [ 'foo', 4 ], [ 'foo', 999999999 ], [ '', 0 ], [ '', 1 ], [ '', 2 ], [ 'mötör', 2 ], [ 'mötör', 4 ] ] RETURN LEFT(t[0], t[1])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test left function +//////////////////////////////////////////////////////////////////////////////// + + testLeftInvalid : function () { + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT()"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT('foo')"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT('foo', 2, 3)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT(null, 2)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT(true, 2)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT(4, 2)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT([ ], 2)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT({ }, 2)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT('foo', null)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT('foo', true)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT('foo', 'bar')"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT('foo', [ ])"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT('foo', { })"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT('foo', -1)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LEFT('foo', -1.5)"); } )); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test right function +//////////////////////////////////////////////////////////////////////////////// + + testRight : function () { + var expected = [ 'oo', 'o', '', 'foo', 'foo', '', '', '', 'ör', 'ötör' ]; + var actual = getQueryResults("FOR t IN [ [ 'foo', 2 ], [ 'foo', 1 ], [ 'foo', 0 ], [ 'foo', 4 ], [ 'foo', 999999999 ], [ '', 0 ], [ '', 1 ], [ '', 2 ], [ 'mötör', 2 ], [ 'mötör', 4 ] ] RETURN RIGHT(t[0], t[1])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test left function +//////////////////////////////////////////////////////////////////////////////// + + testRightInvalid : function () { + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT()"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT('foo')"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT('foo', 2, 3)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT(null, 2)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT(true, 2)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT(4, 2)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT([ ], 2)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT({ }, 2)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT('foo', null)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT('foo', true)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT('foo', 'bar')"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT('foo', [ ])"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT('foo', { })"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT('foo', -1)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RIGHT('foo', -1.5)"); } )); + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test length function //////////////////////////////////////////////////////////////////////////////// @@ -523,6 +587,16 @@ function ahuacatlFunctionsTestSuite () { assertEqual(expected, actual); }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test length function for strings +//////////////////////////////////////////////////////////////////////////////// + + testLength4 : function () { + var expected = [ 0, 1, 3, 3, 4, 5 ]; + var actual = getQueryResults("FOR test IN [ '', ' ', 'foo', 'bar', 'meow', 'mötör' ] RETURN LENGTH(test)", true); + assertEqual(expected, actual); + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test length function //////////////////////////////////////////////////////////////////////////////// @@ -533,7 +607,6 @@ function ahuacatlFunctionsTestSuite () { assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LENGTH(null)"); } )); assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LENGTH(true)"); } )); assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LENGTH(4)"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN LENGTH(\"yes\")"); } )); }, ////////////////////////////////////////////////////////////////////////////////