diff --git a/Ahuacatl/ahuacatl-optimiser.c b/Ahuacatl/ahuacatl-optimiser.c index fe7bc22eb6..6743f83fc0 100644 --- a/Ahuacatl/ahuacatl-optimiser.c +++ b/Ahuacatl/ahuacatl-optimiser.c @@ -122,6 +122,10 @@ static void PatchForLoops (TRI_aql_context_t* const context) { continue; } + if (!scope->_ranges) { + continue; + } + // we found a for loop, inspect it prefix = TRI_Concatenate2String(scope->_variableName, "."); @@ -130,7 +134,7 @@ static void PatchForLoops (TRI_aql_context_t* const context) { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return; } - + // iterate over all possible field accesses we found in this scope len = scope->_ranges->_length; for (j = 0; j < len; ++j) { diff --git a/Doxygen/Examples.Ahuacatl/aqlexample-collection b/Doxygen/Examples.Ahuacatl/aqlexample-collection new file mode 100644 index 0000000000..9043875f3b --- /dev/null +++ b/Doxygen/Examples.Ahuacatl/aqlexample-collection @@ -0,0 +1,42 @@ +/* return 5 documents from a users collection, unaltered */ +FOR u IN users + LIMIT 0, 5 + RETURN u + +[ { "_id" : "9259836/10505020", "_rev" : 10505020, "active" : true, "id" : 100, "age" : 37, "name" : "John", "gender" : "m" }, + { "_id" : "9259836/11553596", "_rev" : 11553596, "active" : true, "id" : 107, "age" : 30, "gender" : "m", "name" : "Anthony" }, + { "_id" : "9259836/11094844", "_rev" : 11094844, "active" : true, "id" : 101, "age" : 36, "name" : "Fred", "gender" : "m" }, + { "_id" : "9259836/11619132", "_rev" : 11619132, "active" : true, "id" : 108, "age" : 29, "name" : "Jim", "gender" : "m" }, + { "_id" : "9259836/11160380", "_rev" : 11160380, "active" : false, "id" : 102, "age" : 35, "name" : "Jacob", "gender" : "m" } ] + + +/* return a projection from a users collection */ +FOR u IN users + LIMIT 0, 5 + RETURN { "user" : { "isActive": u.active ? "yes" : "no", "name" : u.name } } + +[ { "user" : { "isActive" : "yes", "name" : "John" } }, + { "user" : { "isActive" : "yes", "name" : "Anthony" } }, + { "user" : { "isActive" : "yes", "name" : "Fred" } }, + { "user" : { "isActive" : "yes", "name" : "Jim" } }, + { "user" : { "isActive" : "no", "name" : "Jacob" } } ] + + +/* return a filtered projection from a users collection */ +FOR u IN users + FILTER u.active == true && u.age >= 30 + SORT u.age DESC + RETURN { "age" : u.age, "name" : u.name } + +[ { "age" : 37, "name" : "John" }, + { "age" : 37, "name" : "Sophia" }, + { "age" : 36, "name" : "Fred" }, + { "age" : 36, "name" : "Emma" }, + { "age" : 34, "name" : "Madison" }, + { "age" : 33, "name" : "Michael" }, + { "age" : 33, "name" : "Chloe" }, + { "age" : 32, "name" : "Alexander" }, + { "age" : 31, "name" : "Daniel" }, + { "age" : 31, "name" : "Abigail" }, + { "age" : 30, "name" : "Anthony" }, + { "age" : 30, "name" : "Isabella" } ] diff --git a/Doxygen/Examples.Ahuacatl/aqlexample-grouping b/Doxygen/Examples.Ahuacatl/aqlexample-grouping new file mode 100644 index 0000000000..0dfeda1d51 --- /dev/null +++ b/Doxygen/Examples.Ahuacatl/aqlexample-grouping @@ -0,0 +1,45 @@ +/* group users by age */ +FOR u IN users + FILTER u.active == true + COLLECT age = u.age INTO group + SORT age DESC + RETURN { "age" : age, "users" : group } + +[ { "age" : 37, "users" : ["Sophia", "John"] }, + { "age" : 36, "users" : ["Emma", "Fred"] }, + { "age" : 34, "users" : ["Madison"] }, + { "age" : 33, "users" : ["Chloe", "Michael"] }, + { "age" : 32, "users" : ["Alexander"] }, + { "age" : 31, "users" : ["Abigail", "Daniel"] }, + { "age" : 30, "users" : ["Isabella", "Anthony"] }, + { "age" : 29, "users" : ["Mary", "Jim"] }, + { "age" : 28, "users" : ["Mariah", "Diego"] } ] + + +/* group users by agegroup and gender */ +FOR u IN users + FILTER u.active == true + COLLECT ageGroup = FLOOR(u.age/5) * 5, gender = u.gender INTO group + SORT ageGroup DESC + RETURN { "ageGroup" : ageGroup, "gender" : gender, "numUsers" : LENGTH(group) } + +[ { "ageGroup" : 35, "gender" : "f", "numUsers" : 2 }, + { "ageGroup" : 35, "gender" : "m", "numUsers" : 2 }, + { "ageGroup" : 30, "gender" : "f", "numUsers" : 4 }, + { "ageGroup" : 30, "gender" : "m", "numUsers" : 4 }, + { "ageGroup" : 25, "gender" : "f", "numUsers" : 2 }, + { "ageGroup" : 25, "gender" : "m", "numUsers" : 2 } ] + + +/* get the 3 agegroups with most users */ +FOR u IN users + FILTER u.active == true + COLLECT ageGroup = FLOOR(u.age/5) * 5 INTO group + FILTER LENGTH(group) > 2 /* group must contain at least 3 users */ + SORT LENGTH(group) DESC + LIMIT 0, 3 + RETURN { "ageGroup" : ageGroup, "numUsers" : LENGTH(group), "users" : group[*].u.name } + +[ { "ageGroup" : 30, "numUsers" : 8, "users" : ["Alexander", "Isabella", "Michael", "Abigail", "Anthony", "Daniel", "Madison", "Chloe"] }, + { "ageGroup" : 25, "numUsers" : 4, "users" : ["Mariah", "Mary", "Jim", "Diego"] }, + { "ageGroup" : 35, "numUsers" : 4, "users" : ["Emma", "Sophia", "Fred", "John"] } ] diff --git a/Doxygen/Examples.Ahuacatl/aqlexample-join b/Doxygen/Examples.Ahuacatl/aqlexample-join new file mode 100644 index 0000000000..122f0a2f55 --- /dev/null +++ b/Doxygen/Examples.Ahuacatl/aqlexample-join @@ -0,0 +1,49 @@ +/* getting the names of friends (also users) for users. this is achieved by "joining" a relations table */ +FOR u IN users + FILTER u.active == true + LET friends = (FOR f IN userRelations + FILTER f.from == u.id + FOR u2 IN users + FILTER f.to == u2.id + RETURN u2.name + ) + RETURN { "user" : u.name, "friends" : friends } + +[ { "user" : "John", "friends" : ["Diego", "Mary", "Abigail"] }, + { "user" : "Anthony", "friends" : ["Madison"] }, + { "user" : "Fred", "friends" : ["Mariah"] }, + { "user" : "Jim", "friends" : ["Mariah"] }, + { "user" : "Diego", "friends" : ["Mary"] }, + { "user" : "Sophia", "friends" : ["Madison", "John"] }, + { "user" : "Michael", "friends" : ["John", "Jim"] }, + { "user" : "Emma", "friends" : ["Jacob", "Madison"] }, + { "user" : "Alexander", "friends" : ["Michael", "John"] }, + { "user" : "Daniel", "friends" : ["Eva"] }, + { "user" : "Madison", "friends" : ["Anthony", "Daniel"] }, + { "user" : "Chloe", "friends" : ["Alexander"] }, + { "user" : "Abigail", "friends" : ["Daniel", "John", "Jacob", "Jim"] }, + { "user" : "Isabella", "friends" : ["Madison", "Diego"] }, + { "user" : "Mary", "friends" : ["Isabella", "Diego", "Michael"] }, + { "user" : "Mariah", "friends" : ["Madison", "Ethan", "Eva"] } ] + + +/* getting users favorite song names from a joined "songs" collection */ +FOR u IN users + LET likes = ( + FOR s IN songs + FILTER s._id IN u.likes + RETURN CONCAT(s.artist, " - ", s.song) + ) + SORT RAND() + LIMIT 0, 8 + RETURN { "user" : u.name, "likes" : likes } + +[ { "user" : "Eva", "likes" : ["Chocolate - Ritmo De La Noche", "4 The Cause - Stand By Me", "Tony Carey - Room with a view"] }, + { "user" : "Mary", "likes" : ["Hall and Oates - Maneater", "Elton John - Candle In The Wind", "A-Ha - Crying In The Rain", "Laid Back - Sunshine Reggae", "Cock Robin - The promise you made"] }, + { "user" : "Alexander", "likes" : ["Moby - Feel so real", "Rednex - Old pop in an oak", "2 Unlimited - No Limit"] }, + { "user" : "Michael", "likes" : ["The Kelly Family - David's Song"] }, + { "user" : "Ethan", "likes" : ["Technotronic - Megamix", "Gipsy Kings - Baila me", "Goombay Dance Band - Seven Tears", "Sandra - Hiroshima"] }, { "user" : "Isabella", "likes" : ["Milli Vanilli - Girl, I'm Gonna Miss You", "Technotronic - Get Up", "Right Said Fred - Don't Talk Just Kiss", "Peter Schilling - Major Tom (Völlig losgelöst)"] }, + { "user" : "Abigail", "likes" : ["Tina Turner - Typical male", "Liquido - Narcotic"] }, + { "user" : "Jim", "likes" : ["Berlin - Take my breath away", "Ashford & Simpson - Solid", "Fine Young Cannibals - She drives me cracy", "Cut'N'Move - Give it up", "Cyndi Lauper - Time after time"] }, + { "user" : "Jacob", "likes" : ["Kylie Minogue - The Loco-motion", "Eruption - Runaway"] } ] + diff --git a/Doxygen/Examples.Ahuacatl/aqlexample-simple b/Doxygen/Examples.Ahuacatl/aqlexample-simple new file mode 100644 index 0000000000..34ccf7ad93 --- /dev/null +++ b/Doxygen/Examples.Ahuacatl/aqlexample-simple @@ -0,0 +1,23 @@ +/* a query that returns a string value. the result string is contained in a list because the result of every valid query is a list */ +RETURN "this will be returned" + +["this will be returned"] + + +/* a query that creates the cross products of two lists, and runs a projection on it */ +FOR year in [ 2011, 2012, 2013 ] + FOR quarter IN [ 1, 2, 3, 4 ] + RETURN { "y" : "year", "q" : quarter, "nice" : CONCAT(TOSTRING(quarter), "/", TOSTRING(year)) } + +[ { "y" : "year", "q" : 1, "nice" : "1/2011" }, + { "y" : "year", "q" : 2, "nice" : "2/2011" }, + { "y" : "year", "q" : 3, "nice" : "3/2011" }, + { "y" : "year", "q" : 4, "nice" : "4/2011" }, + { "y" : "year", "q" : 1, "nice" : "1/2012" }, + { "y" : "year", "q" : 2, "nice" : "2/2012" }, + { "y" : "year", "q" : 3, "nice" : "3/2012" }, + { "y" : "year", "q" : 4, "nice" : "4/2012" }, + { "y" : "year", "q" : 1, "nice" : "1/2013" }, + { "y" : "year", "q" : 2, "nice" : "2/2013" }, + { "y" : "year", "q" : 3, "nice" : "3/2013" }, + { "y" : "year", "q" : 4, "nice" : "4/2013" } ] diff --git a/Makefile.files b/Makefile.files index 976d3c2151..bff867df7c 100644 --- a/Makefile.files +++ b/Makefile.files @@ -407,4 +407,5 @@ WIKI = \ UserManual \ UserManualBasics \ Aql \ + AqlExamples \ jsUnity diff --git a/RestServer/aql-examples.dox b/RestServer/aql-examples.dox new file mode 100644 index 0000000000..192b57bd0c --- /dev/null +++ b/RestServer/aql-examples.dox @@ -0,0 +1,56 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief ArangoDB query language (AQL), examples +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 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 +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @page AqlExamples ArangoDB Query Language (AQL) Examples +/// +/// This page contains some examples for how to write queries in AQL. For better +/// understandability, the query results are also included. +/// +/// @section AqlExamplesSimple Simple queries +/// +/// @verbinclude aqlexample-simple +/// +/// @section AqlExamplesCollection Collection-based queries +/// +/// @verbinclude aqlexample-collection +/// +/// @section AqlExamplesJoins Joins +/// +/// @verbinclude aqlexample-join +/// +/// @section AqlExamplesGrouping Grouping +/// +/// @verbinclude aqlexample-grouping +/// +//////////////////////////////////////////////////////////////////////////////// + +// Local Variables: +// mode: c++ +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @\\}\\)" +// End: diff --git a/RestServer/aql.dox b/RestServer/aql.dox index 3427643410..59327d3e0b 100644 --- a/RestServer/aql.dox +++ b/RestServer/aql.dox @@ -106,6 +106,8 @@ /// to issue read-requests on your database, but modifying data via AQL is /// currently not supported. /// +/// For some example queries, please refer to the page @ref AqlExamples. +/// /// @section AqlQueryResults Query results /// /// @subsection AqlQueryResultsSet Result sets diff --git a/V8/v8-vocbase.cpp b/V8/v8-vocbase.cpp index 833cdc6ed9..4f52653420 100644 --- a/V8/v8-vocbase.cpp +++ b/V8/v8-vocbase.cpp @@ -1033,7 +1033,7 @@ static v8::Handle ExecuteQueryCursorAhuacatl (TRI_vocbase_t* const vo } if (allowDirectReturn || !result->IsArray()) { - // rethrow + // return the value we got as it is. this is a performance optimisation return scope.Close(result); } diff --git a/js/server/ahuacatl.js b/js/server/ahuacatl.js index 4055934b05..b85040c7bc 100644 --- a/js/server/ahuacatl.js +++ b/js/server/ahuacatl.js @@ -1001,13 +1001,10 @@ function AHUACATL_RELATIONAL_IN (lhs, rhs) { if (rightWeight !== AHUACATL_TYPEWEIGHT_LIST) { AHUACATL_THROW(internal.errors.ERROR_QUERY_LIST_EXPECTED); } - - var r = AHUACATL_KEYS(rhs, false); - var numRight = r.length; + var numRight = rhs.length; for (var i = 0; i < numRight; ++i) { - var key = r[i]; - if (AHUACATL_RELATIONAL_EQUAL(lhs, rhs[key])) { + if (AHUACATL_RELATIONAL_EQUAL(lhs, rhs[i])) { return true; } } diff --git a/js/server/js-ahuacatl.h b/js/server/js-ahuacatl.h index 4878dc94e3..45a8df7cb7 100644 --- a/js/server/js-ahuacatl.h +++ b/js/server/js-ahuacatl.h @@ -1002,13 +1002,10 @@ static string JS_server_ahuacatl = " if (rightWeight !== AHUACATL_TYPEWEIGHT_LIST) {\n" " AHUACATL_THROW(internal.errors.ERROR_QUERY_LIST_EXPECTED);\n" " }\n" - " \n" - " var r = AHUACATL_KEYS(rhs, false);\n" - " var numRight = r.length;\n" "\n" + " var numRight = rhs.length;\n" " for (var i = 0; i < numRight; ++i) {\n" - " var key = r[i];\n" - " if (AHUACATL_RELATIONAL_EQUAL(lhs, rhs[key])) {\n" + " if (AHUACATL_RELATIONAL_EQUAL(lhs, rhs[i])) {\n" " return true;\n" " }\n" " }\n"