From d978d99dc66223e6095f8af88f1d4e00ca988e07 Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 19 Aug 2013 17:12:10 +0700 Subject: [PATCH] #91 v1.1.19 --- Changelog | 6 +++ Makefile | 1 - README.md | 6 ++- node/README.md | 3 ++ node/ejdb.js | 1 + package.json | 6 +-- tcejdb/Changelog | 6 +++ tcejdb/WIN32.md | 4 +- tcejdb/configure | 18 +++---- tcejdb/configure.ac | 2 +- tcejdb/debian/changelog | 6 +++ tcejdb/ejdb.c | 62 +++++++++++++++++++---- tcejdb/ejdb.h | 1 + tcejdb/tcutil.h | 2 +- tcejdb/testejdb/t2.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++- 15 files changed, 222 insertions(+), 31 deletions(-) diff --git a/Changelog b/Changelog index 583e940..3c382b4 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,9 @@ +libtcejdb (1.1.19-4) testing; urgency=low + + * Added support for MongoDB $(query) update operator #91 + + -- Anton Adamansky Mon, 19 Aug 2013 16:07:29 +0700 + libtcejdb (1.1.18) testing; urgency=low * Added support MongoDB $(projection) operator #15 diff --git a/Makefile b/Makefile index 7a28c0b..2ff3d36 100644 --- a/Makefile +++ b/Makefile @@ -40,5 +40,4 @@ init: - cp ./tcejdb/debian/changelog ./Changelog - cp ./tcejdb/debian/changelog ./tcejdb/Changelog - .PHONY: all clean deb-packages deb-source-packages init initdeb diff --git a/README.md b/README.md index fa541eb..be1f38d 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ JSON representation of queries and data implemented with API based on [C BSON](h News =============================== +* `2013-08-19` **[v1.1.19 Added support the long awaited mongodb update positional operator] (https://github.com/Softmotions/ejdb/wiki/V1.1.19)** * `2013-08-11` **[v1.1.18 Added support for mongodb $ projection] (https://github.com/Softmotions/ejdb/wiki/V1.1.18)** * `2013-08-08` **[v1.1.17 Now supported $and & $or mongodb operators] (https://github.com/Softmotions/ejdb/issues/81)** * `2013-07-15` **[Google Go binding] (https://github.com/mkilling/goejdb)** @@ -466,8 +467,8 @@ gcc -o csnippet csnippet.o -ltcejdb Building & Installation -------------------------------- - -[Installing on Debian/Ubuntu](https://github.com/Softmotions/ejdb/wiki/Debian-Ubuntu-installation) + * [Installation on windows](https://github.com/Softmotions/ejdb/blob/master/tcejdb/WIN32.md) + * [Installation on Debian/Ubuntu](https://github.com/Softmotions/ejdb/wiki/Debian-Ubuntu-installation) Manual installation ------------------------------- @@ -539,6 +540,7 @@ Queries * Example: {z : 33, $and : [ {$or : [{a : 1}, {b : 2}]}, {$or : [{c : 5}, {d : 7}]} ] } * * - Mongodb $(projection) operator supported. (http://docs.mongodb.org/manual/reference/projection/positional/#proj._S_) + * - Mongodb positional $ update operator supported. (http://docs.mongodb.org/manual/reference/operator/positional/) * * * - Queries can be used to update records: diff --git a/node/README.md b/node/README.md index 5613828..1aa2e12 100644 --- a/node/README.md +++ b/node/README.md @@ -213,6 +213,9 @@ EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy. - {..., $or : [subq1, subq2, ...] } Example: {z : 33, $and : [ {$or : [{a : 1}, {b : 2}]}, {$or : [{c : 5}, {d : 7}]} ] } + - Mongodb $(projection) operator supported. (http://docs.mongodb.org/manual/reference/projection/positional/#proj._S_) + - Mongodb positional $ update operator supported. (http://docs.mongodb.org/manual/reference/operator/positional/) + - Queries can be used to update records: $set Field set operation. diff --git a/node/ejdb.js b/node/ejdb.js index 36982fc..cd42ba4 100644 --- a/node/ejdb.js +++ b/node/ejdb.js @@ -326,6 +326,7 @@ function parseQueryArgs(args) { * Example: {z : 33, $and : [ {$or : [{a : 1}, {b : 2}]}, {$or : [{c : 5}, {d : 7}]} ] } * * - Mongodb $(projection) operator supported. (http://docs.mongodb.org/manual/reference/projection/positional/#proj._S_) + * - Mongodb positional $ update operator supported. (http://docs.mongodb.org/manual/reference/operator/positional/) * * - Queries can be used to update records: * diff --git a/package.json b/package.json index 3f78788..b11f1d1 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name" : "ejdb", - "version" : "1.1.18-2", + "version" : "1.1.19-1", "config" : { - "windownloadurl_ia32" : "http://dl.dropboxusercontent.com/u/4709222/ejdb/tcejdb-1.1.18-mingw32-i686.zip", - "windownloadurl_x64" : "http://dl.dropboxusercontent.com/u/4709222/ejdb/tcejdb-1.1.18-mingw32-x86_64.zip" + "windownloadurl_ia32" : "http://dl.dropboxusercontent.com/u/4709222/ejdb/tcejdb-1.1.19-mingw32-i686.zip", + "windownloadurl_x64" : "http://dl.dropboxusercontent.com/u/4709222/ejdb/tcejdb-1.1.19-mingw32-x86_64.zip" }, "main" : "node/ejdb.js", "homepage" : "http://ejdb.org", diff --git a/tcejdb/Changelog b/tcejdb/Changelog index 583e940..3c382b4 100644 --- a/tcejdb/Changelog +++ b/tcejdb/Changelog @@ -1,3 +1,9 @@ +libtcejdb (1.1.19-4) testing; urgency=low + + * Added support for MongoDB $(query) update operator #91 + + -- Anton Adamansky Mon, 19 Aug 2013 16:07:29 +0700 + libtcejdb (1.1.18) testing; urgency=low * Added support MongoDB $(projection) operator #15 diff --git a/tcejdb/WIN32.md b/tcejdb/WIN32.md index b8b3308..9653031 100644 --- a/tcejdb/WIN32.md +++ b/tcejdb/WIN32.md @@ -1,8 +1,8 @@ Precompiled windows binaries ========================================= -* [tcejdb-1.1.18-mingw32-i686](https://dl.dropboxusercontent.com/u/4709222/ejdb/tcejdb-1.1.18-mingw32-i686.zip) -* [tcejdb-1.1.18-mingw32-x86_64](https://dl.dropboxusercontent.com/u/4709222/ejdb/tcejdb-1.1.18-mingw32-x86_64.zip) +* [tcejdb-1.1.19-mingw32-i686](https://dl.dropboxusercontent.com/u/4709222/ejdb/tcejdb-1.1.19-mingw32-i686.zip) +* [tcejdb-1.1.19-mingw32-x86_64](https://dl.dropboxusercontent.com/u/4709222/ejdb/tcejdb-1.1.19-mingw32-x86_64.zip) **[Installing EJDB NodeJS win32 module](#ejdb-nodejs-module-installation)** diff --git a/tcejdb/configure b/tcejdb/configure index 5e0dab5..a592b48 100755 --- a/tcejdb/configure +++ b/tcejdb/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for tcejdb 1.1.18. +# Generated by GNU Autoconf 2.69 for tcejdb 1.1.19. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='tcejdb' PACKAGE_TARNAME='tcejdb' -PACKAGE_VERSION='1.1.18' -PACKAGE_STRING='tcejdb 1.1.18' +PACKAGE_VERSION='1.1.19' +PACKAGE_STRING='tcejdb 1.1.19' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1268,7 +1268,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 tcejdb 1.1.18 to adapt to many kinds of systems. +\`configure' configures tcejdb 1.1.19 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1333,7 +1333,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of tcejdb 1.1.18:";; + short | recursive ) echo "Configuration of tcejdb 1.1.19:";; esac cat <<\_ACEOF @@ -1439,7 +1439,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -tcejdb configure 1.1.18 +tcejdb configure 1.1.19 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1737,7 +1737,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 tcejdb $as_me 1.1.18, which was +It was created by tcejdb $as_me 1.1.19, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -5273,7 +5273,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 tcejdb $as_me 1.1.18, which was +This file was extended by tcejdb $as_me 1.1.19, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -5326,7 +5326,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="\\ -tcejdb config.status 1.1.18 +tcejdb config.status 1.1.19 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/tcejdb/configure.ac b/tcejdb/configure.ac index 8e7d3d2..00858c0 100644 --- a/tcejdb/configure.ac +++ b/tcejdb/configure.ac @@ -10,7 +10,7 @@ test -n "$CPPFLAGS" && MYCPPFLAGS="$CPPFLAGS $MYCPPFLAGS" test -n "$LDFLAGS" && MYLDFLAGS="$LDFLAGS $MYLDFLAGS" # Package name -AC_INIT(tcejdb, 1.1.18) +AC_INIT(tcejdb, 1.1.19) AC_CANONICAL_HOST # Package information diff --git a/tcejdb/debian/changelog b/tcejdb/debian/changelog index 583e940..3c382b4 100644 --- a/tcejdb/debian/changelog +++ b/tcejdb/debian/changelog @@ -1,3 +1,9 @@ +libtcejdb (1.1.19-4) testing; urgency=low + + * Added support for MongoDB $(query) update operator #91 + + -- Anton Adamansky Mon, 19 Aug 2013 16:07:29 +0700 + libtcejdb (1.1.18) testing; urgency=low * Added support MongoDB $(projection) operator #15 diff --git a/tcejdb/ejdb.c b/tcejdb/ejdb.c index 8640e3b..e5164da 100644 --- a/tcejdb/ejdb.c +++ b/tcejdb/ejdb.c @@ -2682,14 +2682,19 @@ static bool _exec$do(_QRYCTX *ctx, const void *bsbuf, bson *bsout) { return true; } +//Create update BSON object for $set and $inc operations static bson* _qfgetupdateobj(const EJQF *qf) { assert(qf->updateobj); if (!qf->$ufields || TCLISTNUM(qf->$ufields) < 1) { //we do not ref $(query) fields. return qf->updateobj; } - const EJQ *q = qf->q; + const EJQ *q = qf->q; + char pbuf[BSON_MAX_FPATH_LEN + 1]; + int ppos = 0; + bson_iterator it; + bson_type bt; bson *ret = bson_create(); - bson_init(ret); + bson_init(ret); for (int i = 0; i < TCLISTNUM(qf->$ufields); ++i) { const char *uf = TCLISTVALPTR(qf->$ufields, i); for (int j = 0; *(q->allqfields + j) != '\0'; ++j) { @@ -2699,15 +2704,45 @@ static bson* _qfgetupdateobj(const EJQF *qf) { } for (int k = 0; k < TCLISTNUM(kqf->$uslots); ++k) { USLOT *uslot = TCLISTVALPTR(kqf->$uslots, k); - if (uslot->op == uf) { - - //todo + if (uslot->op == uf && uslot->mpos >= 0) { + char *dp = strchr(uf, '$'); + assert(dp); + ppos = (dp - uf); + assert(ppos == uslot->dpos + 1); + if (ppos < 1 || ppos >= BSON_MAX_FPATH_LEN - 1) { + break; + } + memcpy(pbuf, uf, ppos); + int wl = bson_numstrn(pbuf + ppos, (BSON_MAX_FPATH_LEN - ppos), uslot->mpos); + if (wl >= BSON_MAX_FPATH_LEN - ppos) { //output is truncated + break; + } + ppos += wl; + //copy suffix + for (int fpos = (dp - uf) + 1; ppos < BSON_MAX_FPATH_LEN && *(uf + fpos) != '\0';) { + pbuf[ppos++] = *(uf + fpos++); + } + assert(ppos <= BSON_MAX_FPATH_LEN); + pbuf[ppos] = '\0'; + bt = bson_find(&it, qf->updateobj, uf); + if (bt == BSON_EOO) { + assert(false); + break; + } + bson_append_field_from_iterator2(pbuf, &it, ret); break; } } } } + BSON_ITERATOR_INIT(&it, qf->updateobj); + while ((bt = bson_iterator_next(&it)) != BSON_EOO) { + const char *key = bson_iterator_key(&it); + if (strchr(key, '$') == NULL) { + bson_append_field_from_iterator2(key, &it, ret); + } + } bson_finish(ret); return ret; } @@ -2790,26 +2825,30 @@ static bool _qryupdate(_QRYCTX *ctx, void *bsbuf, int bsbufsz) { } } } - - + if (setqf) { //$set + bson *updobj = _qfgetupdateobj(setqf); update = true; bson_init_size(&bsout, bsbufsz); - int err = bson_merge3(bsbuf, bson_data(setqf->updateobj), &bsout); + int err = bson_merge3(bsbuf, bson_data(updobj), &bsout); if (err) { rv = false; _ejdbsetecode(coll->jb, JBEQUPDFAILED, __FILE__, __LINE__, __func__); } bson_finish(&bsout); + if (updobj != setqf->updateobj) { + bson_del(updobj); + } } if (!rv) { goto finish; } if (incqf) { //$inc + bson *updobj = _qfgetupdateobj(incqf); if (!bsout.data) { bson_create_from_buffer2(&bsout, bsbuf, bsbufsz); } - BSON_ITERATOR_INIT(&it, incqf->updateobj); + BSON_ITERATOR_INIT(&it, updobj); while ((bt = bson_iterator_next(&it)) != BSON_EOO) { if (!BSON_IS_NUM_TYPE(bt)) { continue; @@ -2843,6 +2882,9 @@ static bool _qryupdate(_QRYCTX *ctx, void *bsbuf, int bsbufsz) { update = true; } } + if (updobj != incqf->updateobj) { + bson_del(updobj); + } if (!rv) { goto finish; } @@ -4605,7 +4647,7 @@ static int _parse_qobj_impl(EJDB *jb, EJQ *q, bson_iterator *it, TCLIST *qlist, BSON_ITERATOR_SUBITERATOR(it, &sit); while ((sbt = bson_iterator_next(&sit)) != BSON_EOO) { if ((qf.flags & EJCONDALL) && sbt != BSON_ARRAY) { - //$addToSetAll & $pullAll accepts only arrays + //$addToSetAll & $pullAll accepts only a"$set"rrays continue; } if (!(qf.flags & EJCONDALL) && (qf.flags & (EJCONDSET | EJCONDINC))) { //Checking the $(query) positional operator. diff --git a/tcejdb/ejdb.h b/tcejdb/ejdb.h index 9ecd1fb..c856c27 100644 --- a/tcejdb/ejdb.h +++ b/tcejdb/ejdb.h @@ -300,6 +300,7 @@ EJDB_EXPORT bson* ejdbloadbson(EJCOLL *coll, const bson_oid_t *oid); * Example: {z : 33, $and : [ {$or : [{a : 1}, {b : 2}]}, {$or : [{c : 5}, {d : 7}]} ] } * * - Mongodb $(projection) operator supported. (http://docs.mongodb.org/manual/reference/projection/positional/#proj._S_) + * - Mongodb positional $ update operator supported. (http://docs.mongodb.org/manual/reference/operator/positional/) * * - Queries can be used to update records: * diff --git a/tcejdb/tcutil.h b/tcejdb/tcutil.h index b375f4a..6e9cd58 100644 --- a/tcejdb/tcutil.h +++ b/tcejdb/tcutil.h @@ -3733,7 +3733,7 @@ typedef unsigned char TCBITMAP; /* type of a bit map object */ #include -#define _TC_VERSION "1.1.18" +#define _TC_VERSION "1.1.19" #define _TC_LIBVER 911 #define _TC_FORMATVER "1.0" diff --git a/tcejdb/testejdb/t2.c b/tcejdb/testejdb/t2.c index fe06be9..7eb9d29 100644 --- a/tcejdb/testejdb/t2.c +++ b/tcejdb/testejdb/t2.c @@ -4509,7 +4509,7 @@ void testTicket81() { // https://github.com/Softmotions/ejdb/issues/15 // http://docs.mongodb.org/manual/reference/projection/positional/#proj._S_ -void test$projection() { +void testDQprojection() { EJCOLL *coll = ejdbcreatecoll(jb, "f_projection", NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(coll); @@ -4649,6 +4649,129 @@ void test$projection() { bson_destroy(&bsq1); } + +// $(query) +// https://github.com/Softmotions/ejdb/issues/15 +// http://docs.mongodb.org/manual/reference/projection/positional/#proj._S_ + +void testDQupdate() { + EJCOLL *coll = ejdbcreatecoll(jb, "f_update", NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(coll); + + bson b; + bson_oid_t oid; + + bson_init(&b); + bson_append_int(&b, "z", 33); + bson_append_start_array(&b, "arr"); + bson_append_int(&b, "0", 0); + bson_append_int(&b, "1", 1); + bson_append_int(&b, "2", 2); + bson_append_int(&b, "3", 3); + bson_append_finish_array(&b); + bson_finish(&b); + CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid)); + bson_destroy(&b); + + bson bsq1; + bson_init_as_query(&bsq1); + bson_append_int(&bsq1, "z", 33); + bson_append_int(&bsq1, "arr", 1); + bson_append_start_object(&bsq1, "$set"); + bson_append_int(&bsq1, "arr.$", 4); + bson_append_finish_object(&bsq1); + bson_finish(&bsq1); + + TCXSTR *log = tcxstrnew(); + uint32_t count; + EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(q1); + ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log); + CU_ASSERT_EQUAL(count, 1); + + ejdbquerydel(q1); + tcxstrdel(log); + bson_destroy(&bsq1); + + //Now check It + bson_init_as_query(&bsq1); + bson_append_int(&bsq1, "z", 33); + bson_append_int(&bsq1, "arr", 4); + bson_finish(&bsq1); + + log = tcxstrnew(); + q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(q1); + ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log); + CU_ASSERT_EQUAL(count, 1); + + ejdbquerydel(q1); + tcxstrdel(log); + bson_destroy(&bsq1); + +} + +void testDQupdate2() { + EJCOLL *coll = ejdbcreatecoll(jb, "f_update", NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(coll); + + bson b; + bson_oid_t oid; + + bson_init(&b); + bson_append_int(&b, "z", 44); + bson_append_start_array(&b, "arr"); + bson_append_start_object(&b, "0"); + bson_append_int(&b, "h", 1); + bson_append_finish_object(&b); + bson_append_start_object(&b, "1"); + bson_append_int(&b, "h", 2); + bson_append_finish_object(&b); + bson_append_finish_array(&b); + bson_finish(&b); + CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid)); + bson_destroy(&b); + + bson bsq1; + bson_init_as_query(&bsq1); + bson_append_int(&bsq1, "z", 44); + bson_append_int(&bsq1, "arr.h", 2); + bson_append_start_object(&bsq1, "$set"); + bson_append_int(&bsq1, "arr.$.h", 4); + bson_append_int(&bsq1, "arr.$.z", 5); + bson_append_int(&bsq1, "k", 55); + bson_append_finish_object(&bsq1); + bson_finish(&bsq1); + + TCXSTR *log = tcxstrnew(); + uint32_t count; + EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(q1); + ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log); + CU_ASSERT_EQUAL(count, 1); + + ejdbquerydel(q1); + tcxstrdel(log); + bson_destroy(&bsq1); + + //Now check It + bson_init_as_query(&bsq1); + bson_append_int(&bsq1, "k", 55); + bson_append_int(&bsq1, "arr.h", 4); + bson_append_int(&bsq1, "arr.z", 5); + bson_finish(&bsq1); + + log = tcxstrnew(); + q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(q1); + ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log); + CU_ASSERT_EQUAL(count, 1); + + ejdbquerydel(q1); + tcxstrdel(log); + bson_destroy(&bsq1); +} + int main() { setlocale(LC_ALL, "en_US.UTF-8"); CU_pSuite pSuite = NULL; @@ -4722,7 +4845,9 @@ int main() { (NULL == CU_add_test(pSuite, "testTicket88", testTicket88)) || (NULL == CU_add_test(pSuite, "testTicket89", testTicket89)) || (NULL == CU_add_test(pSuite, "testTicket81", testTicket81)) || - (NULL == CU_add_test(pSuite, "test$projection", test$projection)) || + (NULL == CU_add_test(pSuite, "test$projection", testDQprojection)) || + (NULL == CU_add_test(pSuite, "test$update", testDQupdate)) || + (NULL == CU_add_test(pSuite, "test$update2", testDQupdate2)) || (NULL == CU_add_test(pSuite, "testMetaInfo", testMetaInfo)) ) { CU_cleanup_registry(); -- 2.7.4