1
0
Fork 0

added AQL functions KEEP() and UNSET()

This commit is contained in:
Jan Steemann 2013-02-14 16:14:22 +01:00
parent 3d47748434
commit 3e04acf3ee
6 changed files with 163 additions and 0 deletions

View File

@ -1,6 +1,8 @@
v1.2.alpha (XXXX-XX-XX)
-----------------------
* added AQL functions KEEP() and UNSET()
* fixed issue #348: "HTTP Interface for Administration and Monitoring"
documentation errors.

View File

@ -154,6 +154,10 @@ in ArangoDB 1.2:
* `ATTRIBUTES()`: returns the names of all attributes of a document as a list
* `KEEP()`: keeps only the specified attributes of a document, and removes all others
* `UNSET()`: removes only the specified attributes from a document, and preserves all others
* `MATCHES()`: to check if a document matches one of multiple example documents
* `LIKE()`: pattern-based text comparison

View File

@ -1032,6 +1032,20 @@ AQL supports the following functions to operate on document values:
`_key` etc.) are removed from the result. If @FA{sort} is set to `true`, then the
attribute names in the result will be sorted. Otherwise they will be returned in any order.
- @FN{UNSET(@FA{document}\, @FA{attributename}\, ...)}: removes the attributes @FA{attributename}
(can be one or many) from @FA{document}. All other attributes will be preserved.
Multiple attribute names can be specified by either passing multiple individual string argument
names, or by passing a list of attribute names:
RETURN UNSET(doc, '_id', '_key', [ 'foo', 'bar' ])
- @FN{KEEP(@FA{document}\, @FA{attributename}\, ...)}: keeps only the attributes @FA{attributename}
(can be one or many) from @FA{document}. All other attributes will be removed from the result.
Multiple attribute names can be specified by either passing multiple individual string argument
names, or by passing a list of attribute names:
RETURN KEEP(doc, 'firstname', 'name', 'likes')
@subsubsection AqlFunctionsGeo Geo functions
AQL offers the following functions to filter data based on geo indexes:

View File

@ -625,6 +625,8 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) {
REGISTER_FUNCTION("MERGE_RECURSIVE", "MERGE_RECURSIVE", true, false, "a,a|+", NULL);
REGISTER_FUNCTION("DOCUMENT", "DOCUMENT", false, false, "h,sl", NULL);
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);
// geo functions
REGISTER_FUNCTION("NEAR", "GEO_NEAR", false, false, "h,n,n,n|s", NULL);

View File

