summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Adamansky <adamansky@gmail.com>2015-03-18 00:17:33 +0600
committerAnton Adamansky <adamansky@gmail.com>2015-03-18 00:17:33 +0600
commitf6b62658ceb44dc514bfb2ef2f063ff8da5d2bf1 (patch)
tree9c7c948a9d10f88f8c2d297b55721a626b916399
parentcf5b27bd7a84a8174dae93c8f5d1fd028305d20b (diff)
parentc4559322ce212f63024cb92128022bd21dbb583f (diff)
downloadejdb-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.c73
-rw-r--r--src/ejdb/ejdb.h15
-rw-r--r--src/ejdb/tests/ejdbtest2.c41
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))