diff --git a/BasicsC/vector.c b/BasicsC/vector.c index 9f2f6ac9a3..7fb71d54a3 100644 --- a/BasicsC/vector.c +++ b/BasicsC/vector.c @@ -240,6 +240,58 @@ void* TRI_AtVector (TRI_vector_t const* vector, size_t pos) { return (void*) (vector->_buffer + pos * vector->_elementSize); } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief inserts an element at a given position +//////////////////////////////////////////////////////////////////////////////// + +void TRI_InsertVector (TRI_vector_t* vector, void const* element, size_t position) { + char* newBuffer; + size_t newSize; + + // ........................................................................... + // Check and see if we need to extend the vector + // ........................................................................... + + if (vector->_length >= vector->_capacity || position >= vector->_length) { + newSize = (size_t) (1 + GROW_FACTOR * vector->_capacity); + + if (position >= newSize) { + newSize = position + 1; + } + + newBuffer = (char*) TRI_Allocate(vector->_memoryZone, newSize * vector->_elementSize, false); + + if (newBuffer == NULL) { + TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); + return; + } + + vector->_capacity = newSize; + + if (vector->_buffer != NULL) { + memcpy(newBuffer, vector->_buffer, vector->_length * vector->_elementSize); + TRI_Free(vector->_memoryZone, vector->_buffer); + } + + vector->_buffer = newBuffer; + } + + if (position < vector->_length) { + memmove(vector->_buffer + (vector->_elementSize * (position + 1)), + vector->_buffer + (vector->_elementSize * position), + vector->_elementSize * (vector->_length - position) + ); + vector->_length += 1; + } + else { + vector->_length = position + 1; + } + + memcpy(vector->_buffer + (vector->_elementSize * position), element, vector->_elementSize); +} + + //////////////////////////////////////////////////////////////////////////////// /// @brief sets an element at a given position //////////////////////////////////////////////////////////////////////////////// @@ -458,6 +510,11 @@ int TRI_PushBackVectorPointer (TRI_vector_pointer_t* vector, void* element) { //////////////////////////////////////////////////////////////////////////////// int TRI_InsertVectorPointer (TRI_vector_pointer_t* vector, void* element, size_t n) { + + // ........................................................................... + // Check and see if we need to extend the vector + // ........................................................................... + if (vector->_length >= vector->_capacity || n >= vector->_length) { void* newBuffer; size_t newSize = (size_t) (1 + GROW_FACTOR * vector->_capacity); @@ -728,6 +785,11 @@ int TRI_PushBackVectorString (TRI_vector_string_t* vector, char* element) { //////////////////////////////////////////////////////////////////////////////// int TRI_InsertVectorString (TRI_vector_string_t* vector, char* element, size_t n) { + + // ........................................................................... + // Check and see if we need to extend the vector + // ........................................................................... + if (n >= vector->_capacity || n >= vector->_length) { char** newBuffer; size_t newSize = (size_t) (1 + GROW_FACTOR * vector->_capacity); diff --git a/BasicsC/vector.h b/BasicsC/vector.h index 7bd3aa6072..4fb6ff1d02 100644 --- a/BasicsC/vector.h +++ b/BasicsC/vector.h @@ -146,6 +146,13 @@ void TRI_RemoveVector (TRI_vector_t*, size_t n); void* TRI_AtVector (TRI_vector_t const*, size_t); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief inserts an element at a given position +//////////////////////////////////////////////////////////////////////////////// + +void TRI_InsertVector (TRI_vector_t* vector, void const* element, size_t position); + //////////////////////////////////////////////////////////////////////////////// /// @brief sets an element at a given position //////////////////////////////////////////////////////////////////////////////// diff --git a/Doxygen/Examples.AvocadoDB/api-simple-by-example1 b/Doxygen/Examples.AvocadoDB/api-simple-by-example1 new file mode 100644 index 0000000000..5fd423b9a5 --- /dev/null +++ b/Doxygen/Examples.AvocadoDB/api-simple-by-example1 @@ -0,0 +1,18 @@ +> curl --data @- -X PUT --dump - http://localhost:8529/_api/simple/by-example +{ "collection" : "3179705695", "example" : [ { "i" : 1 } ] } + +HTTP/1.1 201 Created +content-type: application/json + +{ + "result": [ + { "a": { "k": 2, "j": 2 }, "i": 1, "_rev": 3181802847, "_id": "3179705695/3181802847" }, + { "a": { "j": 1 }, "i": 1, "_rev": 3181475167, "_id": "3179705695/3181475167" }, + { "a": { "k": 1, "j": 1 }, "i": 1, "_rev": 3181737311, "_id": "3179705695/3181737311" }, + { "i": 1, "_rev": 3181147487, "_id": "3179705695/3181147487" } + ], + "count": 4, + "error": false, + "hasMore": false, + "code": 201 +} diff --git a/Doxygen/Examples.AvocadoDB/api-simple-by-example2 b/Doxygen/Examples.AvocadoDB/api-simple-by-example2 new file mode 100644 index 0000000000..fbdc3d42ea --- /dev/null +++ b/Doxygen/Examples.AvocadoDB/api-simple-by-example2 @@ -0,0 +1,15 @@ +> curl --data @- -X PUT --dump - http://localhost:8529/_api/simple/by-example +{ "collection" : "3179705695", "example" : [ { "a" : { "j" : 1 } } ] } + +HTTP/1.1 201 Created +content-type: application/json + +{ + "result": [ + { "a": { "j": 1 }, "i": 1, "_rev": 3181475167, "_id": "3179705695/3181475167" } + ], + "count": 1, + "error": false, + "hasMore": false, + "code": 201 +} diff --git a/Doxygen/Examples.AvocadoDB/api-simple-by-example3 b/Doxygen/Examples.AvocadoDB/api-simple-by-example3 new file mode 100644 index 0000000000..8d06c268d4 --- /dev/null +++ b/Doxygen/Examples.AvocadoDB/api-simple-by-example3 @@ -0,0 +1,16 @@ +> curl --data @- -X PUT --dump - http://localhost:8529/_api/simple/by-example +{ "collection" : "3179705695", "example" : [ "a.j", 1 ] } + +HTTP/1.1 201 Created +content-type: application/json + +{ + "result": [ + { "a": { "j": 1 }, "i": 1, "_rev": 3181475167, "_id": "3179705695/3181475167" }, + { "a": { "k": 1, "j": 1 }, "i": 1, "_rev": 3181737311, "_id": "3179705695/3181737311" } + ], + "count": 2, + "error": false, + "hasMore": false, + "code": 201 +} diff --git a/Doxygen/Examples.AvocadoDB/api-simple-first-example b/Doxygen/Examples.AvocadoDB/api-simple-first-example new file mode 100644 index 0000000000..3edf309b4c --- /dev/null +++ b/Doxygen/Examples.AvocadoDB/api-simple-first-example @@ -0,0 +1,11 @@ +> curl --data @- -X PUT --dump - http://localhost:8529/_api/simple/first-example +{ "collection" : "666351134", "example" : [ "a.j", 1, "a.k", 1 ] } + +HTTP/1.1 200 OK +content-type: application/json + +{ + "error": false, + "code": 200, + "document": { "_rev": 668382750, "_id": "666351134/668382750", "a": { "k": 1, "j": 1, "l" : 10 }, "i": 1 } +} diff --git a/Doxygen/Examples.AvocadoDB/api-simple-first-example-not-found b/Doxygen/Examples.AvocadoDB/api-simple-first-example-not-found new file mode 100644 index 0000000000..d4e2362ac9 --- /dev/null +++ b/Doxygen/Examples.AvocadoDB/api-simple-first-example-not-found @@ -0,0 +1,12 @@ +> curl --data @- -X PUT --dump - http://localhost:8529/_api/simple/first-example +{ "collection" : "666351134", "example" : [ "a.j", 1, "a.k", 2 ] } + +HTTP/1.1 404 Not Found +content-type: application/json + +{ + "errorMessage": "no match", + "error": true, + "code": 404, + "errorNum": 404 +} diff --git a/Doxygen/Examples.Durham/jsunity1 b/Doxygen/Examples.Durham/jsunity1 index 9945cc0fb5..0afbde7e10 100644 --- a/Doxygen/Examples.Durham/jsunity1 +++ b/Doxygen/Examples.Durham/jsunity1 @@ -1,7 +1,10 @@ function aqlTestSuite () { - function testSizeOfTestCollection () { - assertEqual(5, 5); - } + return { + testSizeOfTestCollection : function () { + assertEqual(5, 5); + }; } jsUnity.run(aqlTestSuite); + +return jsunity.done(); diff --git a/Doxygen/Examples.Durham/shell-collection-count b/Doxygen/Examples.Durham/shell-collection-count new file mode 100644 index 0000000000..f00bebf9f4 --- /dev/null +++ b/Doxygen/Examples.Durham/shell-collection-count @@ -0,0 +1,2 @@ +avocado> db.users.count(); +10001 diff --git a/Doxygen/Examples.Durham/shell-simple-query-first-example b/Doxygen/Examples.Durham/shell-simple-query-first-example new file mode 100644 index 0000000000..a3fc53e8f1 --- /dev/null +++ b/Doxygen/Examples.Durham/shell-simple-query-first-example @@ -0,0 +1,2 @@ +avocado> db.users.firstExample("name", 1237); +{ "_id" : "100225/83049373", "_rev" : 83049373, "name" : 1237 } diff --git a/Doxygen/Scripts/html2html.sh b/Doxygen/Scripts/html2html.sh index 1e90609100..6abcb219f6 100755 --- a/Doxygen/Scripts/html2html.sh +++ b/Doxygen/Scripts/html2html.sh @@ -11,6 +11,6 @@ fi HEADER='AvocadoDB Manual
AvocadoDB
' FOOTER='
' -sed -e "s~<\\?php include \"include/header.php\" \\?> ~${HEADER}~" $INPUT \ - | sed -e "s~<\\?php include \"include/footer.php\" \\?> ~${FOOTER}~" \ +sed -e "s~ ~${HEADER}~" $INPUT \ + | sed -e "s~ ~${FOOTER}~" \ | sed -e "s~
\\([^<]*\\)
~