@ -354,6 +354,34 @@ function VALUES (value) {
return values;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extract key names from an argument list
////////////////////////////////////////////////////////////////////////////////
function EXTRACT_KEYS (args, startArgument, functionName) {
var keys = { }, i, j, key, key2;
for (i = startArgument; i < args.length; ++i) {
key = args[i];
if (typeof key === 'string') {
keys[key] = true;
}
else if (Array.isArray(key)) {
for (j = 0; j < key.length; ++j) {
key2 = key[j];
if (typeof key2 === 'string') {
keys[key2] = true;
}
else {
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, functionName);
}
}
}
}
return keys;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the keys of an array or object in a comparable way
////////////////////////////////////////////////////////////////////////////////
@ -2330,6 +2358,54 @@ function ATTRIBUTES (element, removeInternal, sort) {
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief unset specific attributes from a document
////////////////////////////////////////////////////////////////////////////////
function UNSET (value) {
if (TYPEWEIGHT(value) !== TYPEWEIGHT_DOCUMENT) {
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "UNSET");
}
var keys = EXTRACT_KEYS(arguments, 1, "UNSET"), i;
var result = { };
// copy over all that is left
for (i in value) {
if (value.hasOwnProperty(i)) {
if (keys[i] !== true) {
result[i] = CLONE(value[i]);
}
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief keep specific attributes from a document
////////////////////////////////////////////////////////////////////////////////
function KEEP (value) {
if (TYPEWEIGHT(value) !== TYPEWEIGHT_DOCUMENT) {
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "KEEP");
}
var keys = EXTRACT_KEYS(arguments, 1, "KEEP"), i;
// copy over all that is left
var result = { };
for (i in keys) {
if (keys.hasOwnProperty(i)) {
if (value.hasOwnProperty(i)) {
result[i] = CLONE(value[i]);
}
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief merge all arguments
////////////////////////////////////////////////////////////////////////////////
@ -2980,6 +3056,8 @@ exports.FIRST_LIST = FIRST_LIST;
exports.FIRST_DOCUMENT = FIRST_DOCUMENT;
exports.HAS = HAS;
exports.ATTRIBUTES = ATTRIBUTES;
exports.UNSET = UNSET;
exports.KEEP = KEEP;
exports.MERGE = MERGE;
exports.MERGE_RECURSIVE = MERGE_RECURSIVE;
exports.MATCHES = MATCHES;

View File

@ -913,6 +913,69 @@ function ahuacatlFunctionsTestSuite () {
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { QUERY("RETURN RAND(2)"); } ));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test keep function
////////////////////////////////////////////////////////////////////////////////
testKeepInvalid : function () {
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN KEEP({ }, 1)"); } ));
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN KEEP({ }, { })"); } ));
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN KEEP({ }, 'foo', { })"); } ));
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN KEEP('foo', 'foo')"); } ));
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { QUERY("RETURN KEEP()"); } ));
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { QUERY("RETURN KEEP({ })"); } ));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test keep function
////////////////////////////////////////////////////////////////////////////////
testKeep : function () {
var actual, expected;
actual = getQueryResults("FOR i IN [ { }, { foo: 1, bar: 2, moo: 3, goof: 4, bang: 5, meow: 6 }, { foo: 0, goof: 1, meow: 2 }, { foo: null }, { foo: true }, { goof: null } ] RETURN KEEP(i, 'foo', 'bar', 'baz', [ 'meow' ], [ ])", false);
assertEqual([ { }, { bar: 2, foo: 1, meow: 6 }, { foo: 0, meow: 2 }, { foo: null }, { foo: true }, { } ], actual);
actual = getQueryResults("FOR i IN [ { }, { foo: 1, bar: 2, moo: 3, goof: 4, bang: 5, meow: 6 }, { foo: 0, goof: 1, meow: 2 }, { foo: null }, { foo: true }, { goof: null } ] RETURN KEEP(i, [ 'foo', 'bar', 'baz', 'meow' ])", false);
assertEqual([ { }, { bar: 2, foo: 1, meow: 6 }, { foo: 0, meow: 2 }, { foo: null }, { foo: true }, { } ], actual);
actual = getQueryResults("FOR i IN [ { }, { foo: 1, bar: 2, moo: 3, goof: 4, bang: 5, meow: 6 }, { foo: 0, goof: 1, meow: 2 }, { foo: null }, { foo: true }, { goof: null } ] RETURN KEEP(i, 'foo', 'bar', 'baz', 'meow')", false);
assertEqual([ { }, { bar: 2, foo: 1, meow: 6 }, { foo: 0, meow: 2 }, { foo: null }, { foo: true }, { } ], actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test unset function
////////////////////////////////////////////////////////////////////////////////
testUnsetInvalid : function () {
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN UNSET({ }, 1)"); } ));
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN UNSET({ }, { })"); } ));
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN UNSET({ }, 'foo', { })"); } ));
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { QUERY("RETURN UNSET('foo', 'foo')"); } ));
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { QUERY("RETURN UNSET()"); } ));
assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { QUERY("RETURN UNSET({ })"); } ));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test unset function
////////////////////////////////////////////////////////////////////////////////
testUnset : function () {
var expected = [ { bang: 5, goof: 4, moo: 3 }, { goof: 1 }, { }, { }, { goof: null } ];
var actual;
actual = getQueryResults("FOR i IN [ { foo: 1, bar: 2, moo: 3, goof: 4, bang: 5, meow: 6 }, { foo: 0, goof: 1, meow: 2 }, { foo: null }, { foo: true }, { goof: null } ] RETURN UNSET(i, 'foo', 'bar', 'baz', [ 'meow' ], [ ])", false);
assertEqual(expected, actual);
actual = getQueryResults("FOR i IN [ { foo: 1, bar: 2, moo: 3, goof: 4, bang: 5, meow: 6 }, { foo: 0, goof: 1, meow: 2 }, { foo: null }, { foo: true }, { goof: null } ] RETURN UNSET(i, [ 'foo', 'bar', 'baz', 'meow' ])", false);
assertEqual(expected, actual);
actual = getQueryResults("FOR i IN [ { foo: 1, bar: 2, moo: 3, goof: 4, bang: 5, meow: 6 }, { foo: 0, goof: 1, meow: 2 }, { foo: null }, { foo: true }, { goof: null } ] RETURN UNSET(i, 'foo', 'bar', 'baz', 'meow')", false);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test merge function
////////////////////////////////////////////////////////////////////////////////