From 3760b5c06322d38ece51d77f975c174892f249f6 Mon Sep 17 00:00:00 2001 From: adam Date: Wed, 17 Jul 2013 16:22:28 +0700 Subject: [PATCH] merge with master --- README.md | 519 ++------------------------------------------------- node/README.md | 483 +++++++++++++++++++++++++++++++++++++++++++++++ tcejdb/ejdb.c | 2 +- tcejdb/ejdb.h | 48 +++-- tcejdb/testejdb/t4.c | 47 ++++- 5 files changed, 577 insertions(+), 522 deletions(-) create mode 100644 node/README.md diff --git a/README.md b/README.md index 834b7be..b9a6550 100644 --- 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 ----------------------------------- - - -### EJDB.open(dbFile, openMode) - -Open database. Return database instance handle object. -
Default open mode: `JBOWRITER | JBOCREAT`. -
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. - ---------------------------------------- - -
-### close() - -Close database. -
If database was not opened it does nothing. -
This is blocking function. - ---------------------------------------- - -
-### isOpen() -Check if database in opened state. - ---------------------------------------- - - -### 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. - -
This is blocking function. - -__Arguments__ - - * {String} cname Name of collection. - * {Object} `[copts]` Collection options. - ---------------------------------------- - - -
-### 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) - ---------------------------------------- - - -### 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, |, [options] [cb]) - save(cname, |, [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}. - --------------------------------------- - - -### 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}. - --------------------------------------- - - -### 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) - - --------------------------------------- - - -### 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}. - - -------------------------------------------- - - -### 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} - ------------------------------------ - -### 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. - - ------------------------------------ - - -### 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. - ------------------------------------ - - -### sync(cb) -Synchronize entire EJDB database with disk. - -__Arguments__ - - * {Function} cb Callback args: (error) - ------------------------------------ - - -### 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) - ------------------------------------- - - -### 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) - ------------------------------------ - - -### 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) - ------------------------------------ - - -### 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) - ------------------------------------ - - -### 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 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= && make && make check make install -~~~~~~ +``` * library name: **tcejdb** (with pkgconfig) * main include header: `````` diff --git a/node/README.md b/node/README.md new file mode 100644 index 0000000..13d1d69 --- /dev/null +++ b/node/README.md @@ -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 +---------------------------------- + + +### EJDB.open(dbFile, openMode) + +Open database. Return database instance handle object. +
Default open mode: `JBOWRITER | JBOCREAT`. +
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. + +--------------------------------------- + +
+### close() + +Close database. +
If database was not opened it does nothing. +
This is blocking function. + +--------------------------------------- + +
+### isOpen() +Check if database in opened state. + +--------------------------------------- + + +### 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. + +
This is blocking function. + +__Arguments__ + + * {String} cname Name of collection. + * {Object} `[copts]` Collection options. + +--------------------------------------- + + +
+### 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) + +--------------------------------------- + + +### 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, |, [options] [cb]) + save(cname, |, [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}. + +-------------------------------------- + + +### 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}. + +-------------------------------------- + + +### 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) + + +-------------------------------------- + + +### 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}. + + -------------------------------------------- + + +### 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} + +----------------------------------- + +### 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. + + +----------------------------------- + + +### 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. + +----------------------------------- + + +### sync(cb) +Synchronize entire EJDB database with disk. + +__Arguments__ + + * {Function} cb Callback args: (error) + +----------------------------------- + + +### 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) + +------------------------------------ + + +### 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) + +----------------------------------- + + +### 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) + +----------------------------------- + + +### 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) + +----------------------------------- + + +### 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) + +----------------------------------- diff --git a/tcejdb/ejdb.c b/tcejdb/ejdb.c index fcb212d..411fba1 100644 --- a/tcejdb/ejdb.c +++ b/tcejdb/ejdb.c @@ -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; diff --git a/tcejdb/ejdb.h b/tcejdb/ejdb.h index 749b1ee..b9b135b 100644 --- a/tcejdb/ejdb.h +++ b/tcejdb/ejdb.h @@ -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 */ diff --git a/tcejdb/testejdb/t4.c b/tcejdb/testejdb/t4.c index 7abe7bf..5b60b72 100644 --- a/tcejdb/testejdb/t4.c +++ b/tcejdb/testejdb/t4.c @@ -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; } -- 2.7.4