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 
'
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 @@
///
///
/// - @ref HttpSimpleAll "POST /_api/simple/all"
+/// - @ref HttpSimpleByExample "POST /_api/simple/by-example"
+/// - @ref HttpSimpleFirstExample "POST /_api/simple/first-example"
/// - @ref HttpSimpleNear "POST /_api/simple/near"
/// - @ref HttpSimpleWithin "POST /_api/simple/within"
///
@@ -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
///
///
-/// - @ref Installing
-///
-
-///
- @ref Compiling
-///
+/// - @ref Installing
+/// - @ref Compiling
///
////////////////////////////////////////////////////////////////////////////////
@@ -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
-///
-/// - @ref OTWPSimpleQueriesByExample "PUT /_api/simple/by-example"
-///
-///
-///
@ref Key-Value
-///
-/// - @ref Key-ValuePost "POST /_api/key/@FA{collection-name}/@FA{key}"
-/// - @ref Key-ValuePut "PUT /_api/key/@FA{collection-name}/@FA{key}"
-/// - @ref Key-ValueGet "GET /_api/key/@FA{collection-name}/@FA{key}"
-/// - @ref Key-ValueDelete "DELETE /_api/key/@FA{collection-name}/@FA{key}"
-/// - @ref Key-ValueSearch "GET /_api/keys/@FA{collection-name}/@FA{prefix}"
-///
///
///
///
+///
@ref Key-Value (Under Construction)
+///
+/// - @ref Key-ValuePost "POST /_api/key/collection-name/key"
+/// - @ref Key-ValuePut "PUT /_api/key/collection-name/key"
+/// - @ref Key-ValueGet "GET /_api/key/collection-name/key"
+/// - @ref Key-ValueDelete "DELETE /_api/key/collection-name/key"
+/// - @ref Key-ValueSearch "GET /_api/keys/collection-name/prefix"
+///
+///
///
////////////////////////////////////////////////////////////////////////////////
@@ -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 @@
///
/// - @ref SimpleQueriesQueries
///
-/// - @ref SimpleQueryDocument "db.@FA{collection}.document(@FA{document-reference})"
-/// - @ref SimpleQueryAll "db.@FA{collection}.all()"
-/// - @ref SimpleQueryByExample "db.@FA{collection}.byExample()"
-/// - @ref SimpleQueryCount "@FA{query}.count()"
+/// - @ref SimpleQueryDocument "collection.document(document-reference)"
+/// - @ref SimpleQueryAll "collection.all()"
+/// - @ref SimpleQueryByExample "collection.byExample(example)"
+/// - @ref SimpleQueryFirstExample "collection.firstExample(example)"
+/// - @ref SimpleQueryCollectionCount "collection.count()"
+/// - @ref SimpleQueryToArray "collection.toArray()"
///
///
/// - @ref SimpleQueriesGeoQueries
///
-/// - @ref SimpleQueryNear "db.@FA{collection}.near()"
-/// - @ref SimpleQueryWithin "db.@FA{collection}.within()"
-/// - @ref SimpleQueryGeo "db.@FA{collection}.geo()"
+/// - @ref SimpleQueryNear "collection.near(latitude, longitude)"
+/// - @ref SimpleQueryWithin "collection.within(latitude, longitude)"
+/// - @ref SimpleQueryGeo "collection.geo(location)"
///
///
/// - @ref SimpleQueriesEdgesQueries
///
-/// - @ref SimpleQueryEdges "edges.@FA{collection}.edges()"
-/// - @ref SimpleQueryInEdges "edges.@FA{collection}.inEdges()"
-/// - @ref SimpleQueryOutEdges "edges.@FA{collection}.outEdges()"
+/// - @ref SimpleQueryEdges "edges-collection.edges(vertex)"
+/// - @ref SimpleQueryInEdges "edges-collection.inEdges(vertex)"
+/// - @ref SimpleQueryOutEdges "edges-collection.outEdges(vertex)"
///
///
/// - @ref SimpleQueriesPagination
///
-/// - @ref SimpleQueryLimit "@FA{query}.limit(@FA{limit})"
-/// - @ref SimpleQuerySkip "@FA{query}.skip(@FA{skip})"
+/// - @ref SimpleQueryLimit "query.limit(limit)"
+/// - @ref SimpleQuerySkip "query.skip(skip)"
///
///
/// - @ref SimpleQueriesSequentialAccess
///
-/// - @ref SimpleQueryHasNext "@FA{query}.hasNext()"
-/// - @ref SimpleQueryNext "@FA{query}.next()"
+/// - @ref SimpleQueryHasNext "query.hasNext()"
+/// - @ref SimpleQueryNext "query.next()"
+/// - @ref SimpleQueryCount "query.count()"
///
///
///
@@ -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 @@
///
/// - @ref UserManualServerStartStop
///
-/// - AvocadoScript
-///
-/// - @ref SimpleQueries
-///
-///
-///
/// - Avocado Query Language
///
/// - @ref AQLBasics
@@ -49,47 +43,18 @@
///
///
///
-/// - @ref AvocadoScript
-///
-/// - GeoCoordinates
-///
-///
-///
-/// - Vertices, Edges, and Graphs
-///
-/// - @ref Graphs
-///
-/// - @ref JSModuleGraph
-///
-///
-///
/// - @ref AvocadoErrors
///
///
///
-///
Client Communication
-///
-/// - @ref HttpInterface
-///
-/// - @ref RestDocument
-///
-///
-///
-///
-///
-///
@ref DBAdmin
-///
-/// - @ref DBAdminDurability
-///
-/// - @ref DBAdminIndex
-///
-/// - @ref DBAdminIndexGeo
-///
-///
-///
-///
///
Advanced Topics
///
+/// - @ref DBAdmin
+///
+/// - @ref DBAdminDurability
+///
+///
+///
/// - Actions
///
/// - @ref Actions
@@ -98,12 +63,6 @@
///
///
///
-/// - @ref HttpInterface
-///
-/// - @ref RestSystem
-///
-///
-///
/// - @ref jsUnity
///
///
@@ -128,20 +87,21 @@
/// @page UserManualServerStartStopTOC
///
///
-/// - @ref UserManualServerStartStopHttp "Starting the HTTP Server"
-/// - @ref UserManualServerStartStopDebug "Starting the Debug Shell"
-/// - @ref UserManualServerStartStopOptions "Frequently Used Options"
+/// - @ref UserManualServerStartStopHttp
+/// - @ref UserManualServerStartStopDebug
+/// - @ref UserManualServerStartStopOptions
///
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @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 @@
///
/// - @ref DBAdminDurability
///
-/// - @ref DBAdminIndex
-///
-/// - @ref DBAdminIndexGeo
-///
-///
///
////////////////////////////////////////////////////////////////////////////////
@@ -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() {