From fd61b74174f36b9f1d0daa3b2c22c1fe1524b5ea Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Wed, 5 Dec 2012 11:48:56 +0100 Subject: [PATCH] added AQL function DOCUMENT() to retrieve a document by its _id value --- CHANGELOG | 2 + arangod/Ahuacatl/ahuacatl-functions.c | 1 + arangod/Documentation/aql.dox | 6 ++ js/server/ahuacatl.js | 18 ++++++ js/server/tests/ahuacatl-functions.js | 85 +++++++++++++++++++++++++-- 5 files changed, 106 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ff59e03810..8f790781a7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,8 @@ v1.1.0 (2012-12-05) procedure also guarantees that the server is not run without any required system collections or with in incompatible data state. +* added AQL function DOCUMENT() to retrieve a document by its _id value + * fixed issue #311: fixed segfault on unload * fixed issue #309: renamed stub "import" button from web interface diff --git a/arangod/Ahuacatl/ahuacatl-functions.c b/arangod/Ahuacatl/ahuacatl-functions.c index 2e6ede38f5..626033ea4e 100644 --- a/arangod/Ahuacatl/ahuacatl-functions.c +++ b/arangod/Ahuacatl/ahuacatl-functions.c @@ -479,6 +479,7 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) { REGISTER_FUNCTION("HAS", "HAS", true, false, "az,s", NULL); REGISTER_FUNCTION("MERGE", "MERGE", true, false, "a,a|+", NULL); REGISTER_FUNCTION("MERGE_RECURSIVE", "MERGE_RECURSIVE", true, false, "a,a|+", NULL); + REGISTER_FUNCTION("DOCUMENT", "DOCUMENT", false, false, "h,.", NULL); // geo functions REGISTER_FUNCTION("NEAR", "GEO_NEAR", false, false, "h,n,n,n|s", NULL); diff --git a/arangod/Documentation/aql.dox b/arangod/Documentation/aql.dox index dd62f1c493..f61d709fe7 100644 --- a/arangod/Documentation/aql.dox +++ b/arangod/Documentation/aql.dox @@ -977,6 +977,12 @@ /// /// - @FN{COLLECTIONS()}: returns a list of collections. Each collection is returned as a document /// with attributes @LIT{name} and @LIT{_id}. +/// - @FN{DOCUMENT(@FA{collection}, @FA{id})}: returns the document that id uniquely identified by +/// the @FA{id}. ArangoDB will try to find the document using the @LIT{_id} value of the document +/// in the specified collection. If there is a mismatch between the @FA{collection} passed and +/// the collection specified in @FA{id}, then no document will be returned. Additionally, if the +/// @FA{collection} matches the collection value specified in @FA{id} but the document cannot be +/// found, no document will be returned. /// /// @section AqlOperations High-level operations /// diff --git a/js/server/ahuacatl.js b/js/server/ahuacatl.js index d318032bfe..e99e942d08 100755 --- a/js/server/ahuacatl.js +++ b/js/server/ahuacatl.js @@ -90,6 +90,10 @@ function AHUACATL_INDEX (collection, indexTypes) { //////////////////////////////////////////////////////////////////////////////// function AHUACATL_COLLECTION (name) { + if (typeof name !== 'string') { + AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "internal"); + } + if (name.substring(0, 1) === '_') { // system collections need to be accessed slightly differently as they // are not returned by the propertyGetter of db @@ -107,6 +111,7 @@ function AHUACATL_NORMALIZE (value) { if (value === null || value === undefined) { return null; } + if (typeof(value) !== "object") { return value; } @@ -406,6 +411,19 @@ function AHUACATL_LIST (value) { return value; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief get a document by its unique id +//////////////////////////////////////////////////////////////////////////////// + +function AHUACATL_DOCUMENT (collection, id) { + try { + return AHUACATL_COLLECTION(collection).document(id); + } + catch (e) { + return undefined; + } +} + //////////////////////////////////////////////////////////////////////////////// /// @brief get all documents from the specified collection //////////////////////////////////////////////////////////////////////////////// diff --git a/js/server/tests/ahuacatl-functions.js b/js/server/tests/ahuacatl-functions.js index 1edd39e5f2..f81d85605c 100644 --- a/js/server/tests/ahuacatl-functions.js +++ b/js/server/tests/ahuacatl-functions.js @@ -39,8 +39,8 @@ function ahuacatlFunctionsTestSuite () { /// @brief execute a given query //////////////////////////////////////////////////////////////////////////////// - function executeQuery (query) { - var cursor = AHUACATL_RUN(query, undefined); + function executeQuery (query, bindVars) { + var cursor = AHUACATL_RUN(query, bindVars); if (cursor instanceof ArangoError) { print(query, cursor.errorMessage); } @@ -52,12 +52,12 @@ function ahuacatlFunctionsTestSuite () { /// @brief execute a given query and return the results as an array //////////////////////////////////////////////////////////////////////////////// - function getQueryResults (query, isFlat) { - var result = executeQuery(query).getRows(); + function getQueryResults (query, isFlat, bindVars) { + var result = executeQuery(query, bindVars).getRows(); var results = [ ]; for (var i in result) { - if (!result.hasOwnProperty(i)) { + if (! result.hasOwnProperty(i)) { continue; } @@ -68,7 +68,7 @@ function ahuacatlFunctionsTestSuite () { else { var keys = [ ]; for (var k in row) { - if (row.hasOwnProperty(k)) { + if (row.hasOwnProperty(k) && k != '_rev' && k != '_key' && k != '_id') { keys.push(k); } } @@ -1078,6 +1078,79 @@ function ahuacatlFunctionsTestSuite () { assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN UNION({ }, [ ])"); } )); }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test document function +//////////////////////////////////////////////////////////////////////////////// + + testDocument1 : function () { + var cn = "UnitTestsAhuacatlFunctions"; + + internal.db._drop(cn); + var cx = internal.db._create(cn); + var d1 = cx.save({ "title" : "123", "value" : 456 }); + var d2 = cx.save({ "title" : "nada", "value" : 123 }); + + var expected, actual; + + expected = [ { title: "123", value : 456 } ]; + actual = getQueryResults("RETURN DOCUMENT(" + cn + ", \"" + d1._id + "\")", false); + assertEqual(expected, actual); + + expected = [ { title: "nada", value : 123 } ]; + actual = getQueryResults("RETURN DOCUMENT(" + cn + ", \"" + d2._id + "\")", false); + assertEqual(expected, actual); + + internal.db._drop(cn); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test document function +//////////////////////////////////////////////////////////////////////////////// + + testDocument2 : function () { + var cn = "UnitTestsAhuacatlFunctions"; + + internal.db._drop(cn); + var cx = internal.db._create(cn); + var d1 = cx.save({ "title" : "123", "value" : 456, "zxy" : 1 }); + var d2 = cx.save({ "title" : "nada", "value" : 123, "zzzz" : false }); + + var expected, actual; + + expected = [ { title: "123", value : 456, zxy: 1 } ]; + actual = getQueryResults("RETURN DOCUMENT(@@cn, @id)", false, { "@cn" : cn, "id" : d1._id }); + assertEqual(expected, actual); + + expected = [ { title: "nada", value : 123, zzzz : false } ]; + actual = getQueryResults("RETURN DOCUMENT(@@cn, @id)", false, { "@cn" : cn, "id" : d2._id }); + assertEqual(expected, actual); + + internal.db._drop(cn); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test document function +//////////////////////////////////////////////////////////////////////////////// + + testDocumentInvalid : function () { + var cn = "UnitTestsAhuacatlFunctions"; + + internal.db._drop(cn); + var cx = internal.db._create(cn); + + var expected, actual; + + // test with non-existing document + expected = [ ]; + actual = getQueryResults("RETURN DOCUMENT(" + cn + ", \"" + cn + "/99999999999\")", false); + assertEqual(expected, actual); + + actual = getQueryResults("RETURN DOCUMENT(" + cn + ", \"thefoxdoesnotexist/99999999999\")", false); + assertEqual(expected, actual); + + internal.db._drop(cn); + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test min function ////////////////////////////////////////////////////////////////////////////////