From 6f313948ebe44d00f022cc96cdfcadcb768c5d06 Mon Sep 17 00:00:00 2001 From: adam Date: Wed, 28 Nov 2012 16:47:05 +0700 Subject: [PATCH] v1.0.18 --- Changelog | 4 +++ package.json | 2 +- tcejdb/ejdb.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-- tcejdb/tctdb.h | 1 + tcejdb/testejdb/t2.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 159 insertions(+), 5 deletions(-) diff --git a/Changelog b/Changelog index 12e7a54..77a41e4 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,7 @@ +2012-11-28 Anton Adamansky. + * The $begin query operation now works with tokens. Eg: {'name' : {'$begin' : ['token1', 'token2', ...]}} + - Release 1.0.18 + 2012-11-27 Anton Adamansky. * Added $dropall query operation in order to remove matched records * Better boolean type support, boolean values treated as numbers. diff --git a/package.json b/package.json index 698d304..8e227b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "ejdb", - "version" : "1.0.17", + "version" : "1.0.18", "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 619a434..d949fcf 100644 --- a/tcejdb/ejdb.c +++ b/tcejdb/ejdb.c @@ -1076,7 +1076,7 @@ static bool _qrybsvalmatch(const EJQF *qf, bson_iterator *it, bool expandarrays) for (int i = 0; i < TCLISTNUM(tokens); ++i) { const char *token = TCLISTVALPTR(tokens, i); int tokensz = TCLISTVALSIZ(tokens, i); - if (TCLISTVALSIZ(tokens, i) == cbufstrlen && !strncmp(token, cbuf, tokensz)) { + if (tokensz == cbufstrlen && !strncmp(token, cbuf, tokensz)) { rv = true; break; } @@ -1089,7 +1089,42 @@ static bool _qrybsvalmatch(const EJQF *qf, bson_iterator *it, bool expandarrays) for (int i = 0; i < TCLISTNUM(tokens); ++i) { const char *token = TCLISTVALPTR(tokens, i); int tokensz = TCLISTVALSIZ(tokens, i); - if (TCLISTVALSIZ(tokens, i) == (fvalsz - 1) && !strncmp(token, fval, tokensz)) { + if (tokensz == (fvalsz - 1) && !strncmp(token, fval, tokensz)) { + rv = true; + break; + } + } + } + break; + } + case TDBQCSTRORBW: + { + TCLIST *tokens = qf->exprlist; + assert(tokens); + _FETCHSTRFVAL(); + if ((qf->flags & EJCONDICASE) && (bt == BSON_STRING)) { + cbufstrlen = tcicaseformat(fval, fvalsz - 1, sbuf, JBSTRINOPBUFFERSZ, &cbuf); + if (cbufstrlen < 0) { + _ejdbsetecode(qf->jb, cbufstrlen, __FILE__, __LINE__, __func__); + rv = false; + } else { + for (int i = 0; i < TCLISTNUM(tokens); ++i) { + const char *token = TCLISTVALPTR(tokens, i); + int tokensz = TCLISTVALSIZ(tokens, i); + if (tokensz <= cbufstrlen && !strncmp(token, cbuf, tokensz)) { + rv = true; + break; + } + } + } + if (cbuf && cbuf != sbuf) { + TCFREE(cbuf); + } + } else { + for (int i = 0; i < TCLISTNUM(tokens); ++i) { + const char *token = TCLISTVALPTR(tokens, i); + int tokensz = TCLISTVALSIZ(tokens, i); + if (tokensz <= (fvalsz - 1) && !strncmp(token, fval, tokensz)) { rv = true; break; } @@ -2001,6 +2036,44 @@ static TCLIST* _qryexecute(EJCOLL *jcoll, const EJQ *q, uint32_t *outcount, int tcbdbcurnext(cur); } tcbdbcurdel(cur); + } else if (mqf->tcop == TDBQCSTRORBW) { /* string begins with one token in */ + assert(mqf->ftype == BSON_ARRAY); + assert(midx->type == TDBITLEXICAL); + BDBCUR *cur = tcbdbcurnew(midx->db); + TCLIST *tokens = mqf->exprlist; + assert(tokens); + tclistsort(tokens); + for (int i = 1; i < TCLISTNUM(tokens); i++) { + if (!strcmp(TCLISTVALPTR(tokens, i), TCLISTVALPTR(tokens, i - 1))) { + TCFREE(tclistremove2(tokens, i)); + i--; + } + } + if (mqf->order < 0 && (mqf->flags & EJFORDERUSED)) { + tclistinvert(tokens); + } + int tnum = TCLISTNUM(tokens); + for (int i = 0; (all || count < max) && i < tnum; i++) { + const char *token; + int tsiz; + TCLISTVAL(token, tokens, i, tsiz); + if (tsiz < 1) continue; + tcbdbcurjump(cur, token, tsiz + trim); + while ((all || count < max) && (kbuf = tcbdbcurkey3(cur, &kbufsz)) != NULL) { + if (trim) kbufsz -= 3; + if (kbufsz >= tsiz && !memcmp(kbuf, token, tsiz)) { + vbuf = tcbdbcurval3(cur, &vbufsz); + if (_qryallcondsmatch(onlycount, anum, jcoll, qfs, qfsz, vbuf, vbufsz, &bsbuf, &bsbufsz) && + (ejq->orqobjsnum == 0 || _qryormatch(jcoll, ejq, vbuf, vbufsz, bsbuf, bsbufsz))) { + JBQREGREC(bsbuf, bsbufsz); + } + } else { + break; + } + tcbdbcurnext(cur); + } + } + tcbdbcurdel(cur); } else if (mqf->tcop == TDBQCSTROREQ) { /* string is equal to at least one token in */ assert(mqf->ftype == BSON_ARRAY); assert(midx->type == TDBITLEXICAL); @@ -2385,6 +2458,7 @@ static TDBIDX* _qryfindidx(EJCOLL *jcoll, EJQF *qf, bson *idxmeta) { case TDBQCSTREQ: case TDBQCSTRBW: case TDBQCSTROREQ: + case TDBQCSTRORBW: p = (qf->flags & EJCONDICASE) ? 'i' : 's'; //lexical string index break; case TDBQCNUMEQ: @@ -2980,6 +3054,8 @@ static int _parse_qobj_impl(EJDB *jb, EJQ *q, bson_iterator *it, TCMAP *qmap, TC qf.tcop = TDBQCSTRAND; } else if (!strcmp("$stror", fkey)) { //$stror qf.tcop = TDBQCSTROR; + } else if (qf.flags & EJCONDSTARTWITH) { //$begin with some token + qf.tcop = TDBQCSTRORBW; } else { ret = JBEQINVALIDQCONTROL; TCFREE(qf.expr); diff --git a/tcejdb/tctdb.h b/tcejdb/tctdb.h index 47b1c89..9a437d8 100644 --- a/tcejdb/tctdb.h +++ b/tcejdb/tctdb.h @@ -143,6 +143,7 @@ enum { /* enumeration for query conditions */ TDBQCEXIST, /* string|number exists */ TDBQTRUE, /* any field always matched */ TDBQCSTRNUMOR, /* string includes at least one number token in */ + TDBQCSTRORBW, /* string begins with at least one token in */ TDBQCNEGATE = 1 << 24, /* negation flag */ TDBQCNOIDX = 1 << 25 /* no index flag */ }; diff --git a/tcejdb/testejdb/t2.c b/tcejdb/testejdb/t2.c index 75c6ecf..42a14d0 100644 --- a/tcejdb/testejdb/t2.c +++ b/tcejdb/testejdb/t2.c @@ -3014,7 +3014,6 @@ void testQueryBool() { void testDropAll() { EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(coll); - CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXSTR)); bson bsq1; @@ -3060,6 +3059,79 @@ void testDropAll() { ejdbquerydel(q1); } +void testTokens$begin() { + EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(coll); + CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXSTR)); + + //q: {'name' : {'$begin' : ['Ада', 'John T']}} + bson bsq1; + bson_init_as_query(&bsq1); + bson_append_start_object(&bsq1, "name"); + bson_append_start_array(&bsq1, "$begin"); + bson_append_string(&bsq1, "0", "Ада"); + bson_append_string(&bsq1, "1", "John T"); + bson_append_string(&bsq1, "2", "QWE J"); + bson_append_finish_array(&bsq1); + bson_append_finish_object(&bsq1); + 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: 'sname'")); + CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 22")); + CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2")); + for (int i = 0; i < TCLISTNUM(q1res); ++i) { + CU_ASSERT_TRUE(!bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name") || + !bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name")); + } + + bson_destroy(&bsq1); + tclistdel(q1res); + tcxstrdel(log); + ejdbquerydel(q1); + + //q: {'name' : {'$begin' : ['Ада', 'John T']}} + bson_init_as_query(&bsq1); + bson_append_start_object(&bsq1, "name"); + bson_append_start_array(&bsq1, "$begin"); + bson_append_string(&bsq1, "0", "Ада"); + bson_append_string(&bsq1, "1", "John T"); + bson_append_string(&bsq1, "2", "QWE J"); + bson_append_finish_array(&bsq1); + bson_append_finish_object(&bsq1); + bson_finish(&bsq1); + CU_ASSERT_FALSE_FATAL(bsq1.err); + + + CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXDROPALL)); + + 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: 'NONE'")); + CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN")); + CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2")); + for (int i = 0; i < TCLISTNUM(q1res); ++i) { + CU_ASSERT_TRUE(!bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name") || + !bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name")); + } + + bson_destroy(&bsq1); + tclistdel(q1res); + tcxstrdel(log); + ejdbquerydel(q1); +} + int main() { setlocale(LC_ALL, "en_US.UTF-8"); @@ -3114,7 +3186,8 @@ int main() { (NULL == CU_add_test(pSuite, "testUpdate1", testUpdate1)) || (NULL == CU_add_test(pSuite, "testUpdate2", testUpdate2)) || (NULL == CU_add_test(pSuite, "testQueryBool", testQueryBool)) || - (NULL == CU_add_test(pSuite, "testDropAll", testDropAll)) + (NULL == CU_add_test(pSuite, "testDropAll", testDropAll)) || + (NULL == CU_add_test(pSuite, "testTokens$begin", testTokens$begin)) ) { CU_cleanup_registry(); return CU_get_error(); -- 2.7.4