diff --git a/Ahuacatl/ahuacatl-functions.c b/Ahuacatl/ahuacatl-functions.c index c5cc5bd096..0881583b08 100644 --- a/Ahuacatl/ahuacatl-functions.c +++ b/Ahuacatl/ahuacatl-functions.c @@ -354,23 +354,22 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) { // a = array // type check functions - REGISTER_FUNCTION("ISNULL", "IS_NULL", true, false, "."); - REGISTER_FUNCTION("ISBOOL", "IS_BOOL", true, false, "."); - REGISTER_FUNCTION("ISNUMBER", "IS_NUMBER", true, false, "."); - REGISTER_FUNCTION("ISSTRING", "IS_STRING", true, false, "."); - REGISTER_FUNCTION("ISLIST", "IS_LIST", true, false, "."); - REGISTER_FUNCTION("ISDOCUMENT", "IS_DOCUMENT", true, false, "."); + REGISTER_FUNCTION("IS_NULL", "IS_NULL", true, false, "."); + REGISTER_FUNCTION("IS_BOOL", "IS_BOOL", true, false, "."); + REGISTER_FUNCTION("IS_NUMBER", "IS_NUMBER", true, false, "."); + REGISTER_FUNCTION("IS_STRING", "IS_STRING", true, false, "."); + REGISTER_FUNCTION("IS_LIST", "IS_LIST", true, false, "."); + REGISTER_FUNCTION("IS_DOCUMENT", "IS_DOCUMENT", true, false, "."); // cast functions - REGISTER_FUNCTION("TONUMBER", "CAST_NUMBER", true, false, "."); - REGISTER_FUNCTION("TOSTRING", "CAST_STRING", true, false, "."); - REGISTER_FUNCTION("TOBOOL", "CAST_BOOL", true, false, "."); - REGISTER_FUNCTION("TONULL", "CAST_NULL", true, false, "."); + REGISTER_FUNCTION("TO_NUMBER", "CAST_NUMBER", true, false, "."); + REGISTER_FUNCTION("TO_STRING", "CAST_STRING", true, false, "."); + REGISTER_FUNCTION("TO_BOOL", "CAST_BOOL", true, false, "."); // string functions REGISTER_FUNCTION("CONCAT", "STRING_CONCAT", true, false, "sz,sz|+"); - REGISTER_FUNCTION("CONCATSEPARATOR", "STRING_CONCAT_SEPARATOR", true, false, "s,sz,sz|+"); - REGISTER_FUNCTION("CHARLENGTH", "STRING_LENGTH", true, false, "s"); + REGISTER_FUNCTION("CONCAT_SEPARATOR", "STRING_CONCAT_SEPARATOR", true, false, "s,sz,sz|+"); + REGISTER_FUNCTION("CHAR_LENGTH", "STRING_LENGTH", true, false, "s"); REGISTER_FUNCTION("LOWER", "STRING_LOWER", true, false, "s"); REGISTER_FUNCTION("UPPER", "STRING_UPPER", true, false, "s"); REGISTER_FUNCTION("SUBSTRING", "STRING_SUBSTRING", true, false, "s,n|n"); @@ -408,6 +407,7 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) { REGISTER_FUNCTION("FAIL", "FAIL", false, false, "|s"); // FAIL is non-deterministic, otherwise query optimisation will fail! REGISTER_FUNCTION("PASSTHRU", "PASSTHRU", false, false, "."); // simple non-deterministic wrapper to avoid optimisations at parse time REGISTER_FUNCTION("COLLECTIONS", "COLLECTIONS", false, false, ""); + REGISTER_FUNCTION("NOT_NULL", "NOT_NULL", true, false, ".,."); if (!result) { TRI_FreeFunctionsAql(functions); 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..0d9af84096 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 @@ -695,25 +697,23 @@ /// This helps avoiding unexpected results. All type casts have to be performed /// by invoking a type cast function. AQL offers several type cast functions for this /// task. Each of the these functions takes an operand of any data type and returns a -/// result value of type corresponding to the function name (e.g. @LIT{TONUMBER()} will +/// result value of type corresponding to the function name (e.g. @LIT{TO_NUMBER()} will /// return a number value): /// -/// - @FN{TONULL(@FA{value})}: converts the @FA{value} into a @LIT{null} value. This -/// function will always return @LIT{null}. -/// - @FN{TOBOOL(@FA{value})}: takes an input @FA{value} of any type and converts it +/// - @FN{TO_BOOL(@FA{value})}: takes an input @FA{value} of any type and converts it /// into the appropriate boolean value as follows: /// - @LIT{null} is converted to false. /// - Numbers are converted to true if they are unequal to 0, and to false otherwise. /// - Strings are converted to true if they are non-empty, and to false otherwise. /// - Lists are converted to true if they are non-empty, and to false otherwise. /// - Documents are converted to true if they are non-empty, and to false otherwise. -/// - @FN{TONUMBER(@FA{value})}: takes an input @FA{value} of any type and converts it +/// - @FN{TO_NUMBER(@FA{value})}: takes an input @FA{value} of any type and converts it /// into a numeric value as follows: /// - @LIT{null}, false, lists, and documents are converted to the value @LIT{0}. /// - true is converted to @LIT{1}. /// - Strings are converted to their numeric equivalent if the full string content is /// is a valid number, and to @LIT{0} otherwise. -/// - @FN{TOSTRING(@FA{value})}: takes an input @FA{value} of any type and converts it +/// - @FN{TO_STRING(@FA{value})}: takes an input @FA{value} of any type and converts it /// into a string value as follows: /// - @LIT{null} is converted to the string @LIT{"null"} /// - false is converted to the string @LIT{"false"}, true to the string @LIT{"true"} @@ -728,12 +728,12 @@ /// /// The following type check functions are available: /// -/// - @FN{ISNULL(@FA{value})}: checks whether @FA{value} is a @LIT{null} value -/// - @FN{ISBOOL(@FA{value})}: checks whether @FA{value} is a boolean value -/// - @FN{ISNUMBER(@FA{value})}: checks whether @FA{value} is a numeric value -/// - @FN{ISSTRING(@FA{value})}: checks whether @FA{value} is a string value -/// - @FN{ISLIST(@FA{value})}: checks whether @FA{value} is a list value -/// - @FN{ISDOCUMENT(@FA{value})}: checks whether @FA{value} is a document value +/// - @FN{IS_NULL(@FA{value})}: checks whether @FA{value} is a @LIT{null} value +/// - @FN{IS_BOOL(@FA{value})}: checks whether @FA{value} is a boolean value +/// - @FN{IS_NUMBER(@FA{value})}: checks whether @FA{value} is a numeric value +/// - @FN{IS_STRING(@FA{value})}: checks whether @FA{value} is a string value +/// - @FN{IS_LIST(@FA{value})}: checks whether @FA{value} is a list value +/// - @FN{IS_DOCUMENT(@FA{value})}: checks whether @FA{value} is a document value /// /// @subsubsection AqlFunctionsString String functions /// @@ -741,10 +741,10 @@ /// /// - @FN{CONCAT(@FA{value1}\, @FA{value2}\, ... @FA{valuen})}: concatenate the strings /// passed as in @FA{value1} to @FA{valuen}. @LIT{null} values are ignored. -/// - @FN{CONCATSEPARATOR(@FA{separator}\, @FA{value1}\, @FA{value2}\, ... @FA{valuen})}: +/// - @FN{CONCAT_SEPARATOR(@FA{separator}\, @FA{value1}\, @FA{value2}\, ... @FA{valuen})}: /// concatenate the strings passed as arguments @FA{value1} to @FA{valuen} using the /// @FA{separator} string. @LIT{null} values are ignored. -/// - @FN{CHARLENGTH(@FA{value})}: return the number of characters in @FA{value} +/// - @FN{CHAR_LENGTH(@FA{value})}: return the number of characters in @FA{value} /// - @FN{LOWER(@FA{value})}: lower-case @FA{value} /// - @FN{UPPER(@FA{value})}: upper-case @FA{value} /// - @FN{SUBSTRING(@FA{value}\, @FA{offset}\, @FA{length})}: return a substring of @FA{value}, @@ -756,33 +756,33 @@ /// AQL offers some numeric functions for calculations. The following functions are /// supported: /// -/// - @LIT{FLOOR(@FA{value})}: returns the integer closest but not greater to @FA{value} -/// - @LIT{CEIL(@FA{value})}: returns the integer closest but not less than @FA{value} -/// - @LIT{ROUND(@FA{value})}: returns the integer closest to @FA{value} -/// - @LIT{ABS(@FA{value})}: returns the absolute part of @FA{value} -/// - @LIT{RAND()}: returns a random number between 0 and 1 +/// - @FN{FLOOR(@FA{value})}: returns the integer closest but not greater to @FA{value} +/// - @FN{CEIL(@FA{value})}: returns the integer closest but not less than @FA{value} +/// - @FN{ROUND(@FA{value})}: returns the integer closest to @FA{value} +/// - @FN{ABS(@FA{value})}: returns the absolute part of @FA{value} +/// - @FN{RAND()}: returns a pseudo-random number between 0 and 1 /// /// @subsubsection AqlFunctionsList List functions /// /// AQL supports the following functions to operate on list values: /// -/// - @LIT{LENGTH(@FA{list})}: returns the length (number of elements) of @FA{list} -/// - @LIT{MIN(@FA{list})}: returns the smallest element of @FA{list}. @LIT{null} values +/// - @FN{LENGTH(@FA{list})}: returns the length (number of elements) of @FA{list} +/// - @FN{MIN(@FA{list})}: returns the smallest element of @FA{list}. @LIT{null} values /// are ignored. If the list is empty or only @LIT{null} are contained in the list, the /// function will return @LIT{null}. -/// - @LIT{MAX(@FA{list})}: returns the greatest element of @FA{list}. @LIT{null} values +/// - @FN{MAX(@FA{list})}: returns the greatest element of @FA{list}. @LIT{null} values /// are ignored. If the list is empty or only @LIT{null} are contained in the list, the /// function will return @LIT{null}. -/// - @LIT{SUM(@FA{list})}: returns the sum of values of the elements in @FA{list}. This +/// - @FN{SUM(@FA{list})}: returns the sum of values of the elements in @FA{list}. This /// requires the elements in @FA{list} to be numbers. @LIT{null} values are ignored. /// If the list is empty or only @LIT{null} are contained in the list, the function /// will return @LIT{null}. -/// - @LIT{REVERSE(@FA{list})}: returns the elements in @FA{list} in reversed order. -/// - @LIT{FIRST(@FA{list})}: returns the first element in @FA{list} or @LIT{null} if the +/// - @FN{REVERSE(@FA{list})}: returns the elements in @FA{list} in reversed order. +/// - @FN{FIRST(@FA{list})}: returns the first element in @FA{list} or @LIT{null} if the /// list is empty. -/// - @LIT{LAST(@FA{list})}: returns the last element in @FA{list} or @LIT{null} if the +/// - @FN{LAST(@FA{list})}: returns the last element in @FA{list} or @LIT{null} if the /// list is empty. -/// - @LIT{UNIQUE(@FA{list})}: returns all unique elements in @FA{list}. To determine +/// - @FN{UNIQUE(@FA{list})}: returns all unique elements in @FA{list}. To determine /// uniqueness, the function will use the comparison order defined in @ref AqlTypeOrder. /// Calling this function might return the unique elements in any order. /// @@ -793,18 +793,18 @@ /// /// AQL supports the following functions to operate on document values: /// -/// - @LIT{MERGE(@FA{document1}\, @FA{document2}\, ... @FA{documentn})}: merges the documents +/// - @FN{MERGE(@FA{document1}\, @FA{document2}\, ... @FA{documentn})}: merges the documents /// in @FA{document1} to @FA{documentn} into a single document. If document attribute /// keys are ambigious, the merged result will contain the values of the documents /// contained later in the argument list. -/// - @LIT{HAS(@FA{document}\, @FA{attributename})}: returns true if @FA{document} has an +/// - @FN{HAS(@FA{document}\, @FA{attributename})}: returns true if @FA{document} has an /// attribute named @FA{attributename}, and false otherwise. /// /// @subsubsection AqlFunctionsGeo Geo functions /// /// AQL offers the following functions to filter data based on geo indexes: /// -/// - @LIT{NEAR(@FA{collection}\, @FA{latitude}\, @FA{longitude}\, @FA{limit}\, @FA{distancename})}: +/// - @FN{NEAR(@FA{collection}\, @FA{latitude}\, @FA{longitude}\, @FA{limit}\, @FA{distancename})}: /// returns at most @FA{limit} documents from collection @FA{collection} that are near /// @FA{latitude} and @FA{longitude}. The result contains at @FA{limit} documents, returned in /// any order. If more than @FA{limit} documents qualify, it is undefined which of the qualifying @@ -813,7 +813,7 @@ /// To make use of that, an attribute name for the distance result has to be specified in /// the @FA{distancename} argument. The result documents will contain the distance value in /// an attribute of that name. -/// - @LIT{WITHIN(@FA{collection}\, @FA{latitude}\, @FA{longitude}\, @FA{radius}\, @FA{distancename})}: +/// - @FN{WITHIN(@FA{collection}\, @FA{latitude}\, @FA{longitude}\, @FA{radius}\, @FA{distancename})}: /// returns all documents from collection @FA{collection} that are within a radius of /// @FA{radius} around that specified coordinate (@FA{latitude} and @FA{longitude}). The order /// in which the result documents are returned is undefined. Optionally, the distance between the @@ -829,7 +829,7 @@ /// /// AQL has the following functions to traverse graphs: /// -/// - @LIT{PATHS(@FA{vertexcollection}\, @FA{edgecollection}\, @FA{direction}\, @FA{followcycles})}: +/// - @FN{PATHS(@FA{vertexcollection}\, @FA{edgecollection}\, @FA{direction}\, @FA{followcycles})}: /// returns a list of paths through the graph defined by the nodes in the collection /// @FA{vertexcollection} and edges in the collection @FA{edgecollection}. For each vertex /// in @FA{vertexcollection}, it will determine the paths through the graph depending on the @@ -852,12 +852,19 @@ /// /// @verbinclude aqlpaths /// +/// @subsubsection AqlFunctionsControl Control flow functions +/// +/// AQL offers the following functions to let the user control the flow of operations: +/// +/// - @FN{NOT_NULL(@FA{condition}\, @FA{alternative})}: returns @FA{condition} if it is not +/// @LIT{null}, and @FA{alternative} otherwise. +/// /// @subsubsection AqlFunctionsMisc Miscellaneous functions /// /// Finally, AQL supports the following functions that do not belong to any of the other /// function categories: /// -/// - @LIT{COLLECTIONS()}: returns a list of collections. Each collection is returned as a document +/// - @FN{COLLECTIONS()}: returns a list of collections. Each collection is returned as a document /// with attributes @LIT{name} and @LIT{_id}. /// /// @section AqlOperations High-level operations diff --git a/RestServer/imp-manual.dox b/RestServer/imp-manual.dox index 3b63f10223..84b501a00f 100644 --- a/RestServer/imp-manual.dox +++ b/RestServer/imp-manual.dox @@ -58,7 +58,7 @@ /// /// @EMBEDTOC{ImpManualBasicsTOC} /// -/// The most convenient method to import a lot of data into AvocadoDB is to use +/// The most convenient method to import a lot of data into ArangoDB is to use /// the @LIT{arangoimp} command-line tool. It allows you to import data records /// from a file into an existing database collection. /// @@ -114,7 +114,7 @@ /// @LIT{arangoimp --file "data.csv" --type csv --collection "users"} /// /// Note that the quote and separator characters can be adjusted via the -/// @CA{--quote} and @CA{--separator} arguments when invoking avocimp. +/// @CA{--quote} and @CA{--separator} arguments when invoking arangoimp. //////////////////////////////////////////////////////////////////////////////// // Local Variables: 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/V8Client/arangoimp.cpp b/V8Client/arangoimp.cpp index ed8c0e569c..78d7e27108 100644 --- a/V8Client/arangoimp.cpp +++ b/V8Client/arangoimp.cpp @@ -202,7 +202,7 @@ static void ParseProgramOptions (int argc, char* argv[]) { // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -/// @addtogroup avocimp +/// @addtogroup arangoimp /// @{ //////////////////////////////////////////////////////////////////////////////// diff --git a/js/server/ahuacatl.js b/js/server/ahuacatl.js index 4055934b05..90a969ad27 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; } } @@ -1309,16 +1306,6 @@ function AHUACATL_STRING_SUBSTRING (value, offset, count) { /// @{ //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// @brief cast to null -/// -/// the operand can have any type, always returns null -//////////////////////////////////////////////////////////////////////////////// - -function AHUACATL_CAST_NULL (value) { - return null; -} - //////////////////////////////////////////////////////////////////////////////// /// @brief cast to a bool /// @@ -2052,6 +2039,20 @@ function AHUACATL_GRAPH_SUBNODES (searchAttributes, vertexId, visited, edges, ve /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief return value if it's not null, otherwise return alternative +/// +/// the operands can have any type +//////////////////////////////////////////////////////////////////////////////// + +function AHUACATL_NOT_NULL (value, alternative) { + if (AHUACATL_TYPEWEIGHT(value) === AHUACATL_TYPEWEIGHT_NULL) { + return alternative; + } + + return value; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief check whether a document has an attribute //////////////////////////////////////////////////////////////////////////////// diff --git a/js/server/js-ahuacatl.h b/js/server/js-ahuacatl.h index 4878dc94e3..ea36d5b5cb 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" @@ -1311,16 +1308,6 @@ static string JS_server_ahuacatl = "////////////////////////////////////////////////////////////////////////////////\n" "\n" "////////////////////////////////////////////////////////////////////////////////\n" - "/// @brief cast to null\n" - "///\n" - "/// the operand can have any type, always returns null\n" - "////////////////////////////////////////////////////////////////////////////////\n" - "\n" - "function AHUACATL_CAST_NULL (value) {\n" - " return null;\n" - "}\n" - "\n" - "////////////////////////////////////////////////////////////////////////////////\n" "/// @brief cast to a bool\n" "///\n" "/// the operand can have any type, always returns a bool\n" @@ -2054,6 +2041,20 @@ static string JS_server_ahuacatl = "////////////////////////////////////////////////////////////////////////////////\n" "\n" "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief return value if it's not null, otherwise return alternative\n" + "///\n" + "/// the operands can have any type\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AHUACATL_NOT_NULL (value, alternative) {\n" + " if (AHUACATL_TYPEWEIGHT(value) === AHUACATL_TYPEWEIGHT_NULL) {\n" + " return alternative;\n" + " }\n" + "\n" + " return value;\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" "/// @brief check whether a document has an attribute\n" "////////////////////////////////////////////////////////////////////////////////\n" "\n" diff --git a/js/server/tests/ahuacatl-functions.js b/js/server/tests/ahuacatl-functions.js index 3210d884a0..772aabdd30 100644 --- a/js/server/tests/ahuacatl-functions.js +++ b/js/server/tests/ahuacatl-functions.js @@ -411,7 +411,7 @@ function ahuacatlFunctionsTestSuite () { testConcatSeparator1 : function () { var expected = [ "the,Quick,Brown,Fox,Jumps" ]; - var actual = getQueryResults("FOR r IN [ 1 ] return CONCATSEPARATOR(',', 'the', 'Quick', null, 'Brown', null, 'Fox', 'Jumps')", true); + var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT_SEPARATOR(',', 'the', 'Quick', null, 'Brown', null, 'Fox', 'Jumps')", true); assertEqual(expected, actual); }, @@ -421,7 +421,7 @@ function ahuacatlFunctionsTestSuite () { testConcatSeparator2 : function () { var expected = [ "the*/*/Quick*/*/Brown*/*/*/*/Fox*/*/Jumps" ]; - var actual = getQueryResults("FOR r IN [ 1 ] return CONCATSEPARATOR('*/*/', 'the', 'Quick', null, 'Brown', '', 'Fox', 'Jumps')", true); + var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT_SEPARATOR('*/*/', 'the', 'Quick', null, 'Brown', '', 'Fox', 'Jumps')", true); assertEqual(expected, actual); }, @@ -430,22 +430,22 @@ function ahuacatlFunctionsTestSuite () { //////////////////////////////////////////////////////////////////////////////// testConcatSeparatorInvalid : function () { - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR()"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(\"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(\"yes\", \"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(null, \"yes\", \"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(true, \"yes\", \"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(4, \"yes\", \"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR([ ], \"yes\", \"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR({ }, \"yes\", \"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(\"yes\", true, \"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(\"yes\", 4, \"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(\"yes\", [ ], \"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(\"yes\", { }, \"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(\"yes\", \"yes\", true)"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(\"yes\", \"yes\", 4)"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(\"yes\", \"yes\", [ ])"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCATSEPARATOR(\"yes\", \"yes\", { })"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR()"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(\"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(null, \"yes\", \"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(true, \"yes\", \"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(4, \"yes\", \"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR([ ], \"yes\", \"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR({ }, \"yes\", \"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(\"yes\", true, \"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(\"yes\", 4, \"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(\"yes\", [ ], \"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(\"yes\", { }, \"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", true)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", 4)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", [ ])"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", { })"); } )); }, //////////////////////////////////////////////////////////////////////////////// @@ -454,7 +454,7 @@ function ahuacatlFunctionsTestSuite () { testCharLength1 : function () { var expected = [ 13 ]; - var actual = getQueryResults("FOR r IN [ 1 ] return CHARLENGTH('the quick fox')", true); + var actual = getQueryResults("FOR r IN [ 1 ] return CHAR_LENGTH('the quick fox')", true); assertEqual(expected, actual); }, @@ -464,7 +464,7 @@ function ahuacatlFunctionsTestSuite () { testCharLength2 : function () { var expected = [ 7 ]; - var actual = getQueryResults("FOR r IN [ 1 ] return CHARLENGTH('äöüÄÖÜß')", true); + var actual = getQueryResults("FOR r IN [ 1 ] return CHAR_LENGTH('äöüÄÖÜß')", true); assertEqual(expected, actual); }, @@ -474,7 +474,7 @@ function ahuacatlFunctionsTestSuite () { testCharLength3 : function () { var expected = [ 10 ]; - var actual = getQueryResults("FOR r IN [ 1 ] return CHARLENGTH('アボカド名称について')", true); + var actual = getQueryResults("FOR r IN [ 1 ] return CHAR_LENGTH('アボカド名称について')", true); assertEqual(expected, actual); }, @@ -483,13 +483,13 @@ function ahuacatlFunctionsTestSuite () { //////////////////////////////////////////////////////////////////////////////// testCharLengthInvalid : function () { - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHARLENGTH()"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHARLENGTH(\"yes\", \"yes\")"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHARLENGTH(null)"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHARLENGTH(true)"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHARLENGTH(3)"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHARLENGTH([ ])"); } )); - assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHARLENGTH({ })"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHAR_LENGTH()"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHAR_LENGTH(\"yes\", \"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHAR_LENGTH(null)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHAR_LENGTH(true)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHAR_LENGTH(3)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHAR_LENGTH([ ])"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN CHAR_LENGTH({ })"); } )); }, //////////////////////////////////////////////////////////////////////////////// @@ -990,6 +990,56 @@ function ahuacatlFunctionsTestSuite () { assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS({ }, { })"); } )); }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test not_null +//////////////////////////////////////////////////////////////////////////////// + + testNotNull1 : function () { + var expected = [ 6 ]; + var actual = getQueryResults("RETURN NOT_NULL(null, 2 + 4)", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test not_null +//////////////////////////////////////////////////////////////////////////////// + + testNotNull2 : function () { + var expected = [ 6 ]; + var actual = getQueryResults("RETURN NOT_NULL(2 + 4, 2 + 5)", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test not_null +//////////////////////////////////////////////////////////////////////////////// + + testNotNull3 : function () { + var expected = [ null ]; + var actual = getQueryResults("RETURN NOT_NULL(null, null)", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test not_null +//////////////////////////////////////////////////////////////////////////////// + + testNotNull4 : function () { + var expected = [ 2 ]; + var actual = getQueryResults("RETURN NOT_NULL(2, null)", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test not_null +//////////////////////////////////////////////////////////////////////////////// + + testNotNull5 : function () { + var expected = [ false ]; + var actual = getQueryResults("RETURN NOT_NULL(false, true)", true); + assertEqual(expected, actual); + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test non-existing functions //////////////////////////////////////////////////////////////////////////////// diff --git a/js/server/tests/ahuacatl-operators.js b/js/server/tests/ahuacatl-operators.js index e4f7e87fca..77e4a449cc 100644 --- a/js/server/tests/ahuacatl-operators.js +++ b/js/server/tests/ahuacatl-operators.js @@ -349,35 +349,6 @@ function ahuacatlOperatorsTestSuite () { assertFalse(AHUACATL_IS_DOCUMENT([ false ])); }, -//////////////////////////////////////////////////////////////////////////////// -/// @brief test AHUACATL_CAST_NULL function -//////////////////////////////////////////////////////////////////////////////// - - testCastNull : function () { - assertEqual(null, AHUACATL_CAST_NULL(undefined)); - assertEqual(null, AHUACATL_CAST_NULL(null)); - assertEqual(null, AHUACATL_CAST_NULL(1)); - assertEqual(null, AHUACATL_CAST_NULL(2)); - assertEqual(null, AHUACATL_CAST_NULL(-1)); - assertEqual(null, AHUACATL_CAST_NULL(0)); - assertEqual(null, AHUACATL_CAST_NULL(NaN)); - assertEqual(null, AHUACATL_CAST_NULL(true)); - assertEqual(null, AHUACATL_CAST_NULL(false)); - assertEqual(null, AHUACATL_CAST_NULL('')); - assertEqual(null, AHUACATL_CAST_NULL(' ')); - assertEqual(null, AHUACATL_CAST_NULL(' ')); - assertEqual(null, AHUACATL_CAST_NULL('1')); - assertEqual(null, AHUACATL_CAST_NULL('0')); - assertEqual(null, AHUACATL_CAST_NULL('-1')); - assertEqual(null, AHUACATL_CAST_NULL([ ])); - assertEqual(null, AHUACATL_CAST_NULL([ 0 ] )); - assertEqual(null, AHUACATL_CAST_NULL([ 0, 1 ] )); - assertEqual(null, AHUACATL_CAST_NULL([ 1, 2 ] )); - assertEqual(null, AHUACATL_CAST_NULL({ } )); - assertEqual(null, AHUACATL_CAST_NULL({ 'a' : true })); - assertEqual(null, AHUACATL_CAST_NULL({ 'a' : true, 'b' : 0 })); - }, - //////////////////////////////////////////////////////////////////////////////// /// @brief test AHUACATL_CAST_BOOL function ////////////////////////////////////////////////////////////////////////////////