From 482a37481804e1d4a35c2f6c1bca96bfe28f9844 Mon Sep 17 00:00:00 2001 From: Christian Manning Date: Fri, 23 May 2014 19:06:47 +0100 Subject: [PATCH] Refactor & fix _qrybsrecurrmatch. Update $elemMatch test data. _qrybsrecurrmatch was not checking all elements of an array as it should have, which led to failures for all data and queries more complex than the rather simple test cases. It also now properly accounts for negation. --- tcejdb/ejdb.c | 87 ++++++++------- tcejdb/testejdb/t2.c | 297 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 252 insertions(+), 132 deletions(-) diff --git a/tcejdb/ejdb.c b/tcejdb/ejdb.c index 25f4cde..98af830 100644 --- a/tcejdb/ejdb.c +++ b/tcejdb/ejdb.c @@ -2069,57 +2069,68 @@ static bool _qrybsrecurrmatch(EJQF *qf, FFPCTX *ffpctx, int currpos) { assert(qf && ffpctx && ffpctx->stopnestedarr); bson_type bt = bson_find_fieldpath_value3(ffpctx); if (bt == BSON_ARRAY && ffpctx->stopos < ffpctx->fplen) { //a bit of complicated code in this case =) - //we just stepped in some array in middle of our fieldpath, so have to perform recusive nested iterations + //we just stepped in some array in middle of our fieldpath, so have to perform recursive nested iterations //$elemMatch active in this context while (ffpctx->fpath[ffpctx->stopos] == '.' && ffpctx->stopos < ffpctx->fplen) ffpctx->stopos++; ffpctx->fplen = ffpctx->fplen - ffpctx->stopos; assert(ffpctx->fplen > 0); ffpctx->fpath = ffpctx->fpath + ffpctx->stopos; currpos += ffpctx->stopos; //adjust cumulative field position + bson_iterator sit; BSON_ITERATOR_SUBITERATOR(ffpctx->input, &sit); - int c = 0; - while ((bt = bson_iterator_next(&sit)) != BSON_EOO) { - if (bt == BSON_OBJECT || bt == BSON_ARRAY) { - bson_iterator sit2; - BSON_ITERATOR_SUBITERATOR(&sit, &sit2); - ffpctx->input = &sit2; - if (_qrybsrecurrmatch(qf, ffpctx, currpos) != qf->negate) { - bool ret = true; - if (qf->elmatchgrp > 0 && qf->elmatchpos == currpos) { //$elemMatch matching group exists at right place - for (int i = TCLISTNUM(qf->q->qflist) - 1; i >= 0; --i) { - EJQF *eqf = TCLISTVALPTR(qf->q->qflist, i); - if (eqf == qf || (eqf->mflags & EJFEXCLUDED) || eqf->elmatchgrp != qf->elmatchgrp) { - continue; - } - eqf->mflags |= EJFEXCLUDED; - BSON_ITERATOR_SUBITERATOR(&sit, &sit2); - FFPCTX nffpctx = *ffpctx; - nffpctx.fplen = eqf->fpathsz - eqf->elmatchpos; - if (nffpctx.fplen <= 0) { //should never happen if query construction is correct - assert(false); - ret = false; - break; - } - nffpctx.fpath = eqf->fpath + eqf->elmatchpos; - nffpctx.input = &sit2; - nffpctx.stopos = 0; - if (!_qrybsrecurrmatch(eqf, &nffpctx, eqf->elmatchpos)) { - ret = false; - break; - } - } + for (int arr_idx = 0;(bt = bson_iterator_next(&sit)) != BSON_EOO; ++arr_idx) { + if (bt != BSON_OBJECT && bt != BSON_ARRAY) + continue; + + bson_iterator sit2; + BSON_ITERATOR_SUBITERATOR(&sit, &sit2); + + ffpctx->input = &sit2; + + // Match using context initialised above. + if (_qrybsrecurrmatch(qf, ffpctx, currpos) == qf->negate) { + continue; + } + + bool ret = true; + if (qf->elmatchgrp > 0 && qf->elmatchpos == currpos) { //$elemMatch matching group exists at right place + // Match all sub-queries on current field pos. Early exit (break) on failure. + for (int i = TCLISTNUM(qf->q->qflist) - 1; i >= 0; --i) { + EJQF *eqf = TCLISTVALPTR(qf->q->qflist, i); + if (eqf == qf || (eqf->mflags & EJFEXCLUDED) || eqf->elmatchgrp != qf->elmatchgrp) { + continue; + } + eqf->mflags |= EJFEXCLUDED; + BSON_ITERATOR_SUBITERATOR(&sit, &sit2); + FFPCTX nffpctx = *ffpctx; + nffpctx.fplen = eqf->fpathsz - eqf->elmatchpos; + if (nffpctx.fplen <= 0) { //should never happen if query construction is correct + assert(false); + ret = false; + break; } - if (ret) { - _qrysetarrayidx(ffpctx, qf, (currpos - 1), c); + nffpctx.fpath = eqf->fpath + eqf->elmatchpos; + nffpctx.input = &sit2; + nffpctx.stopos = 0; + + // Match sub-query at current field pos. + // Ignores outer negate (qf) on inner query (eqf). + if (_qrybsrecurrmatch(eqf, &nffpctx, eqf->elmatchpos) == qf->negate) { + // Skip all remaining sub-queries on this field. Go to next element, if any. + ret = false; + break; } - - return ret; } - ++c; + } + if (ret) { + _qrysetarrayidx(ffpctx, qf, (currpos - 1), arr_idx); + // Only return success at this point. + // An failure here may precede a later success so proceed to next element, if any. + return ret != qf->negate; } } - return false; + return qf->negate; } else { if (bt == BSON_EOO || bt == BSON_UNDEFINED || bt == BSON_NULL) { return qf->negate; //Field missing diff --git a/tcejdb/testejdb/t2.c b/tcejdb/testejdb/t2.c index baa0dc3..175f999 100644 --- a/tcejdb/testejdb/t2.c +++ b/tcejdb/testejdb/t2.c @@ -54,9 +54,12 @@ void testAddData() { bson_append_finish_object(&a1); //EOF address bson_append_start_array(&a1, "complexarr"); bson_append_start_object(&a1, "0"); - bson_append_string(&a1, "foo", "bar"); - bson_append_string(&a1, "foo2", "bar2"); - bson_append_string(&a1, "foo3", "bar3"); + bson_append_string(&a1, "key", "title"); + bson_append_string(&a1, "value", "some title"); + bson_append_finish_object(&a1); + bson_append_start_object(&a1, "1"); + bson_append_string(&a1, "key", "comment"); + bson_append_string(&a1, "value", "some comment"); bson_append_finish_object(&a1); bson_append_finish_array(&a1); //EOF complexarr CU_ASSERT_FALSE_FATAL(a1.err); @@ -78,10 +81,14 @@ void testAddData() { bson_append_finish_object(&a1); bson_append_start_array(&a1, "complexarr"); bson_append_start_object(&a1, "0"); - bson_append_string(&a1, "foo", "bar"); - bson_append_string(&a1, "foo2", "bar3"); + bson_append_string(&a1, "key", "title"); + bson_append_string(&a1, "value", "some title"); + bson_append_finish_object(&a1); + bson_append_start_object(&a1, "1"); + bson_append_string(&a1, "key", "title"); + bson_append_string(&a1, "value", "some other title"); bson_append_finish_object(&a1); - bson_append_int(&a1, "1", 333); + bson_append_int(&a1, "2", 333); bson_append_finish_array(&a1); //EOF complexarr bson_append_start_array(&a1, "labels"); bson_append_string(&a1, "0", "red"); @@ -3716,7 +3723,8 @@ void testFindInComplexArray() { CU_ASSERT_PTR_NOT_NULL_FATAL(coll); bson bsq1; bson_init_as_query(&bsq1); - bson_append_string(&bsq1, "complexarr.foo", "bar"); + bson_append_string(&bsq1, "complexarr.key", "title"); + bson_append_string(&bsq1, "complexarr.value", "some title"); bson_finish(&bsq1); CU_ASSERT_FALSE_FATAL(bsq1.err); @@ -3727,10 +3735,21 @@ void testFindInComplexArray() { TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log); CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); //fprintf(stderr, "%s", TCXSTRPTR(log)); - CU_ASSERT_EQUAL(count, 2); - for (int i = 0; i < TCLISTNUM(q1res); ++i) { - CU_ASSERT_FALSE(bson_compare_string("bar", TCLISTVALPTR(q1res, i), "complexarr.0.foo")); - } + CU_ASSERT_EQUAL_FATAL(count, 2); + + // 0 + CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value")); + + // 1 + CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, 1), "name")); + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 1), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 1), "complexarr.0.value")); bson_destroy(&bsq1); tclistdel(q1res); @@ -3739,7 +3758,7 @@ void testFindInComplexArray() { //Check matching positional element bson_init_as_query(&bsq1); - bson_append_string(&bsq1, "complexarr.0.foo", "bar"); + bson_append_string(&bsq1, "complexarr.0.key", "title"); bson_finish(&bsq1); q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(q1); @@ -3747,10 +3766,21 @@ void testFindInComplexArray() { q1res = ejdbqryexecute(coll, q1, &count, 0, log); CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); //fprintf(stderr, "\n%s", TCXSTRPTR(log)); - CU_ASSERT_EQUAL(count, 2); - for (int i = 0; i < TCLISTNUM(q1res); ++i) { - CU_ASSERT_FALSE(bson_compare_string("bar", TCLISTVALPTR(q1res, i), "complexarr.0.foo")); - } + CU_ASSERT_EQUAL_FATAL(count, 2); + + // 0 + CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value")); + + // 1 + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value")); + + CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, 1), "name")); + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 1), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 1), "complexarr.0.value")); bson_destroy(&bsq1); tclistdel(q1res); @@ -3759,7 +3789,7 @@ void testFindInComplexArray() { //Check simple el bson_init_as_query(&bsq1); - bson_append_int(&bsq1, "complexarr.1", 333); + bson_append_int(&bsq1, "complexarr.2", 333); bson_finish(&bsq1); q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(q1); @@ -3767,10 +3797,19 @@ void testFindInComplexArray() { q1res = ejdbqryexecute(coll, q1, &count, 0, log); CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); //fprintf(stderr, "\n%s", TCXSTRPTR(log)); - CU_ASSERT_EQUAL(count, 1); - for (int i = 0; i < TCLISTNUM(q1res); ++i) { - CU_ASSERT_FALSE(bson_compare_long(333, TCLISTVALPTR(q1res, i), "complexarr.1")); - } + CU_ASSERT_EQUAL_FATAL(count, 1); + + // 0 + CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value")); + + CU_ASSERT_FALSE(bson_compare_long(333, TCLISTVALPTR(q1res, 0), "complexarr.2")); + bson_destroy(&bsq1); tclistdel(q1res); tcxstrdel(log); @@ -3786,10 +3825,19 @@ void testFindInComplexArray() { q1res = ejdbqryexecute(coll, q1, &count, 0, log); CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); //fprintf(stderr, "\n%s", TCXSTRPTR(log)); - CU_ASSERT_EQUAL(count, 1); - for (int i = 0; i < TCLISTNUM(q1res); ++i) { - CU_ASSERT_FALSE(bson_compare_long(333, TCLISTVALPTR(q1res, i), "complexarr.1")); - } + CU_ASSERT_EQUAL_FATAL(count, 1); + + // 0 + CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value")); + + CU_ASSERT_FALSE(bson_compare_long(333, TCLISTVALPTR(q1res, 0), "complexarr.2")); + bson_destroy(&bsq1); tclistdel(q1res); tcxstrdel(log); @@ -3798,7 +3846,7 @@ void testFindInComplexArray() { //$exists bson_init_as_query(&bsq1); - bson_append_start_object(&bsq1, "complexarr.foo"); + bson_append_start_object(&bsq1, "complexarr.key"); bson_append_bool(&bsq1, "$exists", true); bson_append_finish_object(&bsq1); bson_finish(&bsq1); @@ -3816,7 +3864,7 @@ void testFindInComplexArray() { //$exists 2 bson_init_as_query(&bsq1); - bson_append_start_object(&bsq1, "complexarr.1"); + bson_append_start_object(&bsq1, "complexarr.2"); bson_append_bool(&bsq1, "$exists", true); bson_append_finish_object(&bsq1); bson_finish(&bsq1); @@ -3851,16 +3899,15 @@ void testFindInComplexArray() { } void test$elemMatch() { - //{complexarr : {$elemMatch : {foo : 'bar', foo2 : 'bar2', foo3 : 'bar3'}}} + // { complexarr: { $elemMatch: { key: 'title', value: 'some title' } } } EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(coll); bson bsq1; bson_init_as_query(&bsq1); bson_append_start_object(&bsq1, "complexarr"); bson_append_start_object(&bsq1, "$elemMatch"); - bson_append_string(&bsq1, "foo", "bar"); - bson_append_string(&bsq1, "foo2", "bar2"); - bson_append_string(&bsq1, "foo3", "bar3"); + bson_append_string(&bsq1, "key", "title"); + bson_append_string(&bsq1, "value", "some title"); bson_append_finish_object(&bsq1); bson_append_finish_object(&bsq1); bson_finish(&bsq1); @@ -3872,14 +3919,27 @@ void test$elemMatch() { TCXSTR *log = tcxstrnew(); TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log); CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); - CU_ASSERT_EQUAL(count, 1); - //fprintf(stderr, "%s", TCXSTRPTR(log)); - for (int i = 0; i < TCLISTNUM(q1res); ++i) { - CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name")); - CU_ASSERT_FALSE(bson_compare_string("bar", TCLISTVALPTR(q1res, i), "complexarr.0.foo")); - CU_ASSERT_FALSE(bson_compare_string("bar2", TCLISTVALPTR(q1res, i), "complexarr.0.foo2")); - CU_ASSERT_FALSE(bson_compare_string("bar3", TCLISTVALPTR(q1res, i), "complexarr.0.foo3")); - } + CU_ASSERT_EQUAL_FATAL(count, 2); +// fprintf(stderr, "%s", TCXSTRPTR(log)); + + // 0 + CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value")); + + // 1 + CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, 1), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 1), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 1), "complexarr.0.value")); + + CU_ASSERT_FALSE(bson_compare_string("comment", TCLISTVALPTR(q1res, 1), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some comment", TCLISTVALPTR(q1res, 1), "complexarr.1.value")); + bson_destroy(&bsq1); tclistdel(q1res); tcxstrdel(log); @@ -3888,8 +3948,8 @@ void test$elemMatch() { bson_init_as_query(&bsq1); bson_append_start_object(&bsq1, "complexarr"); bson_append_start_object(&bsq1, "$elemMatch"); - bson_append_string(&bsq1, "foo", "bar"); - bson_append_string(&bsq1, "foo2", "bar3"); + bson_append_string(&bsq1, "key", "title"); + bson_append_string(&bsq1, "value", "some other title"); bson_append_finish_object(&bsq1); bson_append_finish_object(&bsq1); bson_finish(&bsq1); @@ -3900,12 +3960,17 @@ void test$elemMatch() { q1res = ejdbqryexecute(coll, q1, &count, 0, log); CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); //fprintf(stderr, "%s", TCXSTRPTR(log)); - CU_ASSERT_EQUAL(count, 1); - for (int i = 0; i < TCLISTNUM(q1res); ++i) { - CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name")); - CU_ASSERT_FALSE(bson_compare_string("bar", TCLISTVALPTR(q1res, i), "complexarr.0.foo")); - CU_ASSERT_FALSE(bson_compare_string("bar3", TCLISTVALPTR(q1res, i), "complexarr.0.foo2")); - } + CU_ASSERT_EQUAL_FATAL(count, 1); + + // 0 + CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value")); + bson_destroy(&bsq1); tclistdel(q1res); tcxstrdel(log); @@ -3914,9 +3979,9 @@ void test$elemMatch() { bson_init_as_query(&bsq1); bson_append_start_object(&bsq1, "complexarr"); bson_append_start_object(&bsq1, "$elemMatch"); - bson_append_string(&bsq1, "foo", "bar"); - bson_append_start_object(&bsq1, "foo2"); - bson_append_string(&bsq1, "$not", "bar3"); + bson_append_string(&bsq1, "key", "title"); + bson_append_start_object(&bsq1, "value"); + bson_append_string(&bsq1, "$not", "some title"); bson_append_finish_object(&bsq1); bson_append_finish_object(&bsq1); bson_append_finish_object(&bsq1); @@ -3927,22 +3992,26 @@ void test$elemMatch() { log = tcxstrnew(); q1res = ejdbqryexecute(coll, q1, &count, 0, log); CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); - //fprintf(stderr, "%s", TCXSTRPTR(log)); - CU_ASSERT_EQUAL(count, 1); - for (int i = 0; i < TCLISTNUM(q1res); ++i) { - CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name")); - CU_ASSERT_FALSE(bson_compare_string("bar", TCLISTVALPTR(q1res, i), "complexarr.0.foo")); - CU_ASSERT_FALSE(bson_compare_string("bar2", TCLISTVALPTR(q1res, i), "complexarr.0.foo2")); - CU_ASSERT_FALSE(bson_compare_string("bar3", TCLISTVALPTR(q1res, i), "complexarr.0.foo3")); - } +// fprintf(stderr, "%s", TCXSTRPTR(log)); + CU_ASSERT_EQUAL_FATAL(count, 1); + + // 0 + CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value")); + bson_destroy(&bsq1); tclistdel(q1res); tcxstrdel(log); ejdbquerydel(q1); bson_init_as_query(&bsq1); - bson_append_string(&bsq1, "complexarr.foo", "bar"); - bson_append_string(&bsq1, "complexarr.foo2", "bar3"); + bson_append_string(&bsq1, "complexarr.key", "title"); + bson_append_string(&bsq1, "complexarr.value", "some other title"); bson_finish(&bsq1); CU_ASSERT_FALSE_FATAL(bsq1.err); q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL); @@ -3951,12 +4020,16 @@ void test$elemMatch() { q1res = ejdbqryexecute(coll, q1, &count, 0, log); CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); //fprintf(stderr, "%s", TCXSTRPTR(log)); - CU_ASSERT_EQUAL(count, 1); - for (int i = 0; i < TCLISTNUM(q1res); ++i) { - CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name")); - CU_ASSERT_FALSE(bson_compare_string("bar", TCLISTVALPTR(q1res, i), "complexarr.0.foo")); - CU_ASSERT_FALSE(bson_compare_string("bar3", TCLISTVALPTR(q1res, i), "complexarr.0.foo2")); - } + CU_ASSERT_EQUAL_FATAL(count, 1); + + // 0 + CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value")); bson_destroy(&bsq1); tclistdel(q1res); @@ -3965,7 +4038,7 @@ void test$elemMatch() { } void test$not$elemMatch() { - //{complexarr : {$elemMatch : {foo : 'bar', foo2 : 'bar2', foo3 : 'bar3'}}} + // { complexarr: { $not: { $elemMatch: { key: 'title', value: 'some title' } } } } EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(coll); bson bsq1; @@ -3973,9 +4046,8 @@ void test$not$elemMatch() { bson_append_start_object(&bsq1, "complexarr"); bson_append_start_object(&bsq1, "$not"); bson_append_start_object(&bsq1, "$elemMatch"); - bson_append_string(&bsq1, "foo", "bar"); - bson_append_string(&bsq1, "foo2", "bar2"); - bson_append_string(&bsq1, "foo3", "bar3"); + bson_append_string(&bsq1, "key", "title"); + bson_append_string(&bsq1, "value", "some title"); bson_append_finish_object(&bsq1);//$elemMatch bson_append_finish_object(&bsq1);//$not //include $exists to exclude documents without complexarr @@ -3990,14 +4062,43 @@ void test$not$elemMatch() { TCXSTR *log = tcxstrnew(); TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log); CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); + //fprintf(stderr, "%s", TCXSTRPTR(log)); + CU_ASSERT_EQUAL_FATAL(count, 0); - CU_ASSERT_EQUAL(count, 1); + bson_destroy(&bsq1); + tclistdel(q1res); + tcxstrdel(log); + ejdbquerydel(q1); + + bson_init_as_query(&bsq1); + bson_append_start_object(&bsq1, "complexarr"); + bson_append_start_object(&bsq1, "$not"); + bson_append_start_object(&bsq1, "$elemMatch"); + bson_append_string(&bsq1, "key", "title"); + bson_append_string(&bsq1, "value", "some other title"); + bson_append_finish_object(&bsq1);//$elemMatch + bson_append_finish_object(&bsq1);//$not + bson_append_bool(&bsq1, "$exists", true); + bson_append_finish_object(&bsq1); + 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_FATAL(q1res); //fprintf(stderr, "%s", TCXSTRPTR(log)); - for (int i = 0; i < TCLISTNUM(q1res); ++i) { - CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name")); - CU_ASSERT_FALSE(bson_compare_string("bar", TCLISTVALPTR(q1res, i), "complexarr.0.foo")); - CU_ASSERT_FALSE(bson_compare_string("bar3", TCLISTVALPTR(q1res, i), "complexarr.0.foo2")); - } + CU_ASSERT_EQUAL_FATAL(count, 1); + + // 0 + CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, 0), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value")); + + CU_ASSERT_FALSE(bson_compare_string("comment", TCLISTVALPTR(q1res, 0), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some comment", TCLISTVALPTR(q1res, 0), "complexarr.1.value")); + bson_destroy(&bsq1); tclistdel(q1res); tcxstrdel(log); @@ -4007,8 +4108,7 @@ void test$not$elemMatch() { bson_append_start_object(&bsq1, "complexarr"); bson_append_start_object(&bsq1, "$not"); bson_append_start_object(&bsq1, "$elemMatch"); - bson_append_string(&bsq1, "foo", "bar"); - bson_append_string(&bsq1, "foo2", "bar3"); + bson_append_string(&bsq1, "key", "comment"); bson_append_finish_object(&bsq1);//$elemMatch bson_append_finish_object(&bsq1);//$not bson_append_bool(&bsq1, "$exists", true); @@ -4021,13 +4121,17 @@ void test$not$elemMatch() { q1res = ejdbqryexecute(coll, q1, &count, 0, log); CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); //fprintf(stderr, "%s", TCXSTRPTR(log)); - CU_ASSERT_EQUAL(count, 1); - for (int i = 0; i < TCLISTNUM(q1res); ++i) { - CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name")); - CU_ASSERT_FALSE(bson_compare_string("bar", TCLISTVALPTR(q1res, i), "complexarr.0.foo")); - CU_ASSERT_FALSE(bson_compare_string("bar2", TCLISTVALPTR(q1res, i), "complexarr.0.foo2")); - CU_ASSERT_FALSE(bson_compare_string("bar3", TCLISTVALPTR(q1res, i), "complexarr.0.foo3")); - } + CU_ASSERT_EQUAL_FATAL(count, 1); + + // 0 + CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value")); + bson_destroy(&bsq1); tclistdel(q1res); tcxstrdel(log); @@ -4038,9 +4142,9 @@ void test$not$elemMatch() { bson_append_start_object(&bsq1, "complexarr"); bson_append_start_object(&bsq1, "$not"); bson_append_start_object(&bsq1, "$elemMatch"); - bson_append_string(&bsq1, "foo", "bar"); - bson_append_start_object(&bsq1, "foo2"); - bson_append_string(&bsq1, "$not", "bar3"); + bson_append_string(&bsq1, "key", "title"); + bson_append_start_object(&bsq1, "value"); + bson_append_string(&bsq1, "$not", "some title"); bson_append_finish_object(&bsq1); bson_append_finish_object(&bsq1); bson_append_finish_object(&bsq1); @@ -4053,12 +4157,17 @@ void test$not$elemMatch() { q1res = ejdbqryexecute(coll, q1, &count, 0, log); CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); //fprintf(stderr, "%s", TCXSTRPTR(log)); - CU_ASSERT_EQUAL(count, 1); - for (int i = 0; i < TCLISTNUM(q1res); ++i) { - CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name")); - CU_ASSERT_FALSE(bson_compare_string("bar", TCLISTVALPTR(q1res, i), "complexarr.0.foo")); - CU_ASSERT_FALSE(bson_compare_string("bar3", TCLISTVALPTR(q1res, i), "complexarr.0.foo2")); - } + CU_ASSERT_EQUAL_FATAL(count, 1); + + // 0 + CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, 0), "name")); + + CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key")); + CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value")); + + CU_ASSERT_FALSE(bson_compare_string("comment", TCLISTVALPTR(q1res, 0), "complexarr.1.key")); + CU_ASSERT_FALSE(bson_compare_string("some comment", TCLISTVALPTR(q1res, 0), "complexarr.1.value")); + bson_destroy(&bsq1); tclistdel(q1res); tcxstrdel(log); -- 2.7.4