diff options
author | Anton Adamansky <adamansky@gmail.com> | 2015-03-18 00:17:33 +0600 |
---|---|---|
committer | Anton Adamansky <adamansky@gmail.com> | 2015-03-18 00:17:33 +0600 |
commit | f6b62658ceb44dc514bfb2ef2f063ff8da5d2bf1 (patch) | |
tree | 9c7c948a9d10f88f8c2d297b55721a626b916399 | |
parent | cf5b27bd7a84a8174dae93c8f5d1fd028305d20b (diff) | |
parent | c4559322ce212f63024cb92128022bd21dbb583f (diff) | |
download | ejdb-f6b62658ceb44dc514bfb2ef2f063ff8da5d2bf1.tar.gz ejdb-f6b62658ceb44dc514bfb2ef2f063ff8da5d2bf1.tar.bz2 ejdb-f6b62658ceb44dc514bfb2ef2f063ff8da5d2bf1.zip |
Merge remote-tracking branch 'origin/issue93'
Conflicts:
src/ejdb/tests/ejdbtest2.c
-rw-r--r-- | src/ejdb/ejdb.c | 73 | ||||
-rw-r--r-- | src/ejdb/ejdb.h | 15 | ||||
-rw-r--r-- | src/ejdb/tests/ejdbtest2.c | 41 |
3 files changed, 129 insertions, 0 deletions
diff --git a/src/ejdb/ejdb.c b/src/ejdb/ejdb.c index a1045e6..abdbaa6 100644 --- a/src/ejdb/ejdb.c +++ b/src/ejdb/ejdb.c @@ -592,6 +592,79 @@ EJQRESULT ejdbqryexecute(EJCOLL *coll, const EJQ *q, uint32_t *count, int qflags return res; } +bson* ejdbqrydistinct(EJCOLL *coll, const char *fpath, bson *qobj, bson *orqobjs, int orqobjsnum, uint32_t *count, TCXSTR *log) { + assert(coll); + uint32_t icount = 0; + + bson *rqobj = qobj; + bson *hints = bson_create(); + bson_init_as_query(hints); + bson_append_start_object(hints, "$fields"); + bson_append_int(hints, fpath, 1); + bson_append_finish_object(hints); + bson_append_start_object(hints, "$orderby"); + bson_append_int(hints, fpath, 1); + bson_append_finish_object(hints); + bson_finish(hints); + + EJQ *q = NULL; + bson *rres = NULL; + *count = 0; + + if (!rqobj) { + rqobj = bson_create(); + bson_init(rqobj); + bson_finish(rqobj); + } + q = ejdbcreatequery(coll->jb, rqobj, orqobjs, orqobjsnum, hints); + if (q == NULL) { + goto fail; + } + if (q->flags & EJQUPDATING) { + _ejdbsetecode(coll->jb, JBEQERROR, __FILE__, __LINE__, __func__); + goto fail; + } + TCLIST *res = ejdbqryexecute(coll, q, &icount, 0, log); + rres = bson_create(); + bson_init(rres); + + bson_iterator bsi[2]; + bson_iterator *prev = NULL, *cur; + int biind = 0; + char biindstr[TCNUMBUFSIZ]; + memset(biindstr, '\0', 32); + int fplen = strlen(fpath); + for(int i = 0; i < TCLISTNUM(res); ++i) { + cur = bsi + (biind & 1); + BSON_ITERATOR_FROM_BUFFER(cur, TCLISTVALPTR(res, i)); + bson_type bt = bson_find_fieldpath_value2(fpath, fplen, cur); + if (bt == BSON_EOO) { + continue; + } + + if (prev == NULL || bson_compare_it_current(prev, cur)) { + bson_numstrn(biindstr, TCNUMBUFSIZ, biind); + bson_append_field_from_iterator2(biindstr, cur, rres); + prev = cur; + biind++; + } + } + bson_finish(rres); + tclistdel(res); + + *count = biind; + +fail: + if (q) { + ejdbquerydel(q); + } + if (rqobj != qobj) { + bson_destroy(rqobj); + } + bson_destroy(hints); + return rres; +} + int ejdbqresultnum(EJQRESULT qr) { return qr ? tclistnum(qr) : 0; } diff --git a/src/ejdb/ejdb.h b/src/ejdb/ejdb.h index d00c212..bb07773 100644 --- a/src/ejdb/ejdb.h +++ b/src/ejdb/ejdb.h @@ -496,6 +496,21 @@ EJDB_EXPORT void ejdbqresultdispose(EJQRESULT qr); EJDB_EXPORT uint32_t ejdbupdate(EJCOLL *jcoll, bson *qobj, bson *orqobjs, int orqobjsnum, bson *hints, TCXSTR *log); /** + * Provides 'distinct' operation over query (http://docs.mongodb.org/manual/reference/method/db.collection.distinct/). + * + * @param jcoll EJDB database collection handle. + * @param fpath Field path to collect distinct values from. + * @param qobj Main BSON query object. + * @param orqobjs Array of additional OR query objects (joined with OR predicate). + * @param orqobjsnum Number of OR query objects. + * + * NOTE: Queries with update instruction not supported. + * + * @return Unique values by specified path and query (as BSON array) + */ +EJDB_EXPORT bson* ejdbqrydistinct(EJCOLL *jcoll, const char *fpath, bson *qobj, bson *orqobjs, int orqobjsnum, uint32_t *count, TCXSTR *log); + +/** * Synchronize content of a EJDB collection database with the file on device. * @param jcoll EJDB collection. * @return On success return true. diff --git a/src/ejdb/tests/ejdbtest2.c b/src/ejdb/tests/ejdbtest2.c index 5652c66..1e2f0dd 100644 --- a/src/ejdb/tests/ejdbtest2.c +++ b/src/ejdb/tests/ejdbtest2.c @@ -5521,6 +5521,46 @@ void testSlice(void) { } +void testDistinct() { + EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(contacts); + + int count; + TCXSTR *log; + bson *q1res; + + log = tcxstrnew(); + q1res = ejdbqrydistinct(contacts, "address", NULL, NULL, 0, &count, log); + + CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); + CU_ASSERT_EQUAL(count, 4); + + bson_del(q1res); + + bson bsq1; + bson_init_as_query(&bsq1); + bson_append_string(&bsq1, "address.street", "Pirogova"); + bson_finish(&bsq1); + CU_ASSERT_FALSE_FATAL(bsq1.err); + + q1res = ejdbqrydistinct(contacts, "address.room", &bsq1, NULL, 0, &count, log); + + CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); + CU_ASSERT_EQUAL(count, 1); + + bson_del(q1res); + + q1res = ejdbqrydistinct(contacts, "nonexisted", NULL, NULL, 0, &count, log); + + CU_ASSERT_PTR_NOT_NULL_FATAL(q1res); + CU_ASSERT_EQUAL(count, 0); + + bson_del(q1res); + + bson_destroy(&bsq1); + tcxstrdel(log); +} + int main() { setlocale(LC_ALL, "en_US.UTF-8"); @@ -5604,6 +5644,7 @@ int main() { (NULL == CU_add_test(pSuite, "testTicket99", testTicket99)) || (NULL == CU_add_test(pSuite, "testTicket101", testTicket101)) || (NULL == CU_add_test(pSuite, "testTicket110", testTicket110)) || + (NULL == CU_add_test(pSuite, "testDistinct", testDistinct)) || (NULL == CU_add_test(pSuite, "testSlice", testSlice)) || (NULL == CU_add_test(pSuite, "testMetaInfo", testMetaInfo)) |