1
0
Fork 0

added AQL TRANSLATE function

This commit is contained in:
Jan Steemann 2014-06-13 19:53:43 +02:00
parent 85b92dbf21
commit 34389a10d3
5 changed files with 159 additions and 72 deletions

View File

@ -1,6 +1,13 @@
v2.2.0 (XXXX-XX-XX)
-------------------
* added AQL TRANSLATE function
This function can be used to perform lookups from static lists, e.g.
LET countryNames = { US: "United States", UK: "United Kingdom", FR: "France" }
RETURN TRANSLATE("FR", countryNames)
* fixed check-version for empty directory
* moved try/catch block to the top of routing chain

View File

@ -40,11 +40,6 @@
// --SECTION-- private macros
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief shorthand to register a query function and process the result
////////////////////////////////////////////////////////////////////////////////
@ -62,19 +57,10 @@
return false; \
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private types
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief parameter type holder
////////////////////////////////////////////////////////////////////////////////
@ -91,19 +77,10 @@ typedef struct param_s {
}
param_t;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief return a param_t structure with all bits set to 0
////////////////////////////////////////////////////////////////////////////////
@ -356,19 +333,10 @@ static bool EqualName (TRI_associative_pointer_t* array,
function->_externalName);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- optimiser callbacks
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief check if we have a matching restriction we can use to optimise
/// a PATHS query
@ -554,11 +522,13 @@ static void OptimisePaths (const TRI_aql_node_t* const fcallNode,
// add min and max values to the function call argument list
argNode = TRI_CreateNodeValueIntAql(context, useMin ? (int64_t) minValue : (int64_t) 0);
if (argNode) {
// min value node
TRI_PushBackVectorPointer(&args->_members, (void*) argNode);
argNode = TRI_CreateNodeValueIntAql(context, useMax ? (int64_t) maxValue : (int64_t) (1024 * 1024));
if (argNode) {
// max value node
TRI_PushBackVectorPointer(&args->_members, (void*) argNode);
@ -568,19 +538,10 @@ static void OptimisePaths (const TRI_aql_node_t* const fcallNode,
}
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief initialise the array with the function declarations
////////////////////////////////////////////////////////////////////////////////
@ -694,6 +655,7 @@ TRI_associative_pointer_t* TRI_CreateFunctionsAql (void) {
REGISTER_FUNCTION("MATCHES", "MATCHES", true, false, ".,l|b", NULL);
REGISTER_FUNCTION("UNSET", "UNSET", true, false, "a,sl|+", NULL);
REGISTER_FUNCTION("KEEP", "KEEP", true, false, "a,sl|+", NULL);
REGISTER_FUNCTION("TRANSLATE", "TRANSLATE", true, false, ".,a|.", NULL);
// geo functions
REGISTER_FUNCTION("NEAR", "GEO_NEAR", false, false, "h,n,n|nz,s", NULL);
@ -1059,10 +1021,6 @@ bool TRI_ValidateArgsFunctionAql (TRI_aql_context_t* const context,
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"

View File

@ -44,11 +44,6 @@ struct TRI_associative_pointer_s;
// --SECTION-- public defines
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief default namespace for aql functions
////////////////////////////////////////////////////////////////////////////////
@ -73,19 +68,10 @@ struct TRI_associative_pointer_s;
#define TRI_AQL_DEFAULT_PREFIX TRI_AQL_DEFAULT_NAMESPACE TRI_AQL_NAMESPACE_SEPARATOR
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief query function data structure
////////////////////////////////////////////////////////////////////////////////
@ -102,19 +88,10 @@ typedef struct TRI_aql_function_s {
}
TRI_aql_function_t;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief initialise the array with the function declarations
////////////////////////////////////////////////////////////////////////////////
@ -167,10 +144,6 @@ bool TRI_ValidateArgsFunctionAql (struct TRI_aql_context_s* const,
const TRI_aql_function_t* const,
const TRI_aql_node_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
#endif
// Local Variables:

View File

@ -3770,6 +3770,29 @@ function MERGE_RECURSIVE () {
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief translate a value, using a lookup document
////////////////////////////////////////////////////////////////////////////////
function TRANSLATE (value, lookup, defaultValue) {
"use strict";
if (defaultValue === undefined) {
defaultValue = value;
}
if (TYPEWEIGHT(lookup) !== TYPEWEIGHT_DOCUMENT) {
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "TRANSLATE");
}
var key = String(value);
if (lookup.hasOwnProperty(key)) {
return lookup[key];
}
return defaultValue;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief compare an object against a list of examples and return whether the
/// object matches any of the examples. returns the example index or a bool,
@ -7060,6 +7083,7 @@ exports.UNSET = UNSET;
exports.KEEP = KEEP;
exports.MERGE = MERGE;
exports.MERGE_RECURSIVE = MERGE_RECURSIVE;
exports.TRANSLATE = TRANSLATE;
exports.MATCHES = MATCHES;
exports.PASSTHRU = PASSTHRU;
exports.SLEEP = SLEEP;

View File

@ -1561,6 +1561,131 @@ function ahuacatlFunctionsTestSuite () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN MERGE_RECURSIVE({ }, { }, [ ])");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test translate function
////////////////////////////////////////////////////////////////////////////////
testTranslate1 : function () {
var tests = [
{ value: "foo", lookup: { }, expected: "foo" },
{ value: "foo", lookup: { foo: "bar" }, expected: "bar" },
{ value: "foo", lookup: { bar: "foo" }, expected: "foo" },
{ value: 1, lookup: { 1: "one", 2: "two" }, expected: "one" },
{ value: 1, lookup: { "1": "one", "2": "two" }, expected: "one" },
{ value: "1", lookup: { 1: "one", 2: "two" }, expected: "one" },
{ value: "1", lookup: { "1": "one", "2": "two" }, expected: "one" },
{ value: null, lookup: { foo: "bar", bar: "foo" }, expected: null },
{ value: "foobar", lookup: { foo: "bar", bar: "foo" }, expected: "foobar" },
{ value: "foobaz", lookup: { foobar: "bar", foobaz: "replaced!" }, expected: "replaced!" },
{ value: "foobaz", lookup: { foobar: "bar", foobaz: null }, expected: null },
{ value: "foobaz", lookup: { foobar: "bar", foobaz: [ 1, 2, 3 ] }, expected: [ 1, 2, 3 ] },
{ value: "foobaz", lookup: { foobar: "bar", foobaz: { thefoxx: "is great" } }, expected: { thefoxx: "is great" } },
{ value: "one", lookup: { one: "two", two: "three", three: "four" }, expected: "two" },
{ value: null, lookup: { "foo": "one", " ": "bar", "empty": 3 }, expected: null },
{ value: false, lookup: { "foo": "one", " ": "bar", "empty": 3 }, expected: false },
{ value: 0, lookup: { "foo": "one", " ": "bar", "empty": 3 }, expected: 0 },
{ value: "", lookup: { "foo": "one", " ": "bar", "empty": 3 }, expected: "" },
{ value: "CGN", lookup: { "DUS" : "Duessldorf", "FRA" : "Frankfurt", "CGN" : "Cologne" }, expected: "Cologne" }
];
tests.forEach(function(t) {
var actual = getQueryResults("RETURN TRANSLATE(@value, @lookup)", { value: t.value, lookup: t.lookup });
assertEqual(t.expected, actual[0]);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test translate function
////////////////////////////////////////////////////////////////////////////////
testTranslate2 : function () {
var i, lookup = { };
for (i = 0; i < 100; ++i) {
lookup["test" + i] = "the quick brown Foxx:" + i;
}
for (i = 0; i < 100; ++i) {
var actual = getQueryResults("RETURN TRANSLATE(@value, @lookup)", { value: "test" + i, lookup: lookup });
assertEqual(lookup["test" + i], actual[0]);
assertEqual("the quick brown Foxx:" + i, actual[0]);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test translate function
////////////////////////////////////////////////////////////////////////////////
testTranslate3 : function () {
var i, lookup = { };
for (i = 0; i < 100; ++i) {
lookup[i] = i * i;
}
for (i = 0; i < 100; ++i) {
var actual = getQueryResults("RETURN TRANSLATE(@value, @lookup, @def)", { value: i, lookup: lookup, def: "fail!" });
assertEqual(lookup[i], actual[0]);
assertEqual(i * i, actual[0]);
actual = getQueryResults("RETURN TRANSLATE(@value, @lookup, @def)", { value: "test" + i, lookup: lookup, def: "fail" + i });
assertEqual("fail" + i, actual[0]);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test translate function
////////////////////////////////////////////////////////////////////////////////
testTranslateDefault : function () {
var tests = [
{ value: "foo", lookup: { }, expected: "bar", def: "bar" },
{ value: "foo", lookup: { foo: "bar" }, expected: "bar", def: "lol" },
{ value: "foo", lookup: { bar: "foo" }, expected: "lol", def: "lol" },
{ value: 1, lookup: { 1: "one", 2: "two" }, expected: "one", def: "foobar" },
{ value: 1, lookup: { "1": "one", "2": "two" }, expected: "one", def: "test" },
{ value: 1, lookup: { "3": "one", "2": "two" }, expected: "test", def: "test" },
{ value: "1", lookup: { 1: "one", 2: "two" }, expected: "one", def: "test" },
{ value: "1", lookup: { 3: "one", 2: "two" }, expected: "test", def: "test" },
{ value: "1", lookup: { "1": "one", "2": "two" }, expected: "one", def: "test" },
{ value: "1", lookup: { "3": "one", "2": "two" }, expected: "test", def: "test" },
{ value: null, lookup: { foo: "bar", bar: "foo" }, expected: 1, def: 1 },
{ value: null, lookup: { foo: "bar", bar: "foo" }, expected: "foobar", def: "foobar" },
{ value: "foobar", lookup: { foo: "bar", bar: "foo" }, expected: "foobart", def: "foobart" },
{ value: "foobaz", lookup: { foobar: "bar", foobaz: "replaced!" }, expected: "replaced!", def: "foobart" },
{ value: "foobaz", lookup: { foobar: "bar", foobaz: null }, expected: null, def: "foobaz" },
{ value: "foobaz", lookup: { foobar: "bar", foobaz: [ 1, 2, 3 ] }, expected: [ 1, 2, 3 ], def: null },
{ value: "foobaz", lookup: { foobar: "bar" }, expected: null, def: null },
{ value: "foobaz", lookup: { }, expected: "FOXX", def: "FOXX" },
{ value: "foobaz", lookup: { foobar: "bar", foobaz: { thefoxx: "is great" } }, expected: { thefoxx: "is great" }, def: null },
{ value: "one", lookup: { one: "two", two: "three", three: "four" }, expected: "two", def: "foo" },
{ value: null, lookup: { "foo": "one", " ": "bar", "empty": 3 }, expected: "bla", def: "bla" },
{ value: false, lookup: { "foo": "one", " ": "bar", "empty": 3 }, expected: true, def: true },
{ value: 0, lookup: { "foo": "one", " ": "bar", "empty": 3 }, expected: 42, def: 42 },
{ value: "", lookup: { "foo": "one", " ": "bar", "empty": 3 }, expected: "three", def: "three" },
{ value: "CGN", lookup: { "DUS" : "Duessldorf", "FRA" : "Frankfurt", "MUC" : "Munich" }, expected: "Cologne", def: "Cologne" }
];
tests.forEach(function(t) {
var actual = getQueryResults("RETURN TRANSLATE(@value, @lookup, @def)", { value: t.value, lookup: t.lookup, def: t.def });
assertEqual(t.expected, actual[0]);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test merge_recursive function
////////////////////////////////////////////////////////////////////////////////
testTranslateInvalid : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN TRANSLATE()");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN TRANSLATE('foo')");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN TRANSLATE('foo', { }, '', 'baz')");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN TRANSLATE({ }, 'foo')");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN TRANSLATE('', null)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN TRANSLATE('', true)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN TRANSLATE('', 1)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN TRANSLATE('', '')");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN TRANSLATE('', [])");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test union function
////////////////////////////////////////////////////////////////////////////////