summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog6
-rw-r--r--package.json2
-rw-r--r--tcejdb/ejdb.c47
-rw-r--r--tcejdb/ejdb_private.h6
-rw-r--r--tcejdb/testejdb/t2.c101
5 files changed, 146 insertions, 16 deletions
diff --git a/Changelog b/Changelog
index 0f3940b..12e7a54 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,9 @@
+2012-11-27 Anton Adamansky. <adamansky@gmail.com>
+ * Added $dropall query operation in order to remove matched records
+ * Better boolean type support, boolean values treated as numbers.
+ * Various bugfixes
+ - Release 1.0.17
+
2012-11-26 Anton Adamansky. <adamansky@gmail.com>
* NodeJS: Added merge json object option ($merge) in save() method
* Added ejdbsavebson2() with merge option.
diff --git a/package.json b/package.json
index a1393f9..698d304 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name" : "ejdb",
- "version" : "1.0.16",
+ "version" : "1.0.17",
"main" : "node/ejdb.js",
"description" : "EJDB - Embedded JSON Database engine",
"homepage" : "http://ejdb.org",
diff --git a/tcejdb/ejdb.c b/tcejdb/ejdb.c
index 05a285f..619a434 100644
--- a/tcejdb/ejdb.c
+++ b/tcejdb/ejdb.c
@@ -391,10 +391,8 @@ EJDB_EXPORT bool ejdbrmbson(EJCOLL *jcoll, bson_oid_t *oid) {
goto finish;
}
olddata = tcmapget3(rmap, JDBCOLBSON, JDBCOLBSONL, &olddatasz);
- if (!_updatebsonidx(jcoll, oid, NULL, olddata, olddatasz, NULL)) {
- rv = false;
- }
- if (!tctdbout(jcoll->tdb, oid, sizeof (*oid))) {
+ if (!_updatebsonidx(jcoll, oid, NULL, olddata, olddatasz, NULL) ||
+ !tctdbout(jcoll->tdb, oid, sizeof (*oid))) {
rv = false;
}
finish:
@@ -1570,7 +1568,7 @@ static void _pushstripbson(TCLIST *rs, TCMAP *ifields, void *bsbuf, int bsbufsz)
TCFREE(bsbuf);
}
-static bool _qryupdate(EJCOLL *jcoll, const EJQ *ejq, void *bsbuf, int bsbufsz, TCLIST *didxctx) {
+static bool _qryupdate(EJCOLL *jcoll, const EJQ *ejq, void *bsbuf, int bsbufsz, TCLIST *didxctx, TCXSTR *log) {
assert(ejq->flags & EJQUPDATING);
assert(didxctx);
@@ -1586,16 +1584,45 @@ static bool _qryupdate(EJCOLL *jcoll, const EJQ *ejq, void *bsbuf, int bsbufsz,
TCMAP *qobjmap = ejq->qobjmap;
TCMAP *rowm = NULL;
+ if (ejq->flags & EJQDROPALL) { //Record will be dropped
+ bt = bson_find_from_buffer(&it, bsbuf, JDBIDKEYNAME);
+ if (bt != BSON_OID) {
+ _ejdbsetecode(jcoll->jb, JBEQUPDFAILED, __FILE__, __LINE__, __func__);
+ return false;
+ }
+ oid = bson_iterator_oid(&it);
+ assert(oid);
+ if (log) {
+ char xoid[25];
+ bson_oid_to_string(oid, xoid);
+ tcxstrprintf(log, "$DROPALL ON: %s\n", xoid);
+ }
+ const void *olddata;
+ int olddatasz = 0;
+ TCMAP *rmap = tctdbget(jcoll->tdb, oid, sizeof (*oid));
+ if (rmap) {
+ olddata = tcmapget3(rmap, JDBCOLBSON, JDBCOLBSONL, &olddatasz);
+ if (!_updatebsonidx(jcoll, oid, NULL, olddata, olddatasz, didxctx) ||
+ !tctdbout(jcoll->tdb, oid, sizeof (*oid))) {
+ rv = false;
+ }
+ tcmapdel(rmap);
+ }
+ return rv;
+ }
+
+ //Apply update operation
bson src;
bson_create_from_buffer2(&src, bsbuf, bsbufsz);
- bson bsout; //Resulting updated bson
+ bson bsout;
bsout.data = NULL;
bsout.dataSize = 0;
const EJQF *setqf = NULL;
const EJQF *incqf = NULL;
+ //$set, $inc operations
tcmapiterinit(qobjmap);
while ((kbuf = tcmapiternext(qobjmap, &kbufsz)) != NULL) {
const EJQF *qf = tcmapiterval(kbuf, &qfsz);
@@ -1680,8 +1707,6 @@ static bool _qryupdate(EJCOLL *jcoll, const EJQ *ejq, void *bsbuf, int bsbufsz,
oid = bson_iterator_oid(&it);
rowm = tcmapnew2(TCMAPTINYBNUM);
tcmapput(rowm, JDBCOLBSON, JDBCOLBSONL, bson_data(&bsout), bson_size(&bsout));
- //fprintf(stderr, "\nAFTER\n");
- //bson_print_raw(stderr, bson_data(&bsout), 0);
rv = tctdbput(jcoll->tdb, oid, sizeof (*oid), rowm);
if (rv) {
rv = _updatebsonidx(jcoll, oid, &bsout, bsbuf, bsbufsz, didxctx);
@@ -1816,7 +1841,7 @@ static TCLIST* _qryexecute(EJCOLL *jcoll, const EJQ *q, uint32_t *outcount, int
#define JBQREGREC(_bsbuf, _bsbufsz) \
++count; \
if (ejq->flags & EJQUPDATING) { \
- _qryupdate(jcoll, ejq, (_bsbuf), (_bsbufsz), didxctx); \
+ _qryupdate(jcoll, ejq, (_bsbuf), (_bsbufsz), didxctx, log); \
} \
if (!onlycount && (all || count > skip)) { \
if (ifields) {\
@@ -3127,12 +3152,12 @@ static int _parse_qobj_impl(EJDB *jb, EJQ *q, bson_iterator *it, TCMAP *qmap, TC
bool bv = bson_iterator_bool_raw(it);
if (isckey) {
if (!strcmp("$dropall", fkey) && bv) {
- qf.flags |= EJCONDROPALL;
qf.flags |= EJFEXCLUDED;
qf.fpath = tcstrjoin(pathStack, '.');
qf.fpathsz = strlen(qf.fpath);
qf.tcop = TDBQTRUE;
qf.q->flags |= EJQUPDATING;
+ qf.q->flags |= EJQDROPALL;
qf.expr = tcstrdup(""); //Empty string as expr
qf.exprsz = 0;
tcmapputkeep(qmap, qf.fpath, qf.fpathsz, &qf, sizeof (qf));
@@ -3156,7 +3181,7 @@ static int _parse_qobj_impl(EJDB *jb, EJQ *q, bson_iterator *it, TCMAP *qmap, TC
qf.fpathsz = strlen(qf.fpath);
qf.exprlongval = (bv ? 1 : 0);
qf.exprdblval = qf.exprlongval;
- qf.expr = (bv ? "1" : "0");
+ qf.expr = strdup(bv ? "1" : "0");
qf.exprsz = 1;
tcmapputkeep(qmap, qf.fpath, qf.fpathsz, &qf, sizeof (qf));
break;
diff --git a/tcejdb/ejdb_private.h b/tcejdb/ejdb_private.h
index b710b06..b607c53 100644
--- a/tcejdb/ejdb_private.h
+++ b/tcejdb/ejdb_private.h
@@ -55,14 +55,14 @@ enum { /**> Query field flags */
EJCONDICASE = 1 << 9, /**> Ignore case in matching */
EJCONDSET = 1 << 10, /**> Set field update operation */
- EJCONDINC = 1 << 11, /**> Inc field update operation */
- EJCONDROPALL = 1 << 12 /**> Drop bson object if matched */
+ EJCONDINC = 1 << 11 /**> Inc field update operation */
};
enum { /**> Query flags */
EJQINTERNAL = 1, /**> Internal query object used in _ejdbqryexecute */
- EJQUPDATING = 1 << 1 /**> Query in updating mode */
+ EJQUPDATING = 1 << 1, /**> Query in updating mode */
+ EJQDROPALL = 1 << 2 /**> Drop bson object if matched */
};
struct EJQF { /**> Matching field and status */
diff --git a/tcejdb/testejdb/t2.c b/tcejdb/testejdb/t2.c
index d1f1d4c..75c6ecf 100644
--- a/tcejdb/testejdb/t2.c
+++ b/tcejdb/testejdb/t2.c
@@ -2963,6 +2963,103 @@ void testUpdate2() { //https://github.com/Softmotions/ejdb/issues/9
}
+void testQueryBool() {
+ EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
+
+ bson bsq1;
+ bson_init_as_query(&bsq1);
+ bson_append_bool(&bsq1, "visited", true);
+ bson_finish(&bsq1);
+ CU_ASSERT_FALSE_FATAL(bsq1.err);
+
+
+ EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
+ uint32_t count = 0;
+ TCXSTR *log = tcxstrnew();
+ TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
+ //fprintf(stderr, "%s", TCXSTRPTR(log));
+ CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
+ CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
+ CU_ASSERT_EQUAL(count, 1);
+
+ bson_destroy(&bsq1);
+ tclistdel(q1res);
+ tcxstrdel(log);
+ ejdbquerydel(q1);
+
+ CU_ASSERT_TRUE(ejdbsetindex(coll, "visited", JBIDXNUM));
+
+ bson_init_as_query(&bsq1);
+ bson_append_bool(&bsq1, "visited", true);
+ bson_finish(&bsq1);
+ CU_ASSERT_FALSE_FATAL(bsq1.err);
+
+ q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
+ log = tcxstrnew();
+ q1res = ejdbqryexecute(coll, q1, &count, 0, log);
+ //fprintf(stderr, "%s", TCXSTRPTR(log));
+ CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'nvisited'"));
+ CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
+ CU_ASSERT_EQUAL(count, 1);
+
+ bson_destroy(&bsq1);
+ tclistdel(q1res);
+ tcxstrdel(log);
+ ejdbquerydel(q1);
+}
+
+void testDropAll() {
+ EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
+
+ CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXSTR));
+
+ bson bsq1;
+ bson_init_as_query(&bsq1);
+ bson_append_string(&bsq1, "name", "HeLlo WorlD");
+ bson_append_bool(&bsq1, "$dropall", true);
+ bson_finish(&bsq1);
+ CU_ASSERT_FALSE_FATAL(bsq1.err);
+
+
+ EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
+ uint32_t count = 0;
+ TCXSTR *log = tcxstrnew();
+ TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
+ //fprintf(stderr, "%s", TCXSTRPTR(log));
+ CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "$DROPALL ON:"));
+ CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'sname'"));
+ CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
+
+ bson_destroy(&bsq1);
+ tclistdel(q1res);
+ tcxstrdel(log);
+ ejdbquerydel(q1);
+
+ //Select again
+ bson_init_as_query(&bsq1);
+ bson_append_string(&bsq1, "name", "HeLlo WorlD");
+ bson_finish(&bsq1);
+ CU_ASSERT_FALSE_FATAL(bsq1.err);
+
+ q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
+ log = tcxstrnew();
+ q1res = ejdbqryexecute(coll, q1, &count, 0, log);
+ CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'sname'"));
+ CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 0"));
+ //fprintf(stderr, "\n\n%s", TCXSTRPTR(log));
+
+ bson_destroy(&bsq1);
+ tclistdel(q1res);
+ tcxstrdel(log);
+ ejdbquerydel(q1);
+}
+
int main() {
setlocale(LC_ALL, "en_US.UTF-8");
@@ -3015,7 +3112,9 @@ int main() {
(NULL == CU_add_test(pSuite, "testTicket7", testTicket7)) ||
(NULL == CU_add_test(pSuite, "testTicket8", testTicket8)) ||
(NULL == CU_add_test(pSuite, "testUpdate1", testUpdate1)) ||
- (NULL == CU_add_test(pSuite, "testUpdate2", testUpdate2))
+ (NULL == CU_add_test(pSuite, "testUpdate2", testUpdate2)) ||
+ (NULL == CU_add_test(pSuite, "testQueryBool", testQueryBool)) ||
+ (NULL == CU_add_test(pSuite, "testDropAll", testDropAll))
) {
CU_cleanup_registry();
return CU_get_error();