merge with master
authoradam <adamansky@gmail.com>
Wed, 17 Jul 2013 09:22:28 +0000 (16:22 +0700)
committeradam <adamansky@gmail.com>
Wed, 17 Jul 2013 09:22:28 +0000 (16:22 +0700)
README.md
node/README.md [new file with mode: 0644]
tcejdb/ejdb.c
tcejdb/ejdb.h
tcejdb/testejdb/t4.c

index 834b7be..b9a6550 100644 (file)
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
 Embedded JSON Database engine
 ====================================
 
-It aims to be a fast [MongoDB](http://mongodb.org)-like library **which can be embedded into C/C++, .Net, NodeJS, Python, Lua, Java, Ruby, Go applications under terms of LGPL license.**
+It aims to be a fast [MongoDB](http://mongodb.org)-like library **which can be embedded into C/C++, .Net, NodeJS, Python, Lua, Go, Java and Ruby applications under terms of LGPL license.**
 
 EJDB is the C library based on modified version of [Tokyo Cabinet](http://fallabs.com/tokyocabinet/).
 
@@ -43,24 +43,22 @@ Features
 Documentation
 ================================
 
-* **[The great intro to the EJDB](http://blog.abigopal.com/post/51616277039/ejdb)**
+* **[The brief intro to the EJDB](http://blog.abigopal.com/post/51616277039/ejdb)**
 * **[EJDB Command line interface](https://github.com/Softmotions/ejdb/wiki/EJDB-Command-line-interface)**
-* **[C# .Net] (https://github.com/Softmotions/ejdb/tree/master/nejdb)**
-* **[NodeJS](#nodejs-binding)**
-    * [Installation](#installation)
-    * [Samples](#ejdb-nodejs-samples)
-    * [NodeJS API](#ejdb-nodejs-api)
-* **[Python 2.7/3.x](https://github.com/Softmotions/ejdb/blob/master/pyejdb/)**
-* **[Lua](https://github.com/Softmotions/ejdb/blob/master/luaejdb/)**
-* **[Java](https://github.com/Softmotions/ejdb/blob/master/jejdb/)**
-* **[Ruby](https://github.com/Softmotions/ejdb/blob/master/rbejdb/)**
-* **[Go](https://github.com/mkilling/goejdb/)**
-* **[Pike language] (https://github.com/hww3/pike_modules-ejdb)**
-* **[Adobe Air] (https://github.com/thejustinwalsh/airejdb)**
 * **[EJDB C Library](#ejdb-c-library)**
     * [Building & Installation](#building--installation)
     * [Samples](#ejdb-c-samples)
     * [C API](#c-api)
+* **Bindings**
+    * **[C# .Net] (https://github.com/Softmotions/ejdb/tree/master/nejdb)**
+    * **[NodeJS] (https://github.com/Softmotions/ejdb/blob/master/node/)**
+    * **[Python 2.7/3.x](https://github.com/Softmotions/ejdb/blob/master/pyejdb/)**
+    * **[Lua](https://github.com/Softmotions/ejdb/blob/master/luaejdb/)**
+    * **[Java](https://github.com/Softmotions/ejdb/blob/master/jejdb/)**
+    * **[Ruby](https://github.com/Softmotions/ejdb/blob/master/rbejdb/)**
+    * **[Go](https://github.com/mkilling/goejdb/)**
+    * **[Pike language] (https://github.com/hww3/pike_modules-ejdb)**
+    * **[Adobe Air] (https://github.com/thejustinwalsh/airejdb)**
 * **[Collection joins](https://github.com/Softmotions/ejdb/wiki/Collection-joins)**
 
 
@@ -75,7 +73,7 @@ NodeJS binding
 One snippet intro
 ---------------------------------
 
-```JavaScript
+```
 var EJDB = require("ejdb");
 //Open zoo DB
 var jb = EJDB.open("zoo", EJDB.DEFAULT_OPEN_MODE | EJDB.JBOTRUNC);
@@ -123,488 +121,7 @@ jb.save("parrots", [parrot1, parrot2], function(err, oids) {
             });
 });
 ```
-
-Installation
---------------------------------
-**System libraries:**
-
-* g++
-* zlib
-
-On Debian/Ubuntu linux you can install it as follows:
-
-~~~~~~
-sudo apt-get install g++ zlib1g zlib1g-dev
-~~~~~~
-
-**Installation from node package manager on linux/macos:**
-
-    npm install ejdb
-
-**[Installing EJDB NodeJS module on windows](https://github.com/Softmotions/ejdb/blob/master/tcejdb/WIN32.md#ejdb-nodejs-module-installation)**
-
-
-EJDB NodeJS samples
----------------------------------
-
-* [node/samples](https://github.com/Softmotions/ejdb/tree/master/node/samples)
-* [node/tests](https://github.com/Softmotions/ejdb/tree/master/node/tests)
-* [nwk-ejdb-address-book](https://github.com/Softmotions/nwk-ejdb-address-book)
-
-
-EJDB NodeJS API
-----------------------------------
-
-<a name="open" />
-### EJDB.open(dbFile, openMode)
-
-Open database. Return database instance handle object.
-<br/>Default open mode: `JBOWRITER | JBOCREAT`.
-<br/>This is blocking function.
-
-__Arguments__
-
- * {String} dbFile Database main file name
- * {Number} `[openMode=JBOWRITER | JBOCREAT]` Bitmast of open modes:
-       - `JBOREADER` Open as a reader.
-       - `JBOWRITER` Open as a writer.
-       - `JBOCREAT` Create if db file not exists
-       - `JBOTRUNC` Truncate db.
-
----------------------------------------
-
-<a name="close" />
-### close()
-
-Close database.
-<br/>If database was not opened it does nothing.
-<br/>This is blocking function.
-
----------------------------------------
-
-<a name="isOpen"/>
-### isOpen()
-Check if database in opened state.
-
----------------------------------------
-
-<a name="ensureCollection"/>
-### ensureCollection(cname, copts)
-
-Automatically creates new collection if it does't exists.
-Collection options `copts` applied only for newly created collection.
-For existing collections `copts` takes no effect.
-
-Collection options (copts):
-
- * cachedrecords : Max number of cached records in shared memory segment. Default: 0
- * records : Estimated number of records in this collection. Default: 65535.
- * large : Specifies that the size of the database can be larger than 2GB. Default: false
- * compressed : If true collection records will be compressed with DEFLATE compression. Default: false.
-
-<br/>This is blocking function.
-
-__Arguments__
-
- * {String} cname Name of collection.
- * {Object} `[copts]` Collection options.
-
----------------------------------------
-
-
-<a name="dropCollection"/>
-### dropCollection(cname, prune, cb)
-
-Drop collection.
-
-Call variations:
-
-    dropCollection(cname)
-    dropCollection(cname, cb)
-    dropCollection(cname, prune, cb)
-
-__Arguments__
-
- * {String} cname Name of collection.
- * {Boolean} `[prune=false]` If true the collection data will erased from disk.
- * {Function} `[cb]` Callback args: (error)
-
----------------------------------------
-
-<a name="save"/>
-### save(cname, jsarr, cb)
-
-Save/update specified JSON objects in the collection.
-If collection with `cname` does not exists it will be created.
-
-Each persistent object has unique identifier (OID) placed in the `_id` property.
-If a saved object does not have  `_id` it will be autogenerated.
-To identify and update object it should contains `_id` property.
-
-If callback is not provided this function will be synchronous.
-
-Call variations:
-
-    save(cname, <json object>|<Array of json objects>, [options] [cb])
-    save(cname, <json object>|<Array of json objects>, [cb])
-
-NOTE: Field names of passed JSON objects may not contain `$` and `.` characters,
-      error condition will be fired in this case.
-
-__Arguments__
-
- * {String} **cname** Name of collection.
- * {Array|Object} jsarr Signle JSON object or array of JSON objects to save
- * {Function} `[cb]` Callback args: (error, {Array} of OIDs for saved objects)
-
-__Return__
-
- * {Array} of OIDs of saved objects in synchronous mode otherwise returns {undefined}.
-
---------------------------------------
-
-<a name="load"/>
-### load(cname, oid, cb)
-
-Loads JSON object identified by OID from the collection.
-If callback is not provided this function will be synchronous.
-
-__Arguments__
-
- * {String} cname Name of collection
- * {String} oid Object identifier (OID)
- * {Function} cb  Callback args: (error, obj)
-        `obj`:  Retrieved JSON object or NULL if it is not found.
-
-__Return__
-
- * JSON object or {null} if it is not found in synchronous mode otherwise return {undefined}.
-
---------------------------------------
-
-<a name="remove"/>
-### remove(cname, oid, cb)
-
-Removes JSON object from the collection.
-If callback is not provided this function will be synchronous.
-
-__Arguments__
-
- * {String} cname Name of collection
- * {String} oid Object identifier (OID)
- * {Function} cb  Callback args: (error)
-
-
---------------------------------------
-
-<a name="find"/>
-### find(cname, qobj, orarr, hints, cb)
-Execute query on collection.
-EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy.
-
-    Supported queries:
-      - Simple matching of String OR Number OR Array value:
-          -   {'fpath' : 'val', ...}
-      - $not Negate operation.
-          -   {'fpath' : {'$not' : val}} //Field not equal to val
-          -   {'fpath' : {'$not' : {'$begin' : prefix}}} //Field not begins with val
-      - $begin String starts with prefix
-          -   {'fpath' : {'$begin' : prefix}}
-      - $gt, $gte (>, >=) and $lt, $lte for number types:
-          -   {'fpath' : {'$gt' : number}, ...}
-      - $bt Between for number types:
-          -   {'fpath' : {'$bt' : [num1, num2]}}
-      - $in String OR Number OR Array val matches to value in specified array:
-          -   {'fpath' : {'$in' : [val1, val2, val3]}}
-      - $nin - Not IN
-      - $strand String tokens OR String array val matches all tokens in specified array:
-          -   {'fpath' : {'$strand' : [val1, val2, val3]}}
-      - $stror String tokens OR String array val matches any token in specified array:
-          -   {'fpath' : {'$stror' : [val1, val2, val3]}}
-      - $exists Field existence matching:
-          -   {'fpath' : {'$exists' : true|false}}
-      - $icase Case insensitive string matching:
-          -  {'fpath' : {'$icase' : 'val1'}} //icase matching
-          Ignore case matching with '$in' operation:
-          -  {'name' : {'$icase' : {'$in' : ['tHéâtre - театр', 'heLLo WorlD']}}}
-          For case insensitive matching you can create special type of string index.
-      - $elemMatch The $elemMatch operator matches more than one component within an array element.
-          -  { array: { $elemMatch: { value1 : 1, value2 : { $gt: 1 } } } }
-          Restriction: only one $elemMatch allowed in context of one array field.
-
-      - Queries can be used to update records:
-
-        $set Field set operation.
-            - {.., '$set' : {'field1' : val1, 'fieldN' : valN}}
-        $upsert Atomic upsert. If matching records are found it will be '$set' operation,
-                otherwise new record will be inserted with fields specified by argment object.
-           - {.., '$upsert' : {'field1' : val1, 'fieldN' : valN}}
-        $inc Increment operation. Only number types are supported.
-            - {.., '$inc' : {'field1' : number, ...,  'field1' : number}
-        $dropall In-place record removal operation.
-            - {.., '$dropall' : true}
-        $addToSet Atomically adds value to the array only if its not in the array already.
-                    If containing array is missing it will be created.
-            - {.., '$addToSet' : {'fpath' : val1, 'fpathN' : valN, ...}}
-        $addToSetAll Batch version if $addToSet
-            - {.., '$addToSetAll' : {'fpath' : [array of values to add], ...}}
-        $pull Atomically removes all occurrences of value from field, if field is an array.
-            - {.., '$pull' : {'fpath' : val1, 'fpathN' : valN, ...}}
-        $pullAll Batch version of $pull
-            - {.., '$pullAll' : {'fpath' : [array of values to remove], ...}}
-
-    NOTE: It is better to execute update queries with `$onlycount=true` hint flag
-         or use the special `update()` method to avoid unnecessarily rows fetching.
-
-    NOTE: Negate operations: $not and $nin not using indexes
-          so they can be slow in comparison to other matching operations.
-
-    NOTE: Only one index can be used in search query operation.
-
-    NOTE: If callback is not provided this function will be synchronous.
-
-    QUERY HINTS (specified by `hints` argument):
-      - $max Maximum number in the result set
-      - $skip Number of skipped results in the result set
-      - $orderby Sorting order of query fields.
-      - $onlycount true|false If `true` only count of matching records will be returned
-                              without placing records in result set.
-      - $fields Set subset of fetched fields
-           If a field presented in $orderby clause it will be forced to include in resulting records.
-           Example:
-           hints:    {
-                       "$orderby" : { //ORDER BY field1 ASC, field2 DESC
-                           "field1" : 1,
-                           "field2" : -1
-                       },
-                       "$fields" : { //SELECT ONLY {_id, field1, field2}
-                           "field1" : 1,
-                           "field2" : 1
-                       }
-                     }
-
-    Many C API query examples can be found in `tcejdb/testejdb/t2.c` test case.
-
-    To traverse selected records cursor object is used:
-      - Cursor#next() Move cursor to the next record and returns true if next record exists.
-      - Cursor#hasNext() Returns true if cursor can be placed to the next record.
-      - Cursor#field(name) Retrieve value of the specified field of the current JSON object record.
-      - Cursor#object() Retrieve whole JSON object with all fields.
-      - Cursor#reset() Reset cursor to its initial state.
-      - Cursor#length Read-only property: Number of records placed into cursor.
-      - Cursor#pos Read/Write property: You can set cursor position: 0 <= pos < length
-      - Cursor#close() Closes cursor and free cursor resources. Cursor cant be used in closed state.
-
-    Call variations of find():
-       - find(cname, [cb])
-       - find(cname, qobj, [cb])
-       - find(cname, qobj, hints, [cb])
-       - find(cname, qobj, qobjarr, [cb])
-       - find(cname, qobj, qobjarr, hints, [cb])
-
- __Arguments__
-
- * {String} cname Name of collection
- * {Object} qobj Main JSON query object
- * {Array} `[orarr]` Array of additional OR query objects (joined with OR predicate).
- * {Object} `[hints]` JSON object with query hints.
- * {Function} cb Callback args: (error, cursor, count)
-            `cursor`: Cursor object to traverse records
-      qobj      `count`:  Total number of selected records
-
-__Return__
-
- * If callback is provided returns {undefined}
- * If no callback and `$onlycount` hint is set returns count {Number}.
- * If no callback and no `$onlycount` hint returns cursor {Object}.
-
- --------------------------------------------
-
-<a name="findOne"/>
-### findOne(cname, qobj, orarr, hints, cb)
-Same as #find() but retrieves only one matching JSON object.
-
-Call variations of findOne():
-
-    findOne(cname, [cb])
-    findOne(cname, qobj, [cb])
-    findOne(cname, qobj, hints, [cb])
-    findOne(cname, qobj, qobjarr, [cb])
-    findOne(cname, qobj, qobjarr, hints, [cb])
-
-__Arguments__
-
- * {String} cname Name of collection
- * {Object} qobj Main JSON query object
- * {Array} `[orarr]` Array of additional OR query objects (joined with OR predicate).
- * {Object} `[hints]` JSON object with query hints.
- * {Function} cb Callback args: (error, obj)
-             `obj`  Retrieved JSON object or NULL if it is not found.
-
-__Return__
-
- * If callback is provided returns {undefined}
- * If no callback is provided returns found {Object} or {null}
-
------------------------------------
-<a name="findOne"/>
-### update(cname, qobj, orarr, hints, cb)
-Convenient method to execute update queries.
-
- * `$set` Field set operation:
-    - {some fields for selection, '$set' : {'field1' : {obj}, ...,  'field1' : {obj}}}
- * `$upsert` Atomic upsert. If matching records are found it will be '$set' operation,
- otherwise new record will be inserted with fields specified by argment object.
-    - {.., '$upsert' : {'field1' : val1, 'fieldN' : valN}}
- * `$inc` Increment operation. Only number types are supported.
-    - {some fields for selection, '$inc' : {'field1' : number, ...,  'field1' : {number}}
- * `$dropall` In-place record removal operation.
-    - {some fields for selection, '$dropall' : true}
- * `$addToSet` | `$addToSetAll` Atomically adds value to the array only if its not in the array already.
- If containing array is missing it will be created.
-    - {.., '$addToSet' : {'fpath' : val1, 'fpathN' : valN, ...}}
- * `$pull` | `pullAll` Atomically removes all occurrences of value from field, if field is an array.
-    - {.., '$pull' : {'fpath' : val1, 'fpathN' : valN, ...}}
-
-Call variations of update():
-
-    update(cname, [cb])
-    update(cname, qobj, [cb])
-    update(cname, qobj, hints, [cb])
-    update(cname, qobj, qobjarr, [cb])
-    update(cname, qobj, qobjarr, hints, [cb])
-
-__Arguments__
-
- * {String} cname Name of collection
- * {Object} qobj Update JSON query object
- * {Array} `[orarr]` Array of additional OR query objects (joined with OR predicate).
- * {Object} `[hints]` JSON object with query hints.
- * {Function} cb Callback args: (error, count)
-             `count`  The number of updated records.
-
-__Return__
-
- * If callback is provided returns {undefined}.
- * If no callback is provided returns {Number} of updated objects.
-
-
------------------------------------
-
-<a name="count"/>
-### count(cname, qobj, orarr, hints, cb)
-Convenient count(*) operation.
-
-Call variations of count():
-
-    count(cname, [cb])
-    count(cname, qobj, [cb])
-    count(cname, qobj, hints, [cb])
-    count(cname, qobj, qobjarr, [cb])
-    count(cname, qobj, qobjarr, hints, [cb])
-
-__Arguments__
-
- * {String} cname Name of collection
- * {Object} qobj Main JSON query object
- * {Array} `[orarr]` Array of additional OR query objects (joined with OR predicate).
- * {Object} `[hints]` JSON object with query hints.
- * {Function} cb Callback args: (error, count)
-              `count`:  Number of matching records.
-
-__Return__
-
- * If callback is provided returns {undefined}.
- * If no callback is provided returns {Number} of matched object.
-
------------------------------------
-
-<a name="sync"/>
-### sync(cb)
-Synchronize entire EJDB database with disk.
-
-__Arguments__
-
- * {Function} cb Callback args: (error)
-
------------------------------------
-
-<a name="dropIndexes"/>
-### dropIndexes(cname, path, cb)
-Drop indexes of all types for JSON field path.
-
-__Arguments__
-
- * {String} cname Name of collection
- * {String} path  JSON field path
- * {Function} `[cb]` Optional callback function. Callback args: (error)
-
-------------------------------------
-
-<a name="optimizeIndexes"/>
-### optimizeIndexes(cname, path, cb)
-Optimize indexes of all types for JSON field path.
-Performs B+ tree index file optimization.
-
- __Arguments__
-
-  * {String} cname Name of collection
-  * {String} path  JSON field path
-  * {Function} `[cb]` Optional callback function. Callback args: (error)
-
------------------------------------
-
-<a name="ensureIndex"/>
-### ensureStringIndex(cname, path, cb)
-### ensureIStringIndex(cname, path, cb)
-### ensureNumberIndex(cname, path, cb)
-### ensureArrayIndex(cname, path, cb)
-
-Ensure index presence of String|Number|Array type for JSON field path.
-`IString` is the special type of String index for case insensitive matching.
-
- __Arguments__
-
-  * {String} cname Name of collection
-  * {String} path  JSON field path
-  * {Function} `[cb]` Optional callback function. Callback args: (error)
-
------------------------------------
-
-<a name="rebuildIndex"/>
-### rebuildStringIndex(cname, path, cb)
-### rebuildIStringIndex(cname, path, cb)
-### rebuildNumberIndex(cname, path, cb)
-### rebuildArrayIndex(cname, path, cb)
-
-Rebuild index of String|Number|Array type for JSON field path.
-`IString` is the special type of String index for case insensitive matching.
-
- __Arguments__
-
-  * {String} cname Name of collection
-  * {String} path  JSON field path
-  * {Function} `[cb]` Optional callback function. Callback args: (error)
-
------------------------------------
-
-<a name="dropIndex"/>
-### dropStringIndex(cname, path, cb)
-### dropIStringIndex(cname, path, cb)
-### dropNumberIndex(cname, path, cb)
-### dropArrayIndex(cname, path, cb)
-
-Drop index of String|Number|Array type for JSON field path.
-`IString` is the special type of String index for case insensitive matching.
-
- __Arguments__
-
-  * {String} cname Name of collection
-  * {String} path  JSON field path
-  * {Function} `[cb]` Optional callback function. Callback args: (error)
-
------------------------------------
-
+**[EJDB NodeJS binding page](https://github.com/Softmotions/ejdb/blob/master/node/README.md)**
 
 EJDB Python binding
 ==================================
@@ -725,7 +242,7 @@ EJDB C Library
 One snippet intro
 -----------------------------------
 
-~~~~~~
+```C
 #include <tcejdb/ejdb.h>
 
 static EJDB *jb;
@@ -787,7 +304,7 @@ int main() {
     ejdbdel(jb);
     return 0;
 }
-~~~~~~
+```
 
 You can save this code in `csnippet.c` And build:
 
@@ -813,11 +330,11 @@ Manual installation
 
 ### Build and install
 
-~~~~~~
+```
    cd ./tcejdb
    ./configure --prefix=<installation prefix> && make && make check
    make install
-~~~~~~
+```
 * library name: **tcejdb** (with pkgconfig)
 * main include header: ```<tcejdb/ejdb.h>```
 
diff --git a/node/README.md b/node/README.md
new file mode 100644 (file)
index 0000000..13d1d69
--- /dev/null
@@ -0,0 +1,483 @@
+EJDB NodeJS
+================================================
+
+Installation
+--------------------------------
+**System libraries:**
+
+* g++
+* zlib
+
+On Debian/Ubuntu linux you can install it as follows:
+
+```sh
+sudo apt-get install g++ zlib1g zlib1g-dev
+```
+
+**Installation from node package manager on linux/macos:**
+
+    npm install ejdb
+
+**[Installing EJDB NodeJS module on windows](https://github.com/Softmotions/ejdb/blob/master/tcejdb/WIN32.md#ejdb-nodejs-module-installation)**
+
+
+EJDB NodeJS samples
+---------------------------------
+
+* [node/samples](https://github.com/Softmotions/ejdb/tree/master/node/samples)
+* [node/tests](https://github.com/Softmotions/ejdb/tree/master/node/tests)
+* [nwk-ejdb-address-book](https://github.com/Softmotions/nwk-ejdb-address-book)
+
+
+EJDB NodeJS API
+----------------------------------
+
+<a name="open" />
+### EJDB.open(dbFile, openMode)
+
+Open database. Return database instance handle object.
+<br/>Default open mode: `JBOWRITER | JBOCREAT`.
+<br/>This is blocking function.
+
+__Arguments__
+
+ * {String} dbFile Database main file name
+ * {Number} `[openMode=JBOWRITER | JBOCREAT]` Bitmast of open modes:
+       - `JBOREADER` Open as a reader.
+       - `JBOWRITER` Open as a writer.
+       - `JBOCREAT` Create if db file not exists
+       - `JBOTRUNC` Truncate db.
+
+---------------------------------------
+
+<a name="close" />
+### close()
+
+Close database.
+<br/>If database was not opened it does nothing.
+<br/>This is blocking function.
+
+---------------------------------------
+
+<a name="isOpen"/>
+### isOpen()
+Check if database in opened state.
+
+---------------------------------------
+
+<a name="ensureCollection"/>
+### ensureCollection(cname, copts)
+
+Automatically creates new collection if it does't exists.
+Collection options `copts` applied only for newly created collection.
+For existing collections `copts` takes no effect.
+
+Collection options (copts):
+
+ * cachedrecords : Max number of cached records in shared memory segment. Default: 0
+ * records : Estimated number of records in this collection. Default: 65535.
+ * large : Specifies that the size of the database can be larger than 2GB. Default: false
+ * compressed : If true collection records will be compressed with DEFLATE compression. Default: false.
+
+<br/>This is blocking function.
+
+__Arguments__
+
+ * {String} cname Name of collection.
+ * {Object} `[copts]` Collection options.
+
+---------------------------------------
+
+
+<a name="dropCollection"/>
+### dropCollection(cname, prune, cb)
+
+Drop collection.
+
+Call variations:
+
+    dropCollection(cname)
+    dropCollection(cname, cb)
+    dropCollection(cname, prune, cb)
+
+__Arguments__
+
+ * {String} cname Name of collection.
+ * {Boolean} `[prune=false]` If true the collection data will erased from disk.
+ * {Function} `[cb]` Callback args: (error)
+
+---------------------------------------
+
+<a name="save"/>
+### save(cname, jsarr, cb)
+
+Save/update specified JSON objects in the collection.
+If collection with `cname` does not exists it will be created.
+
+Each persistent object has unique identifier (OID) placed in the `_id` property.
+If a saved object does not have  `_id` it will be autogenerated.
+To identify and update object it should contains `_id` property.
+
+If callback is not provided this function will be synchronous.
+
+Call variations:
+
+    save(cname, <json object>|<Array of json objects>, [options] [cb])
+    save(cname, <json object>|<Array of json objects>, [cb])
+
+NOTE: Field names of passed JSON objects may not contain `$` and `.` characters,
+      error condition will be fired in this case.
+
+__Arguments__
+
+ * {String} **cname** Name of collection.
+ * {Array|Object} jsarr Signle JSON object or array of JSON objects to save
+ * {Function} `[cb]` Callback args: (error, {Array} of OIDs for saved objects)
+
+__Return__
+
+ * {Array} of OIDs of saved objects in synchronous mode otherwise returns {undefined}.
+
+--------------------------------------
+
+<a name="load"/>
+### load(cname, oid, cb)
+
+Loads JSON object identified by OID from the collection.
+If callback is not provided this function will be synchronous.
+
+__Arguments__
+
+ * {String} cname Name of collection
+ * {String} oid Object identifier (OID)
+ * {Function} cb  Callback args: (error, obj)
+        `obj`:  Retrieved JSON object or NULL if it is not found.
+
+__Return__
+
+ * JSON object or {null} if it is not found in synchronous mode otherwise return {undefined}.
+
+--------------------------------------
+
+<a name="remove"/>
+### remove(cname, oid, cb)
+
+Removes JSON object from the collection.
+If callback is not provided this function will be synchronous.
+
+__Arguments__
+
+ * {String} cname Name of collection
+ * {String} oid Object identifier (OID)
+ * {Function} cb  Callback args: (error)
+
+
+--------------------------------------
+
+<a name="find"/>
+### find(cname, qobj, orarr, hints, cb)
+Execute query on collection.
+EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy.
+
+    Supported queries:
+      - Simple matching of String OR Number OR Array value:
+          -   {'fpath' : 'val', ...}
+      - $not Negate operation.
+          -   {'fpath' : {'$not' : val}} //Field not equal to val
+          -   {'fpath' : {'$not' : {'$begin' : prefix}}} //Field not begins with val
+      - $begin String starts with prefix
+          -   {'fpath' : {'$begin' : prefix}}
+      - $gt, $gte (>, >=) and $lt, $lte for number types:
+          -   {'fpath' : {'$gt' : number}, ...}
+      - $bt Between for number types:
+          -   {'fpath' : {'$bt' : [num1, num2]}}
+      - $in String OR Number OR Array val matches to value in specified array:
+          -   {'fpath' : {'$in' : [val1, val2, val3]}}
+      - $nin - Not IN
+      - $strand String tokens OR String array val matches all tokens in specified array:
+          -   {'fpath' : {'$strand' : [val1, val2, val3]}}
+      - $stror String tokens OR String array val matches any token in specified array:
+          -   {'fpath' : {'$stror' : [val1, val2, val3]}}
+      - $exists Field existence matching:
+          -   {'fpath' : {'$exists' : true|false}}
+      - $icase Case insensitive string matching:
+          -  {'fpath' : {'$icase' : 'val1'}} //icase matching
+          Ignore case matching with '$in' operation:
+          -  {'name' : {'$icase' : {'$in' : ['tHéâtre - театр', 'heLLo WorlD']}}}
+          For case insensitive matching you can create special type of string index.
+      - $elemMatch The $elemMatch operator matches more than one component within an array element.
+          -  { array: { $elemMatch: { value1 : 1, value2 : { $gt: 1 } } } }
+          Restriction: only one $elemMatch allowed in context of one array field.
+
+      - Queries can be used to update records:
+
+        $set Field set operation.
+            - {.., '$set' : {'field1' : val1, 'fieldN' : valN}}
+        $upsert Atomic upsert. If matching records are found it will be '$set' operation,
+                otherwise new record will be inserted with fields specified by argment object.
+           - {.., '$upsert' : {'field1' : val1, 'fieldN' : valN}}
+        $inc Increment operation. Only number types are supported.
+            - {.., '$inc' : {'field1' : number, ...,  'field1' : number}
+        $dropall In-place record removal operation.
+            - {.., '$dropall' : true}
+        $addToSet Atomically adds value to the array only if its not in the array already.
+                    If containing array is missing it will be created.
+            - {.., '$addToSet' : {'fpath' : val1, 'fpathN' : valN, ...}}
+        $addToSetAll Batch version if $addToSet
+            - {.., '$addToSetAll' : {'fpath' : [array of values to add], ...}}
+        $pull Atomically removes all occurrences of value from field, if field is an array.
+            - {.., '$pull' : {'fpath' : val1, 'fpathN' : valN, ...}}
+        $pullAll Batch version of $pull
+            - {.., '$pullAll' : {'fpath' : [array of values to remove], ...}}
+
+    NOTE: It is better to execute update queries with `$onlycount=true` hint flag
+         or use the special `update()` method to avoid unnecessarily rows fetching.
+
+    NOTE: Negate operations: $not and $nin not using indexes
+          so they can be slow in comparison to other matching operations.
+
+    NOTE: Only one index can be used in search query operation.
+
+    NOTE: If callback is not provided this function will be synchronous.
+
+    QUERY HINTS (specified by `hints` argument):
+      - $max Maximum number in the result set
+      - $skip Number of skipped results in the result set
+      - $orderby Sorting order of query fields.
+      - $onlycount true|false If `true` only count of matching records will be returned
+                              without placing records in result set.
+      - $fields Set subset of fetched fields
+           If a field presented in $orderby clause it will be forced to include in resulting records.
+           Example:
+           hints:    {
+                       "$orderby" : { //ORDER BY field1 ASC, field2 DESC
+                           "field1" : 1,
+                           "field2" : -1
+                       },
+                       "$fields" : { //SELECT ONLY {_id, field1, field2}
+                           "field1" : 1,
+                           "field2" : 1
+                       }
+                     }
+
+    Many C API query examples can be found in `tcejdb/testejdb/t2.c` test case.
+
+    To traverse selected records cursor object is used:
+      - Cursor#next() Move cursor to the next record and returns true if next record exists.
+      - Cursor#hasNext() Returns true if cursor can be placed to the next record.
+      - Cursor#field(name) Retrieve value of the specified field of the current JSON object record.
+      - Cursor#object() Retrieve whole JSON object with all fields.
+      - Cursor#reset() Reset cursor to its initial state.
+      - Cursor#length Read-only property: Number of records placed into cursor.
+      - Cursor#pos Read/Write property: You can set cursor position: 0 <= pos < length
+      - Cursor#close() Closes cursor and free cursor resources. Cursor cant be used in closed state.
+
+    Call variations of find():
+       - find(cname, [cb])
+       - find(cname, qobj, [cb])
+       - find(cname, qobj, hints, [cb])
+       - find(cname, qobj, qobjarr, [cb])
+       - find(cname, qobj, qobjarr, hints, [cb])
+
+ __Arguments__
+
+ * {String} cname Name of collection
+ * {Object} qobj Main JSON query object
+ * {Array} `[orarr]` Array of additional OR query objects (joined with OR predicate).
+ * {Object} `[hints]` JSON object with query hints.
+ * {Function} cb Callback args: (error, cursor, count)
+            `cursor`: Cursor object to traverse records
+      qobj      `count`:  Total number of selected records
+
+__Return__
+
+ * If callback is provided returns {undefined}
+ * If no callback and `$onlycount` hint is set returns count {Number}.
+ * If no callback and no `$onlycount` hint returns cursor {Object}.
+
+ --------------------------------------------
+
+<a name="findOne"/>
+### findOne(cname, qobj, orarr, hints, cb)
+Same as #find() but retrieves only one matching JSON object.
+
+Call variations of findOne():
+
+    findOne(cname, [cb])
+    findOne(cname, qobj, [cb])
+    findOne(cname, qobj, hints, [cb])
+    findOne(cname, qobj, qobjarr, [cb])
+    findOne(cname, qobj, qobjarr, hints, [cb])
+
+__Arguments__
+
+ * {String} cname Name of collection
+ * {Object} qobj Main JSON query object
+ * {Array} `[orarr]` Array of additional OR query objects (joined with OR predicate).
+ * {Object} `[hints]` JSON object with query hints.
+ * {Function} cb Callback args: (error, obj)
+             `obj`  Retrieved JSON object or NULL if it is not found.
+
+__Return__
+
+ * If callback is provided returns {undefined}
+ * If no callback is provided returns found {Object} or {null}
+
+-----------------------------------
+<a name="findOne"/>
+### update(cname, qobj, orarr, hints, cb)
+Convenient method to execute update queries.
+
+ * `$set` Field set operation:
+    - {some fields for selection, '$set' : {'field1' : {obj}, ...,  'field1' : {obj}}}
+ * `$upsert` Atomic upsert. If matching records are found it will be '$set' operation,
+ otherwise new record will be inserted with fields specified by argment object.
+    - {.., '$upsert' : {'field1' : val1, 'fieldN' : valN}}
+ * `$inc` Increment operation. Only number types are supported.
+    - {some fields for selection, '$inc' : {'field1' : number, ...,  'field1' : {number}}
+ * `$dropall` In-place record removal operation.
+    - {some fields for selection, '$dropall' : true}
+ * `$addToSet` | `$addToSetAll` Atomically adds value to the array only if its not in the array already.
+ If containing array is missing it will be created.
+    - {.., '$addToSet' : {'fpath' : val1, 'fpathN' : valN, ...}}
+ * `$pull` | `pullAll` Atomically removes all occurrences of value from field, if field is an array.
+    - {.., '$pull' : {'fpath' : val1, 'fpathN' : valN, ...}}
+
+Call variations of update():
+
+    update(cname, [cb])
+    update(cname, qobj, [cb])
+    update(cname, qobj, hints, [cb])
+    update(cname, qobj, qobjarr, [cb])
+    update(cname, qobj, qobjarr, hints, [cb])
+
+__Arguments__
+
+ * {String} cname Name of collection
+ * {Object} qobj Update JSON query object
+ * {Array} `[orarr]` Array of additional OR query objects (joined with OR predicate).
+ * {Object} `[hints]` JSON object with query hints.
+ * {Function} cb Callback args: (error, count)
+             `count`  The number of updated records.
+
+__Return__
+
+ * If callback is provided returns {undefined}.
+ * If no callback is provided returns {Number} of updated objects.
+
+
+-----------------------------------
+
+<a name="count"/>
+### count(cname, qobj, orarr, hints, cb)
+Convenient count(*) operation.
+
+Call variations of count():
+
+    count(cname, [cb])
+    count(cname, qobj, [cb])
+    count(cname, qobj, hints, [cb])
+    count(cname, qobj, qobjarr, [cb])
+    count(cname, qobj, qobjarr, hints, [cb])
+
+__Arguments__
+
+ * {String} cname Name of collection
+ * {Object} qobj Main JSON query object
+ * {Array} `[orarr]` Array of additional OR query objects (joined with OR predicate).
+ * {Object} `[hints]` JSON object with query hints.
+ * {Function} cb Callback args: (error, count)
+              `count`:  Number of matching records.
+
+__Return__
+
+ * If callback is provided returns {undefined}.
+ * If no callback is provided returns {Number} of matched object.
+
+-----------------------------------
+
+<a name="sync"/>
+### sync(cb)
+Synchronize entire EJDB database with disk.
+
+__Arguments__
+
+ * {Function} cb Callback args: (error)
+
+-----------------------------------
+
+<a name="dropIndexes"/>
+### dropIndexes(cname, path, cb)
+Drop indexes of all types for JSON field path.
+
+__Arguments__
+
+ * {String} cname Name of collection
+ * {String} path  JSON field path
+ * {Function} `[cb]` Optional callback function. Callback args: (error)
+
+------------------------------------
+
+<a name="optimizeIndexes"/>
+### optimizeIndexes(cname, path, cb)
+Optimize indexes of all types for JSON field path.
+Performs B+ tree index file optimization.
+
+ __Arguments__
+
+  * {String} cname Name of collection
+  * {String} path  JSON field path
+  * {Function} `[cb]` Optional callback function. Callback args: (error)
+
+-----------------------------------
+
+<a name="ensureIndex"/>
+### ensureStringIndex(cname, path, cb)
+### ensureIStringIndex(cname, path, cb)
+### ensureNumberIndex(cname, path, cb)
+### ensureArrayIndex(cname, path, cb)
+
+Ensure index presence of String|Number|Array type for JSON field path.
+`IString` is the special type of String index for case insensitive matching.
+
+ __Arguments__
+
+  * {String} cname Name of collection
+  * {String} path  JSON field path
+  * {Function} `[cb]` Optional callback function. Callback args: (error)
+
+-----------------------------------
+
+<a name="rebuildIndex"/>
+### rebuildStringIndex(cname, path, cb)
+### rebuildIStringIndex(cname, path, cb)
+### rebuildNumberIndex(cname, path, cb)
+### rebuildArrayIndex(cname, path, cb)
+
+Rebuild index of String|Number|Array type for JSON field path.
+`IString` is the special type of String index for case insensitive matching.
+
+ __Arguments__
+
+  * {String} cname Name of collection
+  * {String} path  JSON field path
+  * {Function} `[cb]` Optional callback function. Callback args: (error)
+
+-----------------------------------
+
+<a name="dropIndex"/>
+### dropStringIndex(cname, path, cb)
+### dropIStringIndex(cname, path, cb)
+### dropNumberIndex(cname, path, cb)
+### dropArrayIndex(cname, path, cb)
+
+Drop index of String|Number|Array type for JSON field path.
+`IString` is the special type of String index for case insensitive matching.
+
+ __Arguments__
+
+  * {String} cname Name of collection
+  * {String} path  JSON field path
+  * {Function} `[cb]` Optional callback function. Callback args: (error)
+
+-----------------------------------
index fcb212d..411fba1 100644 (file)
@@ -1113,7 +1113,7 @@ static bool _importcoll(EJDB *jb, const char *bspath, TCLIST *cnames, int flags,
     if (!mjson) {
         err = true;
         if (log) {
-            tcxstrprintf(log, "\nERROR: Error reading file: '%s'", tcxstrptr(xmetapath));
+            tcxstrprintf(log, "\nERROR: Error reading the file: '%s'", tcxstrptr(xmetapath));
         }
         _ejdbsetecode2(jb, TCEREAD, __FILE__, __LINE__, __func__, true);
         goto finish;
index 749b1ee..b9b135b 100644 (file)
@@ -511,33 +511,53 @@ EJDB_EXPORT bson* ejdbmeta(EJDB *jb);
 /** Export/Import settings used in `ejdbexport()` and `ejdbimport()` functions. */
 enum {
     JBJSONEXPORT = 1, //If set json collection data will be exported as JSON files instead of BSON.
-    JBIMPORTUPDATE = 2, //Update existing collection entries with imported ones. Collections will not be recreated and its options are ignored.
-    JBIMPORTREPLACE = 3 //Recreate existing collections and replace all collection data with imported entries.
+    JBIMPORTUPDATE = 1 << 1, //Update existing collection entries with imported ones. Collections will not be recreated and its options are ignored.
+    JBIMPORTREPLACE = 1 << 2 //Recreate existing collections and replace all collection data with imported entries.
 };
 
 /**
- * Export database collections data to the specified location.
- * Database read lock will be taken on each collection
- * @param path Directory name in which data will exported.
- * @param colnames List of collection names to export. If its value is `NULL` then all existing collections will be exported.
- * @param flags. Can be set to `JBJSONEXPORT` in order to export collection data into JSON instead of BSON.
- * @param log Optional opration log buffer.
+ * Exports database collections data to the specified directory.
+ * Database read lock will be taken on each collection.
+ *
+ * NOTE: Only data exported as BSONs can be imported with `ejdbimport()`
+ *
+ * @param jb EJDB database handle.
+ * @param path The directory path in which data will be exported.
+ * @param cnames List of collection names to export. `NULL` implies that all existing collections will be exported.
+ * @param flags. Can be set to `JBJSONEXPORT` in order to export data as JSON files instead exporting into BSONs.
+ * @param log Optional operation string log buffer.
  * @return on sucess `true`
  */
 EJDB_EXPORT bool ejdbexport(EJDB *jb, const char *path, TCLIST *cnames, int flags, TCXSTR *log);
 
 /**
- * TODO
- * @param jb
- * @param path
- * @param cnames
- * @param flags
- * @param log Optional opration log buffer.
+ * Imports previously exported collections data into ejdb.
+ * Global database write lock will be applied during import operation.
+ *
+ * NOTE: Only data exported as BSONs can be imported with `ejdbimport()`
+ *
+ * @param jb EJDB database handle.
+ * @param path The directory path in which data resides.
+ * @param cnames List of collection names to import. `NULL` implies that all collections found in `path` will be imported.
+ * @param flags Can be one of:
+ *             `JBIMPORTUPDATE`  Update existing collection entries with imported ones.
+ *                               Existing collections will not be recreated.
+ *                               For existing collections options will not be imported.
+ *
+ *             `JBIMPORTREPLACE` Recreate existing collections and replace
+ *                               all their data with imported entries.
+ *                               Collections options will be imported.
+ *
+ *             `0`              Implies `JBIMPORTUPDATE`
+ * @param log Optional operation log buffer.
  * @return
  */
 EJDB_EXPORT bool ejdbimport(EJDB *jb, const char *path, TCLIST *cnames, int flags, TCXSTR *log);
 
 
+EJDB_EXPORT bool ejdbcommand(EJDB *jb)
+
+
 EJDB_EXTERN_C_END
 
 #endif        /* EJDB_H */
index 7abe7bf..5b60b72 100644 (file)
@@ -84,7 +84,6 @@ void testBSONExportImport() {
     }
     CU_ASSERT_TRUE(rv);
 
-
     bson *ometa = ejdbmeta(jb);
     CU_ASSERT_TRUE_FATAL(ometa != NULL);
 
@@ -95,11 +94,18 @@ void testBSONExportImport() {
 
     jb = ejdbnew();
     CU_ASSERT_TRUE_FATAL(ejdbopen(jb, "dbt4_export", JBOWRITER | JBOCREAT));
+
+    coll = ejdbgetcoll(jb, "col1");
+    CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
+    bson_init(&bv1);
+    bson_append_int(&bv1, "e", 2);
+    bson_finish(&bv1);
+    CU_ASSERT_TRUE(ejdbsavebson(coll, &bv1, &oid));
+    bson_destroy(&bv1);
+
     rv = ejdbimport(jb, "testBSONExportImport", cnames, JBIMPORTREPLACE, log);
     CU_ASSERT_TRUE(rv);
 
-    fprintf(stderr, "\n Import log: %s\n", TCXSTRPTR(log));
-
     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "Reading 'testBSONExportImport/col1.bson'"));
     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "Replacing all data in 'col1'"));
     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "1 objects imported into 'col1'"));
@@ -121,15 +127,44 @@ void testBSONExportImport() {
     CU_ASSERT_TRUE(bson_compare(bson_data(ometa), bson_data(nmeta), "collections.1.indexes.1.type", strlen("collections.1.indexes.1.type")) == 0);
     CU_ASSERT_TRUE(bson_compare(bson_data(ometa), bson_data(nmeta), "collections.1.indexes.1.records", strlen("collections.1.indexes.1.records")) == 0);
 
-    bson_del(ometa);
-    bson_del(nmeta);
+    ejdbclose(jb);
+    ejdbdel(jb);
 
-    tcxstrdel(log);
+    jb = ejdbnew();
+    CU_ASSERT_TRUE_FATAL(ejdbopen(jb, "dbt4_export", JBOWRITER | JBOCREAT | JBOTRUNC));
+
+    coll = ejdbcreatecoll(jb, "col1", NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
+    bson_init(&bv1);
+    bson_append_int(&bv1, "e", 2);
+    bson_finish(&bv1);
+    CU_ASSERT_TRUE(ejdbsavebson(coll, &bv1, &oid));
+
+    EJQ *q = ejdbcreatequery(jb, &bv1, NULL, 0, NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(q);
+    uint32_t count = 0;
+    ejdbqryexecute(coll, q, &count, JBQRYCOUNT, NULL);
+    CU_ASSERT_EQUAL(count, 1);
+
+    rv = ejdbimport(jb, "testBSONExportImport", NULL, JBIMPORTUPDATE, NULL);
+    CU_ASSERT_TRUE(rv);
+
+    coll = ejdbcreatecoll(jb, "col1", NULL);
+    ejdbqryexecute(coll, q, &count, JBQRYCOUNT, NULL);
+    CU_ASSERT_EQUAL(count, 1);
+
+    ejdbquerydel(q);
+    bson_destroy(&bv1);
     ejdbclose(jb);
     ejdbdel(jb);
+
+    bson_del(ometa);
+    bson_del(nmeta);
+    tcxstrdel(log);
     tclistdel(cnames);
 }
 
+
 int init_suite(void) {
     return 0;
 }