\\1

~" > $OUTPUT diff --git a/Makefile.files b/Makefile.files index 3b55560f7d..2fd6ec5584 100644 --- a/Makefile.files +++ b/Makefile.files @@ -410,6 +410,8 @@ WIKI = \ ShellIndex \ SimpleQueries \ UserManualServer \ + UserManualServerBasics \ + UserManualServerStartStop \ UserManualShell \ UserManualShellStartStop \ jsUnity diff --git a/Makefile.in b/Makefile.in index 68d9cca686..ee9448db92 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1011,6 +1011,8 @@ WIKI = \ ShellIndex \ SimpleQueries \ UserManualServer \ + UserManualServerBasics \ + UserManualServerStartStop \ UserManualShell \ UserManualShellStartStop \ jsUnity diff --git a/Makefile.local b/Makefile.local index d355b69a4b..63496384e0 100755 --- a/Makefile.local +++ b/Makefile.local @@ -11,6 +11,6 @@ MANUAL_DST="fceller@www.avocadodb.org:/srv/www/www.avocadodb.org/avoc/manuals" publish: (cd Doxygen/wiki && git checkout --force && git pull) $(MAKE) wiki - (cd Doxygen/wiki && git commit -m "`date`" -a; git push) + (cd Doxygen/wiki && git add *.md; git commit -m "`date`" -a; git push) @for w in $(WIKI); do scp Doxygen/html/$$w.html $(MANUAL_DST); done diff --git a/RestServer/api-index.dox b/RestServer/api-index.dox index 65e6e587f7..2480a3fea9 100644 --- a/RestServer/api-index.dox +++ b/RestServer/api-index.dox @@ -52,7 +52,7 @@ /// @page HttpIndex HTTP Interface for Indexes /// /// This is an introduction to AvocadoDB's Http interface for indexes in -/// general. There are special section for +/// general. There are special sections for /// /// @copydoc IndexesTOC /// diff --git a/RestServer/api-simple.dox b/RestServer/api-simple.dox index e208328b4f..d5657ab544 100644 --- a/RestServer/api-simple.dox +++ b/RestServer/api-simple.dox @@ -41,6 +41,8 @@ /// ///
    ///
  1. @ref HttpSimpleAll "POST /_api/simple/all"
  2. +///
  3. @ref HttpSimpleByExample "POST /_api/simple/by-example"
  4. +///
  5. @ref HttpSimpleFirstExample "POST /_api/simple/first-example"
  6. ///
  7. @ref HttpSimpleNear "POST /_api/simple/near"
  8. ///
  9. @ref HttpSimpleWithin "POST /_api/simple/within"
  10. ///
@@ -71,13 +73,20 @@ /// @copydetails JSA_PUT_api_simple_all ///
/// +/// @anchor HttpSimpleByExample +/// @copydetails JSA_PUT_api_simple_by_example +///
+/// +/// @anchor HttpSimpleFirstExample +/// @copydetails JSA_PUT_api_simple_first_example +///
+/// /// @anchor HttpSimpleNear /// @copydetails JSA_PUT_api_simple_near ///
/// /// @anchor HttpSimpleWithin /// @copydetails JSA_PUT_api_simple_within -///
//////////////////////////////////////////////////////////////////////////////// // Local Variables: diff --git a/RestServer/home.dox b/RestServer/home.dox index c4600415e4..edc932cca8 100644 --- a/RestServer/home.dox +++ b/RestServer/home.dox @@ -74,9 +74,6 @@ /// /// @subsection HomePython Python /// -/// Help wanted: -/// http://www.avocadodb.org/2012/03/24/contributors-for-python-api-wanted-for-nosql-project -/// /// @subsection HomeREST REST /// /// @subsection HomeRuby Ruby diff --git a/RestServer/install-manual.dox b/RestServer/install-manual.dox index c5e74f4283..1b33c33a66 100644 --- a/RestServer/install-manual.dox +++ b/RestServer/install-manual.dox @@ -29,10 +29,8 @@ /// @page InstallManual AvocadoDB Installation Manual /// ///
    -///
  1. @ref Installing -///
  2. -///
  3. @ref Compiling -///
  4. +///
  5. @ref Installing
  6. +///
  7. @ref Compiling
  8. ///
//////////////////////////////////////////////////////////////////////////////// @@ -56,7 +54,7 @@ /// @page Installing Installing the AvocadoDB /// ///
-/// @copydoc CompilingTOC +/// @copydoc InstallingTOC ///
/// /// @section MacOSX diff --git a/RestServer/module-jsunity.dox b/RestServer/module-jsunity.dox new file mode 100644 index 0000000000..cad0f4cc06 --- /dev/null +++ b/RestServer/module-jsunity.dox @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief module "internal" +/// +/// @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 Dr. Frank Celler +/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @page jsUnity Using jsUnity and node-jscoverage +/// +/// The AvocadoDB contains a wrapper for +/// jsUnity, a lightyweight universal +/// JavAScript unit testing framework. +/// +/// @section jsUnityRunningTest Running jsUnity Tests +///////////////////////////////////////////////////// +/// +/// Assume that you have a test file containing +/// +/// @verbinclude jsunity1 +/// +/// Then you can run the test suite using @FN{jsunity.runTest} +/// +/// @verbinclude jsunity2 +/// +/// @section jsUnityRunningCoverage Running jsUnity Tests with Coverage +/////////////////////////////////////////////////////////////////////// +/// +/// You can use the coverage tool +/// @LIT{node-jscoverage}. +/// +/// Assume that your file live in a directory called @LIT{lib}. Use +/// +/// @CODE{node-jscoverage lib lib-cov} +/// +/// to create a copy of the JavaScript files with coverage information. Start +/// the AvocadoDB with these files and use @FN{jsunity.runCoverage} instead of +/// @FN{jsunity.runTest}. +//////////////////////////////////////////////////////////////////////////////// + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @\\}\\)" +// End: diff --git a/RestServer/otwp.dox b/RestServer/otwp.dox index 81b2e6be73..aebdad40f7 100644 --- a/RestServer/otwp.dox +++ b/RestServer/otwp.dox @@ -60,22 +60,18 @@ ///
  • @ref HttpSystem /// @copydetails HttpSystemTOC ///
  • -///
  • @ref OTWPSimpleQueries -///
      -///
    1. @ref OTWPSimpleQueriesByExample "PUT /_api/simple/by-example"
    2. -///
    -///
  • -///
  • @ref Key-Value -///
      -///
    1. @ref Key-ValuePost "POST /_api/key/@FA{collection-name}/@FA{key}"
    2. -///
    3. @ref Key-ValuePut "PUT /_api/key/@FA{collection-name}/@FA{key}"
    4. -///
    5. @ref Key-ValueGet "GET /_api/key/@FA{collection-name}/@FA{key}"
    6. -///
    7. @ref Key-ValueDelete "DELETE /_api/key/@FA{collection-name}/@FA{key}"
    8. -///
    9. @ref Key-ValueSearch "GET /_api/keys/@FA{collection-name}/@FA{prefix}"
    10. -///
    ///
  • /// /// +///
  • @ref Key-Value (Under Construction) +///
      +///
    1. @ref Key-ValuePost "POST /_api/key/collection-name/key"
    2. +///
    3. @ref Key-ValuePut "PUT /_api/key/collection-name/key"
    4. +///
    5. @ref Key-ValueGet "GET /_api/key/collection-name/key"
    6. +///
    7. @ref Key-ValueDelete "DELETE /_api/key/collection-name/key"
    8. +///
    9. @ref Key-ValueSearch "GET /_api/keys/collection-name/prefix"
    10. +///
    +///
  • /// //////////////////////////////////////////////////////////////////////////////// @@ -85,14 +81,6 @@ ///
    /// @copydoc OTWPTOC ///
    -/// -/// @section OTWPSimpleQueries Simple Queries -///////////////////////////////////////////// -/// -/// @anchor OTWPSimpleQueriesByExample -/// @copydetails JSA_PUT_api_simple_by_example -///
    -/// //////////////////////////////////////////////////////////////////////////////// // Local Variables: diff --git a/RestServer/simple-queries.dox b/RestServer/simple-queries.dox index 36c12c5c0a..1f01952b82 100644 --- a/RestServer/simple-queries.dox +++ b/RestServer/simple-queries.dox @@ -31,36 +31,39 @@ ///
      ///
    1. @ref SimpleQueriesQueries ///
        -///
      1. @ref SimpleQueryDocument "db.@FA{collection}.document(@FA{document-reference})"
      2. -///
      3. @ref SimpleQueryAll "db.@FA{collection}.all()"
      4. -///
      5. @ref SimpleQueryByExample "db.@FA{collection}.byExample()"
      6. -///
      7. @ref SimpleQueryCount "@FA{query}.count()"
      8. +///
      9. @ref SimpleQueryDocument "collection.document(document-reference)"
      10. +///
      11. @ref SimpleQueryAll "collection.all()"
      12. +///
      13. @ref SimpleQueryByExample "collection.byExample(example)"
      14. +///
      15. @ref SimpleQueryFirstExample "collection.firstExample(example)"
      16. +///
      17. @ref SimpleQueryCollectionCount "collection.count()"
      18. +///
      19. @ref SimpleQueryToArray "collection.toArray()"
      20. ///
      ///
    2. ///
    3. @ref SimpleQueriesGeoQueries ///
        -///
      1. @ref SimpleQueryNear "db.@FA{collection}.near()"
      2. -///
      3. @ref SimpleQueryWithin "db.@FA{collection}.within()"
      4. -///
      5. @ref SimpleQueryGeo "db.@FA{collection}.geo()"
      6. +///
      7. @ref SimpleQueryNear "collection.near(latitude, longitude)"
      8. +///
      9. @ref SimpleQueryWithin "collection.within(latitude, longitude)"
      10. +///
      11. @ref SimpleQueryGeo "collection.geo(location)"
      12. ///
      ///
    4. ///
    5. @ref SimpleQueriesEdgesQueries ///
        -///
      1. @ref SimpleQueryEdges "edges.@FA{collection}.edges()"
      2. -///
      3. @ref SimpleQueryInEdges "edges.@FA{collection}.inEdges()"
      4. -///
      5. @ref SimpleQueryOutEdges "edges.@FA{collection}.outEdges()"
      6. +///
      7. @ref SimpleQueryEdges "edges-collection.edges(vertex)"
      8. +///
      9. @ref SimpleQueryInEdges "edges-collection.inEdges(vertex)"
      10. +///
      11. @ref SimpleQueryOutEdges "edges-collection.outEdges(vertex)"
      12. ///
      ///
    6. ///
    7. @ref SimpleQueriesPagination ///
        -///
      1. @ref SimpleQueryLimit "@FA{query}.limit(@FA{limit})"
      2. -///
      3. @ref SimpleQuerySkip "@FA{query}.skip(@FA{skip})"
      4. +///
      5. @ref SimpleQueryLimit "query.limit(limit)"
      6. +///
      7. @ref SimpleQuerySkip "query.skip(skip)"
      8. ///
      ///
    8. ///
    9. @ref SimpleQueriesSequentialAccess ///
        -///
      1. @ref SimpleQueryHasNext "@FA{query}.hasNext()"
      2. -///
      3. @ref SimpleQueryNext "@FA{query}.next()"
      4. +///
      5. @ref SimpleQueryHasNext "query.hasNext()"
      6. +///
      7. @ref SimpleQueryNext "query.next()"
      8. +///
      9. @ref SimpleQueryCount "query.count()"
      10. ///
      ///
    10. ///
    @@ -72,17 +75,20 @@ /// Simple queries can be used if the query condition is straight forward /// simple, i. e., a document reference, all documents, a query-by-example, or a /// simple geo query. In a simple query you can specify exactly one collection -/// and one condition. The result can then be sorted and result can be split -/// into pages. +/// and one condition. /// ///
    /// @copydoc SimpleQueriesTOC ///
    /// +/// If a query returns a cursor, then you can use @FN{hasNext} and @FN{next} to +/// iterate over the result set or @FN{toArray} to convert it to an array. +/// /// @section SimpleQueriesQueries Queries ///////////////////////////////////////// /// /// @anchor SimpleQueryDocument +/// @copydetails JS_DocumentVocbaseCol ///
    /// /// @anchor SimpleQueryAll @@ -93,8 +99,16 @@ /// @copydetails JSF_AvocadoCollection_prototype_byExample ///
    /// -/// @anchor SimpleQueryCount -/// @copydetails JSF_SimpleQuery_prototype_count +/// @anchor SimpleQueryFirstExample +/// @copydetails JSF_AvocadoCollection_prototype_firstExample +///
    +/// +/// @anchor SimpleQueryCollectionCount +/// @copydetails JS_CountVocbaseCol +///
    +/// +/// @anchor SimpleQueryToArray +/// @copydetails JSF_AvocadoCollection_prototype_toArray /// /// @section SimpleQueriesGeoQueries Geo Queries //////////////////////////////////////////////// @@ -148,7 +162,7 @@ /// If, for example, you display the result of a user search, then you are in /// general not interested in the completed result set, but only the first 10 or /// so documents. Or maybe the next 10 documents for the second page. In this -/// case, you can the @FN{skip} and @FN{limit} operators. These operators works +/// case, you can the @FN{skip} and @FN{limit} operators. These operators work /// like LIMIT in MySQL. /// /// @FN{skip} used together with @FN{limit} can be used to implement pagination. @@ -174,6 +188,10 @@ /// /// @anchor SimpleQueryNext /// @copydetails JSF_SimpleQuery_prototype_next +///
    +/// +/// @anchor SimpleQueryCount +/// @copydetails JSF_SimpleQuery_prototype_count //////////////////////////////////////////////////////////////////////////////// // Local Variables: diff --git a/RestServer/user-manual-server.dox b/RestServer/user-manual-server.dox index 9ccde65c50..97bedbdd6f 100644 --- a/RestServer/user-manual-server.dox +++ b/RestServer/user-manual-server.dox @@ -33,12 +33,6 @@ ///
      ///
    1. @ref UserManualServerStartStop ///
    2. -///
    3. AvocadoScript -///
        -///
      1. @ref SimpleQueries -///
      2. -///
      -///
    4. ///
    5. Avocado Query Language ///
        ///
      1. @ref AQLBasics @@ -49,47 +43,18 @@ ///
      2. ///
      ///
    6. -///
    7. @ref AvocadoScript -///
        -///
      1. GeoCoordinates -///
      2. -///
      -///
    8. -///
    9. Vertices, Edges, and Graphs -///
        -///
      1. @ref Graphs -///
      2. -///
      3. @ref JSModuleGraph -///
      4. -///
      -///
    10. ///
    11. @ref AvocadoErrors ///
    12. ///
    /// -///
  • Client Communication -///
      -///
    1. @ref HttpInterface -///
        -///
      1. @ref RestDocument -///
      2. -///
      -///
    2. -///
    -///
  • -///
  • @ref DBAdmin -///
      -///
    1. @ref DBAdminDurability -///
    2. -///
    3. @ref DBAdminIndex -///
        -///
      1. @ref DBAdminIndexGeo -///
      -///
    4. -///
    -///
  • ///
  • Advanced Topics ///
      +///
    1. @ref DBAdmin +///
        +///
      1. @ref DBAdminDurability +///
      2. +///
      +///
    2. ///
    3. Actions ///
        ///
      1. @ref Actions @@ -98,12 +63,6 @@ ///
      2. ///
      ///
    4. -///
    5. @ref HttpInterface -///
        -///
      1. @ref RestSystem -///
      2. -///
      -///
    6. ///
    7. @ref jsUnity ///
    8. ///
    @@ -128,20 +87,21 @@ /// @page UserManualServerStartStopTOC /// ///
      -///
    1. @ref UserManualServerStartStopHttp "Starting the HTTP Server"
    2. -///
    3. @ref UserManualServerStartStopDebug "Starting the Debug Shell"
    4. -///
    5. @ref UserManualServerStartStopOptions "Frequently Used Options"
    6. +///
    7. @ref UserManualServerStartStopHttp
    8. +///
    9. @ref UserManualServerStartStopDebug
    10. +///
    11. @ref UserManualServerStartStopOptions
    12. ///
    //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @page UserManualServerStartStop Starting the AvocadoDB /// -/// The AvocadoDB has two mode of operation: as server, where it will answer to -/// HTTP requests, see @ref HttpInterface, and a debug shell, where you can -/// access the database directly. Using the debug shell allows you to issue all -/// commands normally available in actions and transactions, see @ref -/// AvocadoScript. +/// The AvocadoDB has two modes of operation: as server, where it will answer to +/// client requests and an emergency console, where you can access the database +/// directly. The latter should - as the name suggests - only be used in case of +/// an emergency, for example, a corrupted collection. Using the emergency +/// console allows you to issue all commands normally available in actions and +/// transactions. /// /// You should never start more than one server for the same database, /// independent from the mode of operation. @@ -151,6 +111,7 @@ ///
    /// /// @section UserManualServerStartStopHttp Starting the HTTP Server +/////////////////////////////////////////////////////////////////// /// /// The following command starts the AvocadoDB in server mode. You will be able /// to access the server using HTTP request on port 8529. See below for a list @@ -158,14 +119,16 @@ /// /// @verbinclude option-database-directory /// -/// @section UserManualServerStartStopDebug Starting the Debug Shell +/// @section UserManualServerStartStopDebug Starting the Emergency Console +////////////////////////////////////////////////////////////////////////// /// -/// The following command starts a debug shell. See below for a list of +/// The following command starts a emergency console. See below for a list of /// frequently used options, see @ref CommandLine "here" for a complete list. /// /// @verbinclude start1 /// /// @section UserManualServerStartStopOptions Frequently Used Options +///////////////////////////////////////////////////////////////////// /// /// The following command-line options are frequently used. For a full /// list of options see @ref CommandLine "here". @@ -198,11 +161,6 @@ ///
      ///
    1. @ref DBAdminDurability ///
    2. -///
    3. @ref DBAdminIndex -///
        -///
      1. @ref DBAdminIndexGeo -///
      -///
    4. ///
    //////////////////////////////////////////////////////////////////////////////// @@ -214,8 +172,10 @@ ///
    /// /// @section DBAdminDurability Durability +///////////////////////////////////////// /// /// @subsection DBAdminDurability1 Mostly Memory/Durability +/////////////////////////////////////////////////////////// /// /// Database documents are stored in the memory-memory-mapped files are used to /// store them. The operating system has the advantageous option to decide @@ -224,6 +184,7 @@ /// documents securely at once (durability). /// /// @subsection DBAdminDurability2 AppendOnly/MVCC +////////////////////////////////////////////////// /// /// Instead of overwriting existing documents, a completely new version of the /// document is generated. The two benefits are: @@ -237,18 +198,9 @@ /// processes. /// /// @subsection DBAdminDurability3 Configuration +//////////////////////////////////////////////// /// /// @copydetails JS_PropertiesVocbaseCol -/// -/// @section DBAdminIndex Index Management -/// -/// @subsection DBAdminIndexHash Hash Indexes -/// -/// copydetails JS_EnsureHashIndexVocbaseCol -/// -/// @subsection DBAdminIndexGeo Geo Indexes -/// -/// copydetails JS_EnsureGeoIndexVocbaseCol //////////////////////////////////////////////////////////////////////////////// // Local Variables: diff --git a/ShapedJson/json-shaper.c b/ShapedJson/json-shaper.c index 82bb751bbd..1b5ac0c335 100644 --- a/ShapedJson/json-shaper.c +++ b/ShapedJson/json-shaper.c @@ -74,6 +74,8 @@ typedef struct array_shaper_s { TRI_associative_pointer_t _shapeDictionary; TRI_vector_pointer_t _shapes; + + // todo: add attribute weight structure } array_shaper_t; @@ -402,6 +404,12 @@ static char const* LookupAttributeIdArrayShaper (TRI_shaper_t* shaper, TRI_shape return NULL; } +static int64_t LookupAttributeWeight (TRI_shaper_t* shaper, TRI_shape_aid_t aid) { + // todo: add support for an attribute weight + assert(0); + return -1; +} + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// @@ -559,7 +567,8 @@ TRI_shaper_t* TRI_CreateArrayShaper (TRI_memory_zone_t* zone) { shaper->base.lookupAttributeId = LookupAttributeIdArrayShaper; shaper->base.findShape = FindShapeShape; shaper->base.lookupShapeId = LookupShapeId; - + shaper->base.lookupAttributeWeight = LookupAttributeWeight; + // handle basics ok = TRI_InsertBasicTypesShaper(&shaper->base); diff --git a/ShapedJson/json-shaper.h b/ShapedJson/json-shaper.h index fd35a7a976..a30ecaadba 100644 --- a/ShapedJson/json-shaper.h +++ b/ShapedJson/json-shaper.h @@ -60,7 +60,7 @@ typedef struct TRI_shaper_s { char const* (*lookupAttributeId) (struct TRI_shaper_s*, TRI_shape_aid_t); TRI_shape_t const* (*findShape) (struct TRI_shaper_s*, TRI_shape_t*); TRI_shape_t const* (*lookupShapeId) (struct TRI_shaper_s*, TRI_shape_sid_t); - + int64_t (*lookupAttributeWeight) (struct TRI_shaper_s*, TRI_shape_aid_t); TRI_shape_path_t const* (*lookupAttributePathByPid) (struct TRI_shaper_s*, TRI_shape_pid_t); TRI_shape_pid_t (*findAttributePathByName) (struct TRI_shaper_s*, char const*); diff --git a/SkipLists/compare.h b/SkipLists/compare.h index 7145062a29..392ed8ad4a 100755 --- a/SkipLists/compare.h +++ b/SkipLists/compare.h @@ -469,7 +469,22 @@ static int CompareShapedJsonShapedJson (const TRI_shaped_json_t* left, const TRI } result = CompareShapeTypes (left, right, leftShaper, rightShaper); - + + + // ............................................................................ + // In the above function CompareShaeTypes we use strcmp which may return + // an integer greater than 1 or less than -1. From this function we only + // need to know whether we have equality (0), less than (-1) or greater than (1) + // ............................................................................ + + if (result < 0) { + result = -1; + } + else if (result > 0) { + result = 1; + } + + return result; } // end of function CompareShapedJsonShapedJson @@ -718,7 +733,16 @@ static int IndexStaticMultiCompareElementElement (TRI_skiplist_multi_t* multiSki for (j = 0; j < hLeftElement->numFields; j++) { compareResult = CompareShapedJsonShapedJson((j + hLeftElement->fields), (j + hRightElement->fields), leftShaper, rightShaper); if (compareResult != 0) { + + // ...................................................................... + // The function CompareShaedJsonShapedJson can only return 0, -1, or 1 + // that is, TRI_SKIPLIST_COMPARE_STRICTLY_EQUAL (0) + // TRI_SKIPLIST_COMPARE_STRICTLY_LESS (-1) + // TRI_SKIPLIST_COMPARE_STRICTLY_GREATER (1) + // ...................................................................... + return compareResult; + } } diff --git a/SkipLists/skiplist.c b/SkipLists/skiplist.c index 057d41c3b2..cbbf743c34 100755 --- a/SkipLists/skiplist.c +++ b/SkipLists/skiplist.c @@ -25,9 +25,10 @@ /// @author Copyright 2006-2012, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -#include "skiplist.h" +#include #include +#include "skiplist.h" #include "compare.h" #define SKIPLIST_ABSOLUTE_MAX_HEIGHT 100 @@ -340,11 +341,11 @@ void TRI_InitSkipList (TRI_skiplist_t* skiplist, size_t elementSize, } // .......................................................................... - // Assign the comparision call back functions + // Assign the STATIC comparision call back functions // .......................................................................... - skiplist->compareElementElement = compareElementElement; - skiplist->compareKeyElement = compareKeyElement; + skiplist->compareElementElement = IndexStaticCompareElementElement; // compareElementElement; + skiplist->compareKeyElement = IndexStaticCompareKeyElement; // compareKeyElement; // .......................................................................... // Assign the maximum height of the skip list. This maximum height must be @@ -352,7 +353,7 @@ void TRI_InitSkipList (TRI_skiplist_t* skiplist, size_t elementSize, // .......................................................................... skiplist->_base._maxHeight = maximumHeight; if (maximumHeight > SKIPLIST_ABSOLUTE_MAX_HEIGHT) { - printf("%s:%d:Invalid maximum height for skiplist\n",__FILE__,__LINE__); + LOG_ERROR("Invalid maximum height for skiplist", TRI_ERROR_INTERNAL); assert(false); } @@ -1290,7 +1291,7 @@ void* TRI_RightLookupByKeySkipList (TRI_skiplist_t* skiplist, void* key) { // Use the callback to determine if the element is less or greater than // the next node element. // ....................................................................... - compareResult = IndexStaticCompareKeyElement(skiplist,key,&(prevNode->_element), 1); + compareResult = IndexStaticCompareKeyElement(skiplist, key, &(prevNode->_element), 1); // ....................................................................... @@ -1311,7 +1312,7 @@ void* TRI_RightLookupByKeySkipList (TRI_skiplist_t* skiplist, void* key) { } // ....................................................................... - // The element is greater than the next node element. Keep going on this + // The key is greater than the next node element. Keep going on this // level. // ....................................................................... if (compareResult < 0) { @@ -1399,9 +1400,9 @@ void TRI_InitSkipListMulti (TRI_skiplist_multi_t* skiplist, // Assign the comparision call back functions // .......................................................................... - skiplist->compareElementElement = compareElementElement; - skiplist->compareKeyElement = compareKeyElement; - skiplist->equalElementElement = equalElementElement; + skiplist->compareElementElement = IndexStaticMultiCompareElementElement; //compareElementElement; + skiplist->compareKeyElement = IndexStaticMultiCompareKeyElement; // compareKeyElement; + skiplist->equalElementElement = IndexStaticMultiEqualElementElement; //equalElementElement; // .......................................................................... // Assign the maximum height of the skip list. This maximum height must be @@ -1409,7 +1410,7 @@ void TRI_InitSkipListMulti (TRI_skiplist_multi_t* skiplist, // .......................................................................... skiplist->_base._maxHeight = maximumHeight; if (maximumHeight > SKIPLIST_ABSOLUTE_MAX_HEIGHT) { - printf("%s:%d:Invalid maximum height for skiplist\n",__FILE__,__LINE__); + LOG_ERROR("Invalid maximum height for skiplist", TRI_ERROR_INTERNAL); assert(false); } @@ -2114,7 +2115,7 @@ int TRI_RemoveElementSkipListMulti (TRI_skiplist_multi_t* skiplist, void* elemen } // ..................................................................... - // The element could be located and we are at the lowest level + // The element could be located (by matching the key) and we are at the lowest level // ..................................................................... if (compareResult == TRI_SKIPLIST_COMPARE_SLIGHTLY_LESS) { goto END; @@ -2163,7 +2164,7 @@ int TRI_RemoveElementSkipListMulti (TRI_skiplist_multi_t* skiplist, void* elemen // .......................................................................... if (old != NULL) { - memcpy(old, &(currentNode->_element), skiplist->_base._elementSize); + IndexStaticCopyElementElement(&(skiplist->_base), old, &(currentNode->_element)); } diff --git a/SkipLists/skiplistIndex.c b/SkipLists/skiplistIndex.c index 09c6a2e1b9..ccfcd9733a 100755 --- a/SkipLists/skiplistIndex.c +++ b/SkipLists/skiplistIndex.c @@ -1150,6 +1150,8 @@ static bool multiSkiplistIndex_findHelperIntervalValid(SkiplistIndex* skiplistIn compareResult = skiplistIndex->skiplist.nonUniqueSkiplist->compareKeyElement( skiplistIndex->skiplist.nonUniqueSkiplist, &(lNode->_element), &(rNode->_element), 0); + + return (compareResult == -1); } @@ -1292,6 +1294,7 @@ TRI_skiplist_iterator_t* MultiSkiplistIndex_find(SkiplistIndex* skiplistIndex, T if (results == NULL) { return NULL; } + results->_index = skiplistIndex; TRI_InitVector(&(results->_intervals), TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_skiplist_iterator_interval_t)); results->_currentInterval = 0; diff --git a/UnitTests/HttpInterface/api-simple-spec.rb b/UnitTests/HttpInterface/api-simple-spec.rb index d758a3a301..3496ed3fee 100644 --- a/UnitTests/HttpInterface/api-simple-spec.rb +++ b/UnitTests/HttpInterface/api-simple-spec.rb @@ -109,10 +109,6 @@ describe AvocadoDB do AvocadoDB.drop_collection(@cn) @cid = AvocadoDB.create_collection(@cn, false) - cmd = api + "?collection=#{@cid}" - body = "{ \"type\" : \"geo\", \"fields\" : [ \"a\" ] }" - #doc = AvocadoDB.post(cmd, :body => body) - (0..10).each{|i| lat = 10 * (i - 5) @@ -189,10 +185,6 @@ describe AvocadoDB do AvocadoDB.drop_collection(@cn) @cid = AvocadoDB.create_collection(@cn, false) - cmd = api + "?collection=#{@cid}" - body = "{ \"type\" : \"geo\", \"fields\" : [ \"a\" ] }" - #doc = AvocadoDB.post(cmd, :body => body) - (0..10).each{|i| lat = 10 * (i - 5) @@ -259,5 +251,116 @@ describe AvocadoDB do end end +################################################################################ +## by-example query +################################################################################ + + context "by-example query:" do + before do + @cn = "UnitTestsCollectionByExample" + AvocadoDB.drop_collection(@cn) + @cid = AvocadoDB.create_collection(@cn, false) + end + + after do + AvocadoDB.drop_collection(@cn) + end + + it "finds the examples" do + body = "{ \"i\" : 1 }" + doc = AvocadoDB.post("/document?collection=#{@cid}", :body => body) + doc.code.should eq(202) + d1 = doc.parsed_response['_id'] + + body = "{ \"i\" : 1, \"a\" : { \"j\" : 1 } }" + doc = AvocadoDB.post("/document?collection=#{@cid}", :body => body) + doc.code.should eq(202) + d2 = doc.parsed_response['_id'] + + body = "{ \"i\" : 1, \"a\" : { \"j\" : 1, \"k\" : 1 } }" + doc = AvocadoDB.post("/document?collection=#{@cid}", :body => body) + doc.code.should eq(202) + d3 = doc.parsed_response['_id'] + + body = "{ \"i\" : 1, \"a\" : { \"j\" : 2, \"k\" : 2 } }" + doc = AvocadoDB.post("/document?collection=#{@cid}", :body => body) + doc.code.should eq(202) + d4 = doc.parsed_response['_id'] + + body = "{ \"i\" : 2 }" + doc = AvocadoDB.post("/document?collection=#{@cid}", :body => body) + doc.code.should eq(202) + d5 = doc.parsed_response['_id'] + + body = "{ \"i\" : 2, \"a\" : 2 }" + doc = AvocadoDB.post("/document?collection=#{@cid}", :body => body) + doc.code.should eq(202) + d6 = doc.parsed_response['_id'] + + body = "{ \"i\" : 2, \"a\" : { \"j\" : 2, \"k\" : 2 } }" + doc = AvocadoDB.post("/document?collection=#{@cid}", :body => body) + doc.code.should eq(202) + d7 = doc.parsed_response['_id'] + + cmd = api + "/by-example" + body = "{ \"collection\" : \"#{@cid}\", \"example\" : [ { \"i\" : 1 } ] }" + doc = AvocadoDB.log_put("#{prefix}-by-example1", cmd, :body => body) + + doc.code.should eq(201) + doc.headers['content-type'].should eq("application/json") + doc.parsed_response['error'].should eq(false) + doc.parsed_response['code'].should eq(201) + doc.parsed_response['hasMore'].should eq(false) + doc.parsed_response['result'].length.should eq(4) + doc.parsed_response['count'].should eq(4) + doc.parsed_response['result'].map{|i| i['_id']}.should =~ [d1,d2,d3,d4] + + cmd = api + "/by-example" + body = "{ \"collection\" : \"#{@cid}\", \"example\" : [ { \"a\" : { \"j\" : 1 } } ] }" + doc = AvocadoDB.log_put("#{prefix}-by-example2", cmd, :body => body) + + doc.code.should eq(201) + doc.headers['content-type'].should eq("application/json") + doc.parsed_response['error'].should eq(false) + doc.parsed_response['code'].should eq(201) + doc.parsed_response['hasMore'].should eq(false) + doc.parsed_response['result'].length.should eq(1) + doc.parsed_response['count'].should eq(1) + doc.parsed_response['result'].map{|i| i['_id']}.should =~ [d2] + + cmd = api + "/by-example" + body = "{ \"collection\" : \"#{@cid}\", \"example\" : [ \"a.j\", 1 ] }" + doc = AvocadoDB.log_put("#{prefix}-by-example3", cmd, :body => body) + + doc.code.should eq(201) + doc.headers['content-type'].should eq("application/json") + doc.parsed_response['error'].should eq(false) + doc.parsed_response['code'].should eq(201) + doc.parsed_response['hasMore'].should eq(false) + doc.parsed_response['result'].length.should eq(2) + doc.parsed_response['count'].should eq(2) + doc.parsed_response['result'].map{|i| i['_id']}.should =~ [d2,d3] + + cmd = api + "/first-example" + body = "{ \"collection\" : \"#{@cid}\", \"example\" : [ \"a.j\", 1, \"a.k\", 1 ] }" + doc = AvocadoDB.log_put("#{prefix}-first-example", cmd, :body => body) + + doc.code.should eq(200) + doc.headers['content-type'].should eq("application/json") + doc.parsed_response['error'].should eq(false) + doc.parsed_response['code'].should eq(200) + doc.parsed_response['document']['_id'].should eq(d3) + + cmd = api + "/first-example" + body = "{ \"collection\" : \"#{@cid}\", \"example\" : [ \"a.j\", 1, \"a.k\", 2 ] }" + doc = AvocadoDB.log_put("#{prefix}-first-example-not-found", cmd, :body => body) + + doc.code.should eq(404) + doc.headers['content-type'].should eq("application/json") + doc.parsed_response['error'].should eq(true) + doc.parsed_response['code'].should eq(404) + end + end + end end diff --git a/UnitTests/Philadelphia/vector-pointer-test.cpp b/UnitTests/Philadelphia/vector-pointer-test.cpp index 7210de6626..27e88c09ff 100644 --- a/UnitTests/Philadelphia/vector-pointer-test.cpp +++ b/UnitTests/Philadelphia/vector-pointer-test.cpp @@ -480,6 +480,14 @@ BOOST_AUTO_TEST_CASE (tst_insert) { void* r = 0; + // ........................................................................... + // this test needs to be altered slightly e.g. + // TRI_InsertVectorPointer(&v1, &a, 100); + // TRI_InsertVectorPointer(&v1, &a, 20); + // TRI_InsertVectorPointer(&v1, &a, 200); + // ........................................................................... + + TRI_InsertVectorPointer(&v1, &a, 0); BOOST_CHECK_EQUAL((size_t) 1, v1._length); BOOST_CHECK_EQUAL(&a, TRI_AtVectorPointer(&v1, 0)); diff --git a/V8/v8-vocbase.cpp b/V8/v8-vocbase.cpp index f5f1a6f97d..ecbffb8eae 100644 --- a/V8/v8-vocbase.cpp +++ b/V8/v8-vocbase.cpp @@ -1851,7 +1851,7 @@ static v8::Handle JS_ByExampleQuery (v8::Arguments const& argv) { ReleaseCollection(collection); return scope.Close(v8::ThrowException( CreateErrorObject(TRI_ERROR_BAD_PARAMETER, - "usage: document(, , ...)"))); + "usage: byExample(, , ...)"))); } size_t n = argv.Length() / 2; @@ -4112,6 +4112,14 @@ static v8::Handle JS_ExecuteAql (v8::Arguments const& argv) { //////////////////////////////////////////////////////////////////////////////// /// @brief counts the number of documents in a result set +/// +/// @FUN{@FA{collection}.count()} +/// +/// Returns the number of living documents in the collection. +/// +/// @EXAMPLES +/// +/// @verbinclude shell-collection-count //////////////////////////////////////////////////////////////////////////////// static v8::Handle JS_CountVocbaseCol (v8::Arguments const& argv) { diff --git a/VERSION b/VERSION index 1d0ba9ea18..2b7c5ae018 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.0 +0.4.2 diff --git a/configure b/configure index baae6c157d..0e3dd99f5a 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for triAGENS AvocadoDB 0.4.0. +# Generated by GNU Autoconf 2.68 for triAGENS AvocadoDB 0.4.2. # # Report bugs to . # @@ -560,8 +560,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='triAGENS AvocadoDB' PACKAGE_TARNAME='avocado' -PACKAGE_VERSION='0.4.0' -PACKAGE_STRING='triAGENS AvocadoDB 0.4.0' +PACKAGE_VERSION='0.4.2' +PACKAGE_STRING='triAGENS AvocadoDB 0.4.2' PACKAGE_BUGREPORT='info@triagens.de' PACKAGE_URL='http://www.avocadodb.org' @@ -1398,7 +1398,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures triAGENS AvocadoDB 0.4.0 to adapt to many kinds of systems. +\`configure' configures triAGENS AvocadoDB 0.4.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1469,7 +1469,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of triAGENS AvocadoDB 0.4.0:";; + short | recursive ) echo "Configuration of triAGENS AvocadoDB 0.4.2:";; esac cat <<\_ACEOF @@ -1622,7 +1622,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -triAGENS AvocadoDB configure 0.4.0 +triAGENS AvocadoDB configure 0.4.2 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -2087,7 +2087,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by triAGENS AvocadoDB $as_me 0.4.0, which was +It was created by triAGENS AvocadoDB $as_me 0.4.2, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -3214,7 +3214,7 @@ fi # Define the identity of the package. PACKAGE='avocado' - VERSION='0.4.0' + VERSION='0.4.2' cat >>confdefs.h <<_ACEOF @@ -10112,7 +10112,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by triAGENS AvocadoDB $as_me 0.4.0, which was +This file was extended by triAGENS AvocadoDB $as_me 0.4.2, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -10179,7 +10179,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -triAGENS AvocadoDB config.status 0.4.0 +triAGENS AvocadoDB config.status 0.4.2 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 06e29f822a..49a56bdf14 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ dnl ============================================================================ dnl PREAMBLE triAGENS GmbH Build Environment dnl ============================================================================ -AC_INIT([triAGENS AvocadoDB], [0.4.0], [info@triagens.de], [avocado], [http://www.avocadodb.org]) +AC_INIT([triAGENS AvocadoDB], [0.4.2], [info@triagens.de], [avocado], [http://www.avocadodb.org]) dnl ---------------------------------------------------------------------------- dnl auxillary directory for install-sh and missing diff --git a/html/admin/css/layout.css b/html/admin/css/layout.css index 22326b97dd..b91263ac17 100644 --- a/html/admin/css/layout.css +++ b/html/admin/css/layout.css @@ -209,6 +209,9 @@ pre ul li span{ .ui-tabs-nav { font-size: 0.8em !important; height: 35px; + -webkit-box-shadow: inset 0 0 1px 1px #f6f6f6 !important; + -moz-box-shadow: inset 0 0 1px 1px #f6f6f6 !important; + box-shadow: inset 0 0 1px 1px #f6f6f6 !important; //border-bottom: 0px !important; } diff --git a/html/admin/js/master.js b/html/admin/js/master.js index 0af2fffed8..19d0260205 100644 --- a/html/admin/js/master.js +++ b/html/admin/js/master.js @@ -136,6 +136,7 @@ else { /////////////////////////////////////////////////////////////////////////////// var collectionTable = $('#collectionsTableID').dataTable({ + "aaSorting": [[ 2, "desc" ]], "bPaginate": false, "bFilter": false, "bLengthChange": false, @@ -152,7 +153,7 @@ var collectionTable = $('#collectionsTableID').dataTable({ /////////////////////////////////////////////////////////////////////////////// var documentEditTable = $('#documentEditTableID').dataTable({ - "aaSorting": [], + "aaSorting": [[ 1, "desc" ]], "bFilter": false, "bPaginate":false, "bSortable": false, @@ -2030,4 +2031,3 @@ function stateReplace (value) { return output; } - diff --git a/js/actions/system/api-simple.js b/js/actions/system/api-simple.js index 8a6c7b2aaa..7da00684ef 100644 --- a/js/actions/system/api-simple.js +++ b/js/actions/system/api-simple.js @@ -351,25 +351,29 @@ actions.defineHttp({ /// /// The call expects a JSON hash array as body with the following attributes: /// -/// @FA{collection} +/// - @LIT{collection}: The identifier or name of the collection to query. /// -/// The identifier or name of the collection to query. +/// - @LIT{example}: The example. /// -/// @FA{example} +/// - @LIT{skip}: The documents to skip in the query. (optional) /// -/// The example. +/// - @LIT{limit}: The maximal amount of documents to return. (optional) /// -/// @FA{skip} (optional) -/// -/// The documents to skip in the query. -/// -/// @FA{limit} (optional) -/// -/// The maximal amount of documents to return. +/// Returns a cursor containing the result, see @ref HttpCursor for details. /// /// @EXAMPLES /// -/// @verbinclude api_simple7 +/// Matching an attribute: +/// +/// @verbinclude api-simple-by-example1 +/// +/// Matching an attribute which is a sub-document: +/// +/// @verbinclude api-simple-by-example2 +/// +/// Matching an attribute within a sub-document: +/// +/// @verbinclude api-simple-by-example3 //////////////////////////////////////////////////////////////////////////////// actions.defineHttp({ @@ -383,16 +387,18 @@ actions.defineHttp({ return; } - var limit = body.limit; - var skip = body.skip; - var name = body.collection; - var example = body.example; - if (req.requestType != actions.PUT) { actions.unsupported(req, res); } else { - collection = internal.db._collection(name); + var limit = body.limit; + var skip = body.skip; + var name = body.collection; + var example = body.example; + + var name = body.collection; + var id = parseInt(name) || name; + var collection = internal.db._collection(id); if (collection == null) { actions.collectionNotFound(req, res, name); @@ -401,17 +407,95 @@ actions.defineHttp({ actions.badParameter(req, res, "example"); } else { - var result = collection.byExample(example); + try { + var result = collection.byExample.apply(collection, example); - if (skip != null) { - result = result.skip(skip); + if (skip != null) { + result = result.skip(skip); + } + + if (limit != null) { + result = result.limit(limit); + } + + actions.resultCursor(req, res, CREATE_CURSOR(result.toArray(), true)); } - - if (limit != null) { - result = result.limit(limit); + catch (err) { + actions.resultException(req, res, err); } + } + } + } +}); - actions.resultOk(req, res, actions.HTTP_OK, result.toArray()); +//////////////////////////////////////////////////////////////////////////////// +/// @fn JSA_PUT_api_simple_first_example +/// @brief returns one document of a collection matching a given example +/// +/// @REST{PUT /_api/simple/first-example} +/// +/// This will return the first document matching a given example. +/// +/// The call expects a JSON hash array as body with the following attributes: +/// +/// - @LIT{collection}: The identifier or name of the collection to query. +/// +/// - @LIT{example}: The example. +/// +/// - @LIT{skip}: The documents to skip in the query. (optional) +/// +/// - @LIT{limit}: The maximal amount of documents to return. (optional) +/// +/// Returns a result containing the document or @LIT{HTTP 404} if no +/// document matched the example. +/// +/// @EXAMPLES +/// +/// If a matching document was found: +/// +/// @verbinclude api-simple-first-example +/// +/// If no document was found: +/// +/// @verbinclude api-simple-first-example-not-found +//////////////////////////////////////////////////////////////////////////////// + +actions.defineHttp({ + url : API + "first-example", + context : "api", + + callback : function (req, res) { + var body = actions.getJsonBody(req, res); + + if (body === undefined) { + return; + } + + if (req.requestType != actions.PUT) { + actions.unsupported(req, res); + } + else { + var example = body.example; + + var name = body.collection; + var id = parseInt(name) || name; + var collection = internal.db._collection(id); + + if (collection == null) { + actions.collectionNotFound(req, res, name); + } + else if (typeof example !== "object") { + actions.badParameter(req, res, "example"); + } + else { + var result = collection.byExample.apply(collection, example).limit(1); + + if (result.hasNext()) { + actions.resultOk(req, res, actions.HTTP_OK, { document : result.next() }); + } + else { + actions.resultNotFound(req, res, "no match"); + } } } } diff --git a/js/client/modules/simple-query.js b/js/client/modules/simple-query.js index 17e2c136f6..41f9d5a057 100644 --- a/js/client/modules/simple-query.js +++ b/js/client/modules/simple-query.js @@ -98,29 +98,28 @@ SQ.SimpleQueryByExample.prototype.execute = function () { var documents; if (this._execution == null) { - if (this._skip == null || this._skip <= 0) { - this._skip = 0; + var data = { + collection : this._collection._id, + example : this._example + } + + if (this._limit != null) { + data.limit = this._limit; } - var parameters = [ ]; - - // the actual example is passed in the first argument - for (var i in this._example[0]) { - if (this._example[0].hasOwnProperty(i)) { - - // attribute name - parameters.push(i); - - // attribute value - parameters.push(this._example[0][i]); - } + if (this._skip != null) { + data.skip = this._skip; } + + var requestResult = this._collection._database._connection.PUT("/_api/simple/by-example", JSON.stringify(data)); - var documents = this._collection.BY_EXAMPLE.apply(this._collection, parameters); + TRI_CheckRequestResult(requestResult); - this._execution = new SQ.GeneralArrayCursor(documents, this._skip, this._limit); - this._countQuery = documents.length; - this._countTotal = documents.length; + this._execution = new AvocadoQueryCursor(this._collection._database, requestResult); + + if (requestResult.hasOwnProperty("count")) { + this._countQuery = requestResult.count; + } } } @@ -128,6 +127,52 @@ SQ.SimpleQueryByExample.prototype.execute = function () { /// @} //////////////////////////////////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup SimpleQuery +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief constructs a query-by-example for a collection +//////////////////////////////////////////////////////////////////////////////// + +AvocadoCollection.prototype.firstExample = function () { + + // create a REAL array, otherwise JSON.stringify will fail + var example = []; + + for (var i = 0; i < arguments.length; ++i) { + example.push(arguments[i]); + } + + var data = { + collection : this._id, + example : example + } + + var requestResult = this._database._connection.PUT("/_api/simple/first-example", JSON.stringify(data)); + + if (requestResult != null + && requestResult.error == true + && requestResult.errorNum == internal.errors.ERROR_HTTP_NOT_FOUND.code) { + return null; + } + + TRI_CheckRequestResult(requestResult); + + return requestResult.document; +} + +AvocadoEdgesCollection.prototype.firstExample = AvocadoCollection.prototype.firstExample; + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + // ----------------------------------------------------------------------------- // --SECTION-- SIMPLE QUERY NEAR // ----------------------------------------------------------------------------- diff --git a/js/common/modules/jsunity.js b/js/common/modules/jsunity.js index 2a63d40942..4937810b1f 100644 --- a/js/common/modules/jsunity.js +++ b/js/common/modules/jsunity.js @@ -36,37 +36,6 @@ var DURATION = 0; internal.loadFile("jsunity/jsunity"); jsUnity.log = console; -//////////////////////////////////////////////////////////////////////////////// -/// @page jsUnity Using jsUnity and node-jscoverage -/// -/// The AvocadoDB contains a wrapper for -/// jsUnity, a lightyweight universal -/// JavAScript unit testing framework. -/// -/// @section jsUnityRunningTest Running jsUnity Tests -/// -/// Assume that you have a test file containing -/// -/// @verbinclude jsunity1 -/// -/// Then you can run the test suite using @FN{jsunity.runTest} -/// -/// @verbinclude jsunity2 -/// -/// @section jsUnityRunningCoverage Running jsUnity Tests with Coverage -/// -/// You can use the coverage tool -/// @LIT{node-jscoverage}. -/// -/// Assume that your file live in a directory called @LIT{lib}. Use -/// -/// @CODE{node-jscoverage lib lib-cov} -/// -/// to create a copy of the JavaScript files with coverage information. Start -/// the AvocadoDB with these files and use @FN{jsunity.runCoverage} instead of -/// @FN{jsunity.runTest}. -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- private functions // ----------------------------------------------------------------------------- diff --git a/js/common/modules/simple-query-basics.js b/js/common/modules/simple-query-basics.js index 32491f9c47..64dd28d052 100644 --- a/js/common/modules/simple-query-basics.js +++ b/js/common/modules/simple-query-basics.js @@ -47,9 +47,9 @@ var AvocadoEdgesCollection = internal.AvocadoEdgesCollection; /// /// @FUN{all()} /// -/// Selects all documents of a collection. You can use @FN{toArray}, @FN{next}, -/// or @FN{hasNext} to access the result. The result can be limited using the -/// @FN{skip} and @FN{limit} operator. +/// Selects all documents of a collection and returns a cursor. You can use +/// @FN{toArray}, @FN{next}, or @FN{hasNext} to access the result. The result +/// can be limited using the @FN{skip} and @FN{limit} operator. /// /// @EXAMPLES /// @@ -257,14 +257,20 @@ AvocadoEdgesCollection.prototype.geo = AvocadoCollection.geo; /// /// @FUN{@FA{collection}.byExample(@FA{path1}, @FA{value1}, ...)} /// -/// Selects all documents of a collection that match the specified -/// example. The example must be specified as paths and values. Allowed +/// Selects all documents of a collection that match the specified example and +/// returns a cursor. The example must be specified as paths and values. Allowed /// attribute types for searching are numbers, strings, and boolean values. /// /// You can use @FN{toArray}, @FN{next}, or @FN{hasNext} to access /// the result. The result can be limited using the @FN{skip} and @FN{limit} /// operator. /// +/// @FUN{@FA{collection}.byExample(@FA{example})} +/// +/// As alternative you can supply an example as single argument. Note that an +/// attribute name of the form @LIT{a.b} is interpreted as attribute path, not +/// as attribute. +/// /// @EXAMPLES /// /// Use @FN{toArray} to get all documents at once: @@ -277,40 +283,19 @@ AvocadoEdgesCollection.prototype.geo = AvocadoCollection.geo; //////////////////////////////////////////////////////////////////////////////// AvocadoCollection.prototype.byExample = function () { - return new SimpleQueryByExample(this, arguments); + + // create a REAL array, otherwise JSON.stringify will fail + var example = []; + + for (var i = 0; i < arguments.length; ++i) { + example.push(arguments[i]); + } + + return new SimpleQueryByExample(this, example); } AvocadoEdgesCollection.prototype.byExample = AvocadoCollection.prototype.byExample; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief constructs a query-by-example for a collection -/// -/// @FUN{@FA{collection}.firstExample(@FA{path1}, @FA{value1}, ...)} -/// -/// Returns the first documents of a collection that match the specified example -/// or @LIT{null}. The example must be specified as paths and -/// values. Allowed attribute types for searching are numbers, strings, and -/// boolean values. -/// -/// @EXAMPLES -//////////////////////////////////////////////////////////////////////////////// - -AvocadoCollection.prototype.firstExample = function () { - var cursor = new SimpleQueryByExample(this, arguments); - var result = null; - - if (cursor.hasNext()) { - result = cursor.next(); - } - - cursor.dispose(); - - return result; -} - -AvocadoEdgesCollection.prototype.firstExample = AvocadoCollection.prototype.firstExample; - //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/js/common/tests/shell-simple-query.js b/js/common/tests/shell-simple-query.js index 0fc29f4e2d..147cb8e8ac 100644 --- a/js/common/tests/shell-simple-query.js +++ b/js/common/tests/shell-simple-query.js @@ -41,7 +41,7 @@ var SQB = require("simple-query-basics"); require("simple-query"); // ----------------------------------------------------------------------------- -// --SECTION-- basic skips and limits +// --SECTION-- basic skips and limits for array // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -176,14 +176,14 @@ function SimpleQueryArraySkipLimitSuite () { } // ----------------------------------------------------------------------------- -// --SECTION-- basic skips and limits +// --SECTION-- basic skips and limits for all // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief test suite: skip and limit with a collection //////////////////////////////////////////////////////////////////////////////// -function SimpleQuerySkipLimitSuite () { +function SimpleQueryAllSkipLimitSuite () { var cn = "UnitTestsCollectionSkipLimit"; var collection = null; var numbers = null; @@ -195,30 +195,30 @@ function SimpleQuerySkipLimitSuite () { /// @brief set up //////////////////////////////////////////////////////////////////////////////// - setUp : function () { - internal.db._drop(cn); - collection = internal.db._create(cn, { waitForSync : false }); + setUp : function () { + internal.db._drop(cn); + collection = internal.db._create(cn, { waitForSync : false }); - for (var i = 0; i < 10; ++i) { - collection.save({ n : i }); - } + for (var i = 0; i < 10; ++i) { + collection.save({ n : i }); + } - numbers = collection.all().toArray().map(num); - }, + numbers = collection.all().toArray().map(num); + }, //////////////////////////////////////////////////////////////////////////////// /// @brief tear down //////////////////////////////////////////////////////////////////////////////// - tearDown : function () { - collection.drop(); - }, + tearDown : function () { + collection.drop(); + }, //////////////////////////////////////////////////////////////////////////////// /// @brief test: skip //////////////////////////////////////////////////////////////////////////////// - testSkip : function () { + testAllSkip : function () { var n = collection.all().skip(0).toArray().map(num); assertEqual(n, numbers); @@ -256,7 +256,7 @@ function SimpleQuerySkipLimitSuite () { /// @brief test: limit //////////////////////////////////////////////////////////////////////////////// - testLimit : function () { + testAllLimit : function () { var n = collection.all().limit(10).toArray().map(num); assertEqual(n, numbers); @@ -290,7 +290,7 @@ function SimpleQuerySkipLimitSuite () { /// @brief test: skip and limit //////////////////////////////////////////////////////////////////////////////// - testSkipLimit : function () { + testAllSkipLimit : function () { var n = collection.all().skip(0).limit(10).toArray().map(num); assertEqual(n, numbers); @@ -318,6 +318,112 @@ function SimpleQuerySkipLimitSuite () { }; } +// ----------------------------------------------------------------------------- +// --SECTION-- basic tests for byExample +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test suite: skip and limit with a collection +//////////////////////////////////////////////////////////////////////////////// + +function SimpleQueryByExampleSuite () { + var cn = "UnitTestsCollectionByExample"; + var collection = null; + var id = function(d) { return d._id; }; + + return { + +//////////////////////////////////////////////////////////////////////////////// +/// @brief set up +//////////////////////////////////////////////////////////////////////////////// + + setUp : function () { + internal.db._drop(cn); + collection = internal.db._create(cn, { waitForSync : false }); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief tear down +//////////////////////////////////////////////////////////////////////////////// + + tearDown : function () { + collection.drop(); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test: byExample +//////////////////////////////////////////////////////////////////////////////// + + testByExampleObject : function () { + var d1 = collection.save({ i : 1 }); + var d2 = collection.save({ i : 1, a : { j : 1 } }); + var d3 = collection.save({ i : 1, a : { j : 1, k : 1 } }); + var d4 = collection.save({ i : 1, a : { j : 2, k : 2 } }); + var d5 = collection.save({ i : 2 }); + var d6 = collection.save({ i : 2, a : 2 }); + var d7 = collection.save({ i : 2, a : { j : 2, k : 2 } }); + var s; + + s = collection.byExample({ i : 1 }).toArray().map(id).sort(); + assertEqual([d1._id, d2._id, d3._id, d4._id].sort(), s); + + s = collection.byExample({ i : 2 }).toArray().map(id).sort(); + assertEqual([d5._id, d6._id, d7._id].sort(), s); + + s = collection.byExample({ a : { j : 1 } }).toArray().map(id).sort(); + assertEqual([d2._id], s); + + s = collection.byExample({ "a.j" : 1 }).toArray().map(id).sort(); + assertEqual([d2._id, d3._id].sort(), s); + + s = collection.byExample({ i : 2, "a.k" : 2 }).toArray().map(id).sort(); + assertEqual([d7._id], s); + + s = collection.firstExample({ "i" : 2, "a.k" : 2 }); + assertEqual(d7._id, s._id); + + s = collection.firstExample({ "i" : 2, "a.k" : 27 }); + assertEqual(null, s); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test: byExample +//////////////////////////////////////////////////////////////////////////////// + + testByExampleList : function () { + var d1 = collection.save({ i : 1 }); + var d2 = collection.save({ i : 1, a : { j : 1 } }); + var d3 = collection.save({ i : 1, a : { j : 1, k : 1 } }); + var d4 = collection.save({ i : 1, a : { j : 2, k : 2 } }); + var d5 = collection.save({ i : 2 }); + var d6 = collection.save({ i : 2, a : 2 }); + var d7 = collection.save({ i : 2, a : { j : 2, k : 2 } }); + var s; + + s = collection.byExample("i", 1).toArray().map(id).sort(); + assertEqual([d1._id, d2._id, d3._id, d4._id].sort(), s); + + s = collection.byExample("i", 2).toArray().map(id).sort(); + assertEqual([d5._id, d6._id, d7._id].sort(), s); + + s = collection.byExample("a", { j : 1 }).toArray().map(id).sort(); + assertEqual([d2._id], s); + + s = collection.byExample("a.j", 1).toArray().map(id).sort(); + assertEqual([d2._id, d3._id].sort(), s); + + s = collection.byExample("i", 2, "a.k", 2).toArray().map(id).sort(); + assertEqual([d7._id], s); + + s = collection.firstExample("i", 2, "a.k", 2); + assertEqual(d7._id, s._id); + + s = collection.firstExample("i", 2, "a.k", 27); + assertEqual(null, s); + } + }; +} + // ----------------------------------------------------------------------------- // --SECTION-- main // ----------------------------------------------------------------------------- @@ -327,7 +433,8 @@ function SimpleQuerySkipLimitSuite () { //////////////////////////////////////////////////////////////////////////////// jsunity.run(SimpleQueryArraySkipLimitSuite); -jsunity.run(SimpleQuerySkipLimitSuite); +jsunity.run(SimpleQueryAllSkipLimitSuite); +jsunity.run(SimpleQueryByExampleSuite); return jsunity.done(); diff --git a/js/server/js-server.h b/js/server/js-server.h index bf9faa51eb..a9d36ed127 100644 --- a/js/server/js-server.h +++ b/js/server/js-server.h @@ -419,6 +419,11 @@ static string JS_server_server = "\n" "////////////////////////////////////////////////////////////////////////////////\n" "/// @brief converts collection into an array\n" + "///\n" + "/// @FUN{@FA{collection}.toArray()}\n" + "///\n" + "/// Converts the collection into an array of documents. Never use this call\n" + "/// in a production environment.\n" "////////////////////////////////////////////////////////////////////////////////\n" "\n" "AvocadoCollection.prototype.toArray = function() {\n" diff --git a/js/server/modules/simple-query.js b/js/server/modules/simple-query.js index 2a50ede6bb..2fed25a6bf 100644 --- a/js/server/modules/simple-query.js +++ b/js/server/modules/simple-query.js @@ -90,20 +90,27 @@ SQ.SimpleQueryByExample.prototype.execute = function () { this._skip = 0; } - var parameters = [ ]; + var parameters = []; // the actual example is passed in the first argument - for (var i in this._example[0]) { - if (this._example[0].hasOwnProperty(i)) { + if (this._example.length == 1) { + for (var i in this._example[0]) { + if (this._example[0].hasOwnProperty(i)) { - // attribute name - parameters.push(i); + // attribute name + parameters.push(i); - // attribute value - parameters.push(this._example[0][i]); + // attribute value + parameters.push(this._example[0][i]); + } } } + // the arguments are passed + else { + parameters = this._example; + } + var documents = this._collection.BY_EXAMPLE.apply(this._collection, parameters); this._execution = new SQ.GeneralArrayCursor(documents, this._skip, this._limit); @@ -116,6 +123,55 @@ SQ.SimpleQueryByExample.prototype.execute = function () { /// @} //////////////////////////////////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup SimpleQuery +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief constructs a query-by-example for a collection +/// +/// @FUN{@FA{collection}.firstExample(@FA{path1}, @FA{value1}, ...)} +/// +/// Returns the first documents of a collection that match the specified example +/// or @LIT{null}. The example must be specified as paths and +/// values. Allowed attribute types for searching are numbers, strings, and +/// boolean values. +/// +/// @FUN{@FA{collection}.firstExample(@FA{example})} +/// +/// As alternative you can supply an example as single argument. Note that an +/// attribute name of the form @LIT{a.b} is interpreted as attribute path, not +/// as attribute. +/// +/// @EXAMPLES +/// +/// @verbinclude shell-simple-query-first-example +//////////////////////////////////////////////////////////////////////////////// + +AvocadoCollection.prototype.firstExample = function () { + var cursor = new SQ.SimpleQueryByExample(this, arguments); + var result = null; + + if (cursor.hasNext()) { + result = cursor.next(); + } + + cursor.dispose(); + + return result; +} + +AvocadoEdgesCollection.prototype.firstExample = AvocadoCollection.prototype.firstExample; + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + // ----------------------------------------------------------------------------- // --SECTION-- SIMPLE QUERY NEAR // ----------------------------------------------------------------------------- diff --git a/js/server/server.js b/js/server/server.js index d8731e9166..740c637af9 100644 --- a/js/server/server.js +++ b/js/server/server.js @@ -418,6 +418,11 @@ AvocadoEdgesCollection.STATUS_DELETED = 5; //////////////////////////////////////////////////////////////////////////////// /// @brief converts collection into an array +/// +/// @FUN{@FA{collection}.toArray()} +/// +/// Converts the collection into an array of documents. Never use this call +/// in a production environment. //////////////////////////////////////////////////////////////////////////////// AvocadoCollection.prototype.toArray = function() {