42c480c1ecc48110fa41eda281f698ee147c1c66
[platform/upstream/ejdb.git] / src / ejdb / tests / ejdbtest2.c
1 /*
2  * File:   newcunittest.c
3  * Author: Adamansky Anton <adamansky@gmail.com>
4  *
5  * Created on Oct 1, 2012, 3:13:44 PM
6  */
7
8 #include "myconf.h"
9 #include "ejdb_private.h"
10 #include "CUnit/Basic.h"
11
12 /*
13  * CUnit Test Suite
14  */
15
16 static EJDB *jb;
17
18 int init_suite(void) {
19     jb = ejdbnew();
20     if (!ejdbopen(jb, "dbt2", JBOWRITER | JBOCREAT | JBOTRUNC)) {
21         return 1;
22     }
23     return 0;
24 }
25
26 int clean_suite(void) {
27     ejdbrmcoll(jb, "contacts", true);
28     ejdbclose(jb);
29     ejdbdel(jb);
30     return 0;
31 }
32
33 void testAddData(void) {
34     CU_ASSERT_PTR_NOT_NULL_FATAL(jb);
35     bson_oid_t oid;
36     EJCOLL *ccoll = ejdbcreatecoll(jb, "contacts", NULL);
37     CU_ASSERT_PTR_NOT_NULL(ccoll);
38
39     //Record 1
40     bson a1;
41
42     bson_init(&a1);
43     bson_append_string(&a1, "name", "Антонов");
44     bson_append_string(&a1, "phone", "333-222-333");
45     bson_append_int(&a1, "age", 33);
46     bson_append_long(&a1, "longscore", 0xFFFFFFFFFF01LL);
47     bson_append_double(&a1, "dblscore", 0.333333);
48     bson_append_start_object(&a1, "address");
49     bson_append_string(&a1, "city", "Novosibirsk");
50     bson_append_string(&a1, "country", "Russian Federation");
51     bson_append_string(&a1, "zip", "630090");
52     bson_append_string(&a1, "street", "Pirogova");
53     bson_append_int(&a1, "room", 334);
54     bson_append_finish_object(&a1); //EOF address
55     bson_append_start_array(&a1, "complexarr");
56     bson_append_start_object(&a1, "0");
57     bson_append_string(&a1, "key", "title");
58     bson_append_string(&a1, "value", "some title");
59     bson_append_finish_object(&a1);
60     bson_append_start_object(&a1, "1");
61     bson_append_string(&a1, "key", "comment");
62     bson_append_string(&a1, "value", "some comment");
63     bson_append_finish_object(&a1);
64     bson_append_finish_array(&a1); //EOF complexarr
65     CU_ASSERT_FALSE_FATAL(a1.err);
66         bson_append_symbol(&a1, "symbol", "apple");
67     bson_finish(&a1);
68     ejdbsavebson(ccoll, &a1, &oid);
69     bson_destroy(&a1);
70
71     //Record 2
72     bson_init(&a1);
73     bson_append_string(&a1, "name", "Адаманский");
74     bson_append_string(&a1, "phone", "444-123-333");
75     bson_append_long(&a1, "longscore", 0xFFFFFFFFFF02LL);
76     bson_append_double(&a1, "dblscore", 0.93);
77     bson_append_start_object(&a1, "address");
78     bson_append_string(&a1, "city", "Novosibirsk");
79     bson_append_string(&a1, "country", "Russian Federation");
80     bson_append_string(&a1, "zip", "630090");
81     bson_append_string(&a1, "street", "Pirogova");
82     bson_append_finish_object(&a1);
83     bson_append_start_array(&a1, "complexarr");
84     bson_append_start_object(&a1, "0");
85     bson_append_string(&a1, "key", "title");
86     bson_append_string(&a1, "value", "some title");
87     bson_append_finish_object(&a1);
88     bson_append_start_object(&a1, "1");
89     bson_append_string(&a1, "key", "title");
90     bson_append_string(&a1, "value", "some other title");
91     bson_append_finish_object(&a1);
92     bson_append_int(&a1, "2", 333);
93     bson_append_finish_array(&a1); //EOF complexarr
94     bson_append_start_array(&a1, "labels");
95     bson_append_string(&a1, "0", "red");
96     bson_append_string(&a1, "1", "green");
97     bson_append_string(&a1, "2", "with gap, label");
98     bson_append_finish_array(&a1);
99     bson_append_start_array(&a1, "drinks");
100     bson_append_int(&a1, "0", 4);
101     bson_append_long(&a1, "1", 556667);
102     bson_append_double(&a1, "2", 77676.22);
103     bson_append_finish_array(&a1);
104         bson_append_symbol(&a1, "symbol", "application");
105
106     bson_finish(&a1);
107     CU_ASSERT_FALSE_FATAL(a1.err);
108     ejdbsavebson(ccoll, &a1, &oid);
109     bson_destroy(&a1);
110
111     //Record 3
112     bson_init(&a1);
113     bson_append_string(&a1, "name", "Ivanov");
114     bson_append_long(&a1, "longscore", 66);
115     bson_append_double(&a1, "dblscore", 1.0);
116     bson_append_start_object(&a1, "address");
117     bson_append_string(&a1, "city", "Petropavlovsk");
118     bson_append_string(&a1, "country", "Russian Federation");
119     bson_append_string(&a1, "zip", "683042");
120     bson_append_string(&a1, "street", "Dalnaya");
121     bson_append_finish_object(&a1);
122     bson_append_start_array(&a1, "drinks");
123     bson_append_int(&a1, "0", 41);
124     bson_append_long(&a1, "1", 222334);
125     bson_append_double(&a1, "2", 77676.22);
126     bson_append_finish_array(&a1);
127         bson_append_symbol(&a1, "symbol", "bison");
128     bson_finish(&a1);
129     CU_ASSERT_FALSE_FATAL(a1.err);
130
131     CU_ASSERT_TRUE(ejdbsavebson(ccoll, &a1, &oid));
132     bson_destroy(&a1);
133 }
134
135 void testInvalidQueries1(void) {
136 }
137
138 void testSetIndex1(void) {
139     EJCOLL *ccoll = ejdbcreatecoll(jb, "contacts", NULL);
140     CU_ASSERT_PTR_NOT_NULL_FATAL(ccoll);
141     CU_ASSERT_TRUE(ejdbsetindex(ccoll, "ab.c.d", JBIDXSTR));
142     CU_ASSERT_TRUE(ejdbsetindex(ccoll, "ab.c.d", JBIDXSTR | JBIDXNUM));
143     CU_ASSERT_TRUE(ejdbsetindex(ccoll, "ab.c.d", JBIDXDROPALL));
144     CU_ASSERT_TRUE(ejdbsetindex(ccoll, "address.zip", JBIDXSTR));
145     CU_ASSERT_TRUE(ejdbsetindex(ccoll, "name", JBIDXSTR));
146
147     //Insert new record with active index
148     //Record 4
149     bson a1;
150     bson_oid_t oid;
151     bson_init(&a1);
152     bson_append_string(&a1, "name", "John Travolta");
153     bson_append_start_object(&a1, "address");
154     bson_append_string(&a1, "country", "USA");
155     bson_append_string(&a1, "zip", "4499995");
156     bson_append_finish_object(&a1);
157     bson_finish(&a1);
158     CU_ASSERT_FALSE_FATAL(a1.err);
159     CU_ASSERT_TRUE(ejdbsavebson(ccoll, &a1, &oid));
160     bson_destroy(&a1);
161
162
163     //Update record 4 with active index
164     //Record 4
165     bson_init(&a1);
166     bson_append_oid(&a1, "_id", &oid);
167     bson_append_string(&a1, "name", "John Travolta2");
168     bson_append_start_object(&a1, "address");
169     bson_append_string(&a1, "country", "USA");
170     bson_append_string(&a1, "zip", "4499996");
171     bson_append_finish_object(&a1);
172     bson_finish(&a1);
173     CU_ASSERT_FALSE_FATAL(a1.err);
174
175     CU_ASSERT_TRUE(ejdbsavebson(ccoll, &a1, &oid));
176     CU_ASSERT_TRUE(ejdbrmbson(ccoll, &oid));
177     bson_destroy(&a1);
178
179     //Save Travolta again
180     bson_init(&a1);
181     bson_append_oid(&a1, "_id", &oid);
182     bson_append_string(&a1, "name", "John Travolta");
183     bson_append_start_object(&a1, "address");
184     bson_append_string(&a1, "country", "USA");
185     bson_append_string(&a1, "zip", "4499996");
186     bson_append_string(&a1, "street", "Beverly Hills");
187     bson_append_finish_object(&a1);
188     bson_append_start_array(&a1, "labels");
189     bson_append_string(&a1, "0", "yellow");
190     bson_append_string(&a1, "1", "red");
191     bson_append_string(&a1, "2", "black");
192     bson_append_finish_array(&a1);
193     bson_finish(&a1);
194     CU_ASSERT_FALSE_FATAL(a1.err);
195     CU_ASSERT_TRUE(ejdbsavebson(ccoll, &a1, &oid));
196     bson_destroy(&a1);
197 }
198
199 void testQuery1(void) {
200     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
201     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
202
203     bson bsq1;
204     bson_init_as_query(&bsq1);
205     bson_append_string(&bsq1, "address.zip", "630090");
206     bson_finish(&bsq1);
207     CU_ASSERT_FALSE_FATAL(bsq1.err);
208
209     bson bshints;
210     bson_init_as_query(&bshints);
211     bson_append_start_object(&bshints, "$orderby");
212     bson_append_int(&bshints, "name", 1); //ASC order on name
213     bson_append_finish_object(&bshints);
214     bson_finish(&bshints);
215     CU_ASSERT_FALSE_FATAL(bshints.err);
216
217     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
218     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
219
220     uint32_t count = 0;
221     TCXSTR *log = tcxstrnew();
222     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
223
224     //for (int i = 0; i < TCLISTNUM(q1res); ++i) {
225     //    void *bsdata = TCLISTVALPTR(q1res, i);
226     //    bson_print_raw(bsdata, 0);
227     //}
228     //fprintf(stderr, "%s", TCXSTRPTR(log));
229
230     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
231     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'saddress.zip'"));
232     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 0"));
233     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
234     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
235     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
236     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
237     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
238     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
239     CU_ASSERT_EQUAL(count, 2);
240     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
241
242
243     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
244         if (i == 0) {
245             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
246             CU_ASSERT_FALSE(bson_compare_string("630090", TCLISTVALPTR(q1res, i), "address.zip"));
247         } else if (i == 1) {
248             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
249             CU_ASSERT_FALSE(bson_compare_string("630090", TCLISTVALPTR(q1res, i), "address.zip"));
250         } else {
251             CU_ASSERT_TRUE(false);
252         }
253     }
254
255     bson_destroy(&bsq1);
256     bson_destroy(&bshints);
257     tclistdel(q1res);
258     ejdbquerydel(q1);
259     tcxstrdel(log);
260 }
261
262 void testQuery2(void) {
263     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
264     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
265
266     bson bsq1;
267     bson_init_as_query(&bsq1);
268     bson_append_string(&bsq1, "address.zip", "630090");
269     bson_finish(&bsq1);
270     CU_ASSERT_FALSE_FATAL(bsq1.err);
271
272     bson bshints;
273     bson_init_as_query(&bshints);
274     bson_append_start_object(&bshints, "$orderby");
275     bson_append_int(&bshints, "name", -1); //DESC order on name
276     bson_append_finish_object(&bshints);
277     bson_finish(&bshints);
278     CU_ASSERT_FALSE_FATAL(bshints.err);
279
280     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
281     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
282
283     uint32_t count = 0;
284     TCXSTR *log = tcxstrnew();
285     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
286
287     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
288     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'saddress.zip'"));
289     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 0"));
290     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
291     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
292     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
293     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
294     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
295     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
296     CU_ASSERT_EQUAL(count, 2);
297     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
298
299     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
300         if (i == 0) {
301             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
302             CU_ASSERT_FALSE(bson_compare_string("630090", TCLISTVALPTR(q1res, i), "address.zip"));
303         } else if (i == 1) {
304             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
305             CU_ASSERT_FALSE(bson_compare_string("630090", TCLISTVALPTR(q1res, i), "address.zip"));
306         } else {
307             CU_ASSERT_TRUE(false);
308         }
309     }
310     bson_destroy(&bsq1);
311     bson_destroy(&bshints);
312     tclistdel(q1res);
313     ejdbquerydel(q1);
314     tcxstrdel(log);
315 }
316
317 void testQuery3(void) {
318     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
319     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
320     CU_ASSERT_TRUE(ejdbsetindex(contacts, "address.zip", JBIDXDROPALL));
321
322     bson bsq1;
323     bson_init_as_query(&bsq1);
324     bson_append_string(&bsq1, "address.zip", "630090");
325     bson_finish(&bsq1);
326     CU_ASSERT_FALSE_FATAL(bsq1.err);
327
328     bson bshints;
329     bson_init_as_query(&bshints);
330     bson_append_start_object(&bshints, "$orderby");
331     bson_append_int(&bshints, "name", 1); //ASC order on name
332     bson_append_finish_object(&bshints);
333     bson_finish(&bshints);
334     CU_ASSERT_FALSE_FATAL(bshints.err);
335
336     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
337     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
338
339     uint32_t count = 0;
340     TCXSTR *log = tcxstrnew();
341     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
342
343     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
344     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'sname'"));
345     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 20"));
346     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
347     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
348     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
349     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
350     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
351     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
352     CU_ASSERT_EQUAL(count, 2);
353     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
354
355     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
356         if (i == 0) {
357             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
358             CU_ASSERT_FALSE(bson_compare_string("630090", TCLISTVALPTR(q1res, i), "address.zip"));
359         } else if (i == 1) {
360             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
361             CU_ASSERT_FALSE(bson_compare_string("630090", TCLISTVALPTR(q1res, i), "address.zip"));
362         } else {
363             CU_ASSERT_TRUE(false);
364         }
365     }
366
367     bson_destroy(&bsq1);
368     bson_destroy(&bshints);
369     tclistdel(q1res);
370     ejdbquerydel(q1);
371     tcxstrdel(log);
372 }
373
374 void testQuery4(void) {
375     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
376     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
377     CU_ASSERT_TRUE(ejdbsetindex(contacts, "name", JBIDXDROPALL));
378
379     bson bsq1;
380     bson_init_as_query(&bsq1);
381     bson_append_string(&bsq1, "address.zip", "630090");
382     bson_finish(&bsq1);
383     CU_ASSERT_FALSE_FATAL(bsq1.err);
384
385     bson bshints;
386     bson_init_as_query(&bshints);
387     bson_append_start_object(&bshints, "$orderby");
388     bson_append_int(&bshints, "name", 1); //ASC order on name
389     bson_append_finish_object(&bshints);
390     bson_finish(&bshints);
391     CU_ASSERT_FALSE_FATAL(bshints.err);
392
393     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
394     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
395
396     uint32_t count = 0;
397     TCXSTR *log = tcxstrnew();
398     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
399
400     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
401     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
402     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
403     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
404     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
405     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
406     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
407     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
408     CU_ASSERT_EQUAL(count, 2);
409     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
410
411     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
412         if (i == 0) {
413             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
414             CU_ASSERT_FALSE(bson_compare_string("630090", TCLISTVALPTR(q1res, i), "address.zip"));
415         } else if (i == 1) {
416             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
417             CU_ASSERT_FALSE(bson_compare_string("630090", TCLISTVALPTR(q1res, i), "address.zip"));
418         } else {
419             CU_ASSERT_TRUE(false);
420         }
421     }
422     bson_destroy(&bsq1);
423     bson_destroy(&bshints);
424     tclistdel(q1res);
425     ejdbquerydel(q1);
426     tcxstrdel(log);
427 }
428
429 void testQuery5(void) {
430     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
431     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
432     bson bsq1;
433     bson_init_as_query(&bsq1);
434     bson_append_string(&bsq1, "labels", "red");
435     bson_finish(&bsq1);
436     CU_ASSERT_FALSE_FATAL(bsq1.err);
437
438     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
439     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
440
441     uint32_t count = 0;
442     TCXSTR *log = tcxstrnew();
443     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
444     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
445     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
446     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
447     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
448     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
449     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
450     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
451     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
452     CU_ASSERT_EQUAL(count, 2);
453     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
454
455     bson_destroy(&bsq1);
456     tclistdel(q1res);
457     tcxstrdel(log);
458     ejdbquerydel(q1);
459 }
460
461 void testQuery6(void) {
462     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
463     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
464     CU_ASSERT_TRUE(ejdbsetindex(contacts, "labels", JBIDXARR));
465
466     bson bsq1;
467     bson_init_as_query(&bsq1);
468     bson_append_string(&bsq1, "labels", "red");
469     bson_finish(&bsq1);
470     CU_ASSERT_FALSE_FATAL(bsq1.err);
471
472     bson bshints;
473     bson_init_as_query(&bshints);
474     bson_append_start_object(&bshints, "$orderby");
475     bson_append_int(&bshints, "name", 1); //ASC order on name
476     bson_append_finish_object(&bshints);
477     bson_finish(&bshints);
478     CU_ASSERT_FALSE_FATAL(bshints.err);
479
480     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
481     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
482
483     uint32_t count = 0;
484     TCXSTR *log = tcxstrnew();
485     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
486     //fprintf(stderr, "%s", TCXSTRPTR(log));
487
488     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
489     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'alabels'"));
490     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
491     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
492     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
493     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 5"));
494     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"red\" 2"));
495     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
496     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
497     CU_ASSERT_EQUAL(count, 2);
498     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
499
500     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
501         if (i == 0) {
502             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
503             CU_ASSERT_FALSE(bson_compare_string("4499996", TCLISTVALPTR(q1res, i), "address.zip"));
504         } else if (i == 1) {
505             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
506             CU_ASSERT_FALSE(bson_compare_string("630090", TCLISTVALPTR(q1res, i), "address.zip"));
507         } else {
508             CU_ASSERT_TRUE(false);
509         }
510     }
511
512     bson_destroy(&bsq1);
513     bson_destroy(&bshints);
514     tclistdel(q1res);
515     tcxstrdel(log);
516     ejdbquerydel(q1);
517 }
518
519 void testQuery7(void) {
520     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
521     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
522
523     bson bsq1;
524     bson_init_as_query(&bsq1);
525     bson_append_string(&bsq1, "labels", "with gap, label");
526     bson_finish(&bsq1);
527     CU_ASSERT_FALSE_FATAL(bsq1.err);
528
529     bson bshints;
530     bson_init_as_query(&bshints);
531     bson_append_start_object(&bshints, "$orderby");
532     bson_append_int(&bshints, "name", 1); //ASC order on name
533     bson_append_finish_object(&bshints);
534     bson_finish(&bshints);
535     CU_ASSERT_FALSE_FATAL(bshints.err);
536
537     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
538     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
539
540     uint32_t count = 0;
541     TCXSTR *log = tcxstrnew();
542     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
543     //fprintf(stderr, "%s", TCXSTRPTR(log));
544
545     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
546     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'alabels'"));
547     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
548     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
549     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
550     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 5"));
551     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"with gap, label\" 1"));
552     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
553     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 1"));
554     CU_ASSERT_EQUAL(count, 1);
555     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 1);
556
557     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
558         if (i == 0) {
559             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
560         } else {
561             CU_ASSERT_TRUE(false);
562         }
563     }
564
565     bson_destroy(&bsq1);
566     bson_destroy(&bshints);
567     tclistdel(q1res);
568     tcxstrdel(log);
569     ejdbquerydel(q1);
570 }
571
572 void testQuery8(void) {
573     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
574     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
575
576     //"labels" : {"$in" : ["yellow", "green"]}
577     bson bsq1;
578     bson_init_as_query(&bsq1);
579     bson_append_start_object(&bsq1, "labels");
580     bson_append_start_array(&bsq1, "$in");
581     bson_append_string(&bsq1, "0", "green");
582     bson_append_string(&bsq1, "1", "yellow");
583     bson_append_finish_array(&bsq1);
584     bson_append_finish_object(&bsq1);
585     bson_finish(&bsq1);
586     CU_ASSERT_FALSE_FATAL(bsq1.err);
587
588     bson bshints;
589     bson_init_as_query(&bshints);
590     bson_append_start_object(&bshints, "$orderby");
591     bson_append_int(&bshints, "name", 1); //ASC order on name
592     bson_append_finish_object(&bshints);
593     bson_finish(&bshints);
594     CU_ASSERT_FALSE_FATAL(bshints.err);
595
596     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
597     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
598
599     uint32_t count = 0;
600     TCXSTR *log = tcxstrnew();
601     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
602     //fprintf(stderr, "%s", TCXSTRPTR(log));
603
604     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
605     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'alabels'"));
606     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
607     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
608     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
609     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 5"));
610     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"green\" 1"));
611     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"yellow\" 1"));
612     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
613     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
614     CU_ASSERT_EQUAL(count, 2);
615     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
616
617     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
618         if (i == 0) {
619             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
620             CU_ASSERT_FALSE(bson_compare_string("yellow", TCLISTVALPTR(q1res, i), "labels.0"));
621         } else if (i == 1) {
622             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
623             CU_ASSERT_FALSE(bson_compare_string("green", TCLISTVALPTR(q1res, i), "labels.1"));
624         } else {
625             CU_ASSERT_TRUE(false);
626         }
627     }
628
629     bson_destroy(&bsq1);
630     bson_destroy(&bshints);
631     tclistdel(q1res);
632     tcxstrdel(log);
633     ejdbquerydel(q1);
634
635
636     //todo check hash tokens mode
637     CU_ASSERT_TRUE(ejdbsetindex(contacts, "labels", JBIDXDROPALL));
638
639     bson_init_as_query(&bsq1);
640     bson_append_start_object(&bsq1, "labels");
641     bson_append_start_array(&bsq1, "$in");
642
643     char nbuff[TCNUMBUFSIZ];
644     for (int i = 0; i <= JBINOPTMAPTHRESHOLD; ++i) {
645         bson_numstrn(nbuff, TCNUMBUFSIZ, i);
646         if (i == 2) {
647             bson_append_string(&bsq1, nbuff, "green");
648         } else if (i == 8) {
649             bson_append_string(&bsq1, nbuff, "yellow");
650         } else {
651             bson_append_string(&bsq1, nbuff, nbuff);
652         }
653     }
654     bson_append_finish_array(&bsq1);
655     bson_append_finish_object(&bsq1);
656     bson_finish(&bsq1);
657     CU_ASSERT_FALSE_FATAL(bsq1.err);
658
659     bson_init_as_query(&bshints);
660     bson_append_start_object(&bshints, "$orderby");
661     bson_append_int(&bshints, "name", 1); //ASC order on name
662     bson_append_finish_object(&bshints);
663     bson_finish(&bshints);
664     CU_ASSERT_FALSE_FATAL(bshints.err);
665
666     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
667     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
668     log = tcxstrnew();
669     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
670     //fprintf(stderr, "%s", TCXSTRPTR(log));
671
672     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "USING HASH TOKENS IN: labels"));
673     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
674     CU_ASSERT_EQUAL(count, 2);
675     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
676     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
677         if (i == 0) {
678             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
679             CU_ASSERT_FALSE(bson_compare_string("yellow", TCLISTVALPTR(q1res, i), "labels.0"));
680         } else if (i == 1) {
681             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
682             CU_ASSERT_FALSE(bson_compare_string("green", TCLISTVALPTR(q1res, i), "labels.1"));
683         } else {
684             CU_ASSERT_TRUE(false);
685         }
686     }
687
688     bson_destroy(&bsq1);
689     bson_destroy(&bshints);
690     tclistdel(q1res);
691     tcxstrdel(log);
692     ejdbquerydel(q1);
693 }
694
695 void testQuery9(void) {
696     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
697     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
698     CU_ASSERT_TRUE(ejdbsetindex(contacts, "labels", JBIDXDROPALL));
699
700     bson bsq1;
701     bson_init_as_query(&bsq1);
702     bson_append_string(&bsq1, "labels", "red");
703     bson_finish(&bsq1);
704     CU_ASSERT_FALSE_FATAL(bsq1.err);
705
706     bson bshints;
707     bson_init_as_query(&bshints);
708     bson_append_start_object(&bshints, "$orderby");
709     bson_append_int(&bshints, "name", 1); //ASC order on name
710     bson_append_finish_object(&bshints);
711     bson_finish(&bshints);
712     CU_ASSERT_FALSE_FATAL(bshints.err);
713
714     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
715     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
716
717     uint32_t count = 0;
718     TCXSTR *log = tcxstrnew();
719     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
720
721     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
722     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
723     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
724     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
725     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
726     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP"));
727     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
728     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
729     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
730     CU_ASSERT_EQUAL(count, 2);
731     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
732
733     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
734         if (i == 0) {
735             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
736             CU_ASSERT_FALSE(bson_compare_string("4499996", TCLISTVALPTR(q1res, i), "address.zip"));
737         } else if (i == 1) {
738             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
739             CU_ASSERT_FALSE(bson_compare_string("630090", TCLISTVALPTR(q1res, i), "address.zip"));
740         } else {
741             CU_ASSERT_TRUE(false);
742         }
743     }
744
745
746     bson_destroy(&bsq1);
747     bson_destroy(&bshints);
748     tclistdel(q1res);
749     tcxstrdel(log);
750     ejdbquerydel(q1);
751 }
752
753 void testQuery10(void) {
754     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
755     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
756     CU_ASSERT_TRUE(ejdbsetindex(contacts, "address.street", JBIDXSTR));
757
758     //"address.street" : {"$in" : ["Pirogova", "Beverly Hills"]}
759     bson bsq1;
760     bson_init_as_query(&bsq1);
761     bson_append_start_object(&bsq1, "address.street");
762     bson_append_start_array(&bsq1, "$in");
763     bson_append_string(&bsq1, "0", "Pirogova");
764     bson_append_string(&bsq1, "1", "Beverly Hills");
765     bson_append_finish_array(&bsq1);
766     bson_append_finish_object(&bsq1);
767     bson_finish(&bsq1);
768     CU_ASSERT_FALSE_FATAL(bsq1.err);
769
770     bson bshints;
771     bson_init_as_query(&bshints);
772     bson_append_start_object(&bshints, "$orderby");
773     bson_append_int(&bshints, "name", 1); //ASC order on name
774     bson_append_finish_object(&bshints);
775     bson_finish(&bshints);
776     CU_ASSERT_FALSE_FATAL(bshints.err);
777
778     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
779     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
780
781     uint32_t count = 0;
782     TCXSTR *log = tcxstrnew();
783     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
784
785     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
786     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'saddress.street'"));
787     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
788     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
789     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
790     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 6"));
791     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
792     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
793     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 3"));
794     CU_ASSERT_EQUAL(count, 3);
795     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 3);
796
797     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
798         if (i == 0) {
799             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
800             CU_ASSERT_FALSE(bson_compare_string("Beverly Hills", TCLISTVALPTR(q1res, i), "address.street"));
801         } else if (i == 1) {
802             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
803             CU_ASSERT_FALSE(bson_compare_string("Pirogova", TCLISTVALPTR(q1res, i), "address.street"));
804         } else if (i == 2) {
805             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
806             CU_ASSERT_FALSE(bson_compare_string("Pirogova", TCLISTVALPTR(q1res, i), "address.street"));
807         } else {
808             CU_ASSERT_TRUE(false);
809         }
810     }
811     bson_destroy(&bsq1);
812     bson_destroy(&bshints);
813     tclistdel(q1res);
814     tcxstrdel(log);
815     ejdbquerydel(q1);
816 }
817
818 void testQuery11(void) {
819     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
820     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
821     CU_ASSERT_TRUE(ejdbsetindex(contacts, "address.street", JBIDXDROPALL));
822
823     //"address.street" : {"$in" : ["Pirogova", "Beverly Hills"]}
824     bson bsq1;
825     bson_init_as_query(&bsq1);
826     bson_append_start_object(&bsq1, "address.street");
827     bson_append_start_array(&bsq1, "$in");
828     bson_append_string(&bsq1, "0", "Pirogova");
829     bson_append_string(&bsq1, "1", "Beverly Hills");
830     bson_append_finish_array(&bsq1);
831     bson_append_finish_object(&bsq1);
832     bson_finish(&bsq1);
833     CU_ASSERT_FALSE_FATAL(bsq1.err);
834
835     bson bshints;
836     bson_init_as_query(&bshints);
837     bson_append_start_object(&bshints, "$orderby");
838     bson_append_int(&bshints, "name", 1); //ASC order on name
839     bson_append_finish_object(&bshints);
840     bson_finish(&bshints);
841     CU_ASSERT_FALSE_FATAL(bshints.err);
842
843     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
844     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
845
846     uint32_t count = 0;
847     TCXSTR *log = tcxstrnew();
848     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
849
850     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
851     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
852     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
853     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
854     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
855     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP"));
856     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
857     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
858     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 3"));
859     CU_ASSERT_EQUAL(count, 3);
860     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 3);
861
862     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
863         if (i == 0) {
864             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
865             CU_ASSERT_FALSE(bson_compare_string("Beverly Hills", TCLISTVALPTR(q1res, i), "address.street"));
866         } else if (i == 1) {
867             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
868             CU_ASSERT_FALSE(bson_compare_string("Pirogova", TCLISTVALPTR(q1res, i), "address.street"));
869         } else if (i == 2) {
870             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
871             CU_ASSERT_FALSE(bson_compare_string("Pirogova", TCLISTVALPTR(q1res, i), "address.street"));
872         } else {
873             CU_ASSERT_TRUE(false);
874         }
875     }
876
877     bson_destroy(&bsq1);
878     bson_destroy(&bshints);
879     tclistdel(q1res);
880     tcxstrdel(log);
881     ejdbquerydel(q1);
882 }
883
884 void testQuery12(void) {
885     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
886     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
887
888     //"labels" : {"$in" : ["yellow", "green"]}
889     bson bsq1;
890     bson_init_as_query(&bsq1);
891     bson_append_start_object(&bsq1, "labels");
892     bson_append_start_array(&bsq1, "$in");
893     bson_append_string(&bsq1, "0", "green");
894     bson_append_string(&bsq1, "1", "yellow");
895     bson_append_finish_array(&bsq1);
896     bson_append_finish_object(&bsq1);
897     bson_finish(&bsq1);
898     CU_ASSERT_FALSE_FATAL(bsq1.err);
899
900     bson bshints;
901     bson_init_as_query(&bshints);
902     bson_append_start_object(&bshints, "$orderby");
903     bson_append_int(&bshints, "name", 1); //ASC order on name
904     bson_append_finish_object(&bshints);
905     bson_finish(&bshints);
906     CU_ASSERT_FALSE_FATAL(bshints.err);
907
908     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
909     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
910
911     uint32_t count = 0;
912     TCXSTR *log = tcxstrnew();
913     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
914     //fprintf(stderr, "%s", TCXSTRPTR(log));
915
916     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
917     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
918     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
919     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
920     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
921     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP"));
922     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
923     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
924     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
925     CU_ASSERT_EQUAL(count, 2);
926     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
927
928     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
929         if (i == 0) {
930             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
931             CU_ASSERT_FALSE(bson_compare_string("yellow", TCLISTVALPTR(q1res, i), "labels.0"));
932         } else if (i == 1) {
933             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
934             CU_ASSERT_FALSE(bson_compare_string("green", TCLISTVALPTR(q1res, i), "labels.1"));
935         } else {
936             CU_ASSERT_TRUE(false);
937         }
938     }
939
940     bson_destroy(&bsq1);
941     bson_destroy(&bshints);
942     tclistdel(q1res);
943     tcxstrdel(log);
944     ejdbquerydel(q1);
945 }
946
947 void testQuery13(void) {
948     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
949     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
950
951     //"drinks" : {"$in" : [4, 77676.22]}
952     bson bsq1;
953     bson_init_as_query(&bsq1);
954     bson_append_start_object(&bsq1, "drinks");
955     bson_append_start_array(&bsq1, "$in");
956     bson_append_int(&bsq1, "0", 4);
957     bson_append_double(&bsq1, "1", 77676.22);
958     bson_append_finish_array(&bsq1);
959     bson_append_finish_object(&bsq1);
960     bson_finish(&bsq1);
961     CU_ASSERT_FALSE_FATAL(bsq1.err);
962
963     bson bshints;
964     bson_init_as_query(&bshints);
965     bson_append_start_object(&bshints, "$orderby");
966     bson_append_int(&bshints, "name", 1); //ASC order on name
967     bson_append_finish_object(&bshints);
968     bson_finish(&bshints);
969     CU_ASSERT_FALSE_FATAL(bshints.err);
970
971     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
972     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
973
974     uint32_t count = 0;
975     TCXSTR *log = tcxstrnew();
976     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
977     //fprintf(stderr, "%s", TCXSTRPTR(log));
978
979
980     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
981     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
982     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
983     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
984     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
985     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP"));
986     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
987     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
988     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
989     CU_ASSERT_EQUAL(count, 2);
990     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
991
992     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
993         if (i == 0) {
994             CU_ASSERT_FALSE(bson_compare_string("Ivanov", TCLISTVALPTR(q1res, i), "name"));
995             CU_ASSERT_FALSE(bson_compare_long(41, TCLISTVALPTR(q1res, i), "drinks.0"));
996             CU_ASSERT_FALSE(bson_compare_long(222334, TCLISTVALPTR(q1res, i), "drinks.1"));
997             CU_ASSERT_FALSE(bson_compare_double(77676.22, TCLISTVALPTR(q1res, i), "drinks.2"));
998         } else if (i == 1) {
999             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
1000             CU_ASSERT_FALSE(bson_compare_long(4, TCLISTVALPTR(q1res, i), "drinks.0"));
1001             CU_ASSERT_FALSE(bson_compare_long(556667, TCLISTVALPTR(q1res, i), "drinks.1"));
1002             CU_ASSERT_FALSE(bson_compare_double(77676.22, TCLISTVALPTR(q1res, i), "drinks.2"));
1003         } else {
1004             CU_ASSERT_TRUE(false);
1005         }
1006     }
1007
1008     bson_destroy(&bsq1);
1009     bson_destroy(&bshints);
1010     tclistdel(q1res);
1011     tcxstrdel(log);
1012     ejdbquerydel(q1);
1013 }
1014
1015 void testQuery14(void) {
1016     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
1017     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
1018     CU_ASSERT_TRUE(ejdbsetindex(contacts, "drinks", JBIDXARR));
1019
1020     //"drinks" : {"$in" : [4, 77676.22]}
1021     bson bsq1;
1022     bson_init_as_query(&bsq1);
1023     bson_append_start_object(&bsq1, "drinks");
1024     bson_append_start_array(&bsq1, "$in");
1025     bson_append_int(&bsq1, "0", 4);
1026     bson_append_double(&bsq1, "1", 77676.22);
1027     bson_append_finish_array(&bsq1);
1028     bson_append_finish_object(&bsq1);
1029     bson_finish(&bsq1);
1030     CU_ASSERT_FALSE_FATAL(bsq1.err);
1031
1032     bson bshints;
1033     bson_init_as_query(&bshints);
1034     bson_append_start_object(&bshints, "$orderby");
1035     bson_append_int(&bshints, "name", 1); //ASC order on name
1036     bson_append_finish_object(&bshints);
1037     bson_finish(&bshints);
1038     CU_ASSERT_FALSE_FATAL(bshints.err);
1039
1040     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1041     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1042
1043     uint32_t count = 0;
1044     TCXSTR *log = tcxstrnew();
1045     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1046     //fprintf(stderr, "%s", TCXSTRPTR(log));
1047
1048     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1049     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'adrinks'"));
1050     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1051     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1052     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
1053     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 21"));
1054     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1055     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"4\" 1"));
1056     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"77676.220000\" 2"));
1057     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
1058     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
1059     CU_ASSERT_EQUAL(count, 2);
1060     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
1061
1062     bson_destroy(&bsq1);
1063     bson_destroy(&bshints);
1064     tclistdel(q1res);
1065     tcxstrdel(log);
1066     ejdbquerydel(q1);
1067 }
1068
1069 void testQuery15(void) {
1070     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
1071     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
1072     CU_ASSERT_TRUE(ejdbsetindex(contacts, "dblscore", JBIDXNUM));
1073
1074     bson bsq1;
1075     bson_init_as_query(&bsq1);
1076     bson_append_double(&bsq1, "dblscore", 0.333333);
1077     bson_finish(&bsq1);
1078     CU_ASSERT_FALSE_FATAL(bsq1.err);
1079
1080     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
1081     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1082
1083     uint32_t count = 0;
1084     TCXSTR *log = tcxstrnew();
1085     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1086     //fprintf(stderr, "%s", TCXSTRPTR(log));
1087
1088     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1089     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'ndblscore'"));
1090     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
1091     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1092     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
1093     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 8"));
1094     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1095     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
1096     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 1"));
1097     CU_ASSERT_EQUAL(count, 1);
1098     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 1);
1099
1100     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1101         if (i == 0) {
1102             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
1103             CU_ASSERT_FALSE(bson_compare_double(0.333333, TCLISTVALPTR(q1res, i), "dblscore"));
1104         } else {
1105             CU_ASSERT_TRUE(false);
1106         }
1107     }
1108
1109     bson_destroy(&bsq1);
1110     tclistdel(q1res);
1111     tcxstrdel(log);
1112     ejdbquerydel(q1);
1113 }
1114
1115 void testQuery16(void) {
1116     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
1117     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
1118     CU_ASSERT_TRUE(ejdbsetindex(contacts, "dblscore", JBIDXDROPALL));
1119
1120     bson bsq1;
1121     bson_init_as_query(&bsq1);
1122     bson_append_double(&bsq1, "dblscore", 0.333333);
1123     bson_finish(&bsq1);
1124     CU_ASSERT_FALSE_FATAL(bsq1.err);
1125
1126     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
1127     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1128
1129     uint32_t count = 0;
1130     TCXSTR *log = tcxstrnew();
1131     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1132     //fprintf(stderr, "%s", TCXSTRPTR(log));
1133
1134     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1135     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
1136     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
1137     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1138     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
1139     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1140     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
1141     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 1"));
1142     CU_ASSERT_EQUAL(count, 1);
1143     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 1);
1144
1145     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1146         if (i == 0) {
1147             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
1148             CU_ASSERT_FALSE(bson_compare_double(0.333333, TCLISTVALPTR(q1res, i), "dblscore"));
1149         } else {
1150             CU_ASSERT_TRUE(false);
1151         }
1152     }
1153
1154     bson_destroy(&bsq1);
1155     tclistdel(q1res);
1156     tcxstrdel(log);
1157     ejdbquerydel(q1);
1158 }
1159
1160 void testQuery17(void) {
1161     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
1162     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
1163     CU_ASSERT_TRUE(ejdbsetindex(contacts, "dblscore", JBIDXNUM));
1164
1165     //"dblscore" : {"$bt" : [0.95, 0.3]}
1166     bson bsq1;
1167     bson_init_as_query(&bsq1);
1168     bson_append_start_object(&bsq1, "dblscore");
1169     bson_append_start_array(&bsq1, "$bt");
1170     bson_append_double(&bsq1, "0", 0.95);
1171     bson_append_double(&bsq1, "1", 0.333333);
1172     bson_append_finish_array(&bsq1);
1173     bson_append_finish_object(&bsq1);
1174     bson_finish(&bsq1);
1175     CU_ASSERT_FALSE_FATAL(bsq1.err);
1176
1177
1178     bson bshints;
1179     bson_init_as_query(&bshints);
1180     bson_append_start_object(&bshints, "$orderby");
1181     bson_append_int(&bshints, "dblscore", -1); //DESC order on name
1182     bson_append_finish_object(&bshints);
1183     bson_finish(&bshints);
1184     CU_ASSERT_FALSE_FATAL(bshints.err);
1185
1186     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1187     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1188
1189     uint32_t count = 0;
1190     TCXSTR *log = tcxstrnew();
1191     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1192     //fprintf(stderr, "%s", TCXSTRPTR(log));
1193
1194     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1195     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'ndblscore'"));
1196     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1197     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1198     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
1199     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1200     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 13"));
1201     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
1202     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
1203     CU_ASSERT_EQUAL(count, 2);
1204     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
1205
1206     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1207         if (i == 0) {
1208             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
1209             CU_ASSERT_FALSE(bson_compare_double(0.93, TCLISTVALPTR(q1res, i), "dblscore"));
1210         } else if (i == 1) {
1211             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
1212             CU_ASSERT_FALSE(bson_compare_double(0.333333, TCLISTVALPTR(q1res, i), "dblscore"));
1213         } else {
1214             CU_ASSERT_TRUE(false);
1215         }
1216     }
1217
1218     //Second query
1219     tcxstrclear(log);
1220     bson_destroy(&bsq1);
1221     bson_destroy(&bshints);
1222     tclistdel(q1res);
1223     ejdbquerydel(q1);
1224
1225     CU_ASSERT_TRUE(ejdbsetindex(contacts, "dblscore", JBIDXDROPALL));
1226
1227     bson_init_as_query(&bsq1);
1228     bson_append_start_object(&bsq1, "dblscore");
1229     bson_append_start_array(&bsq1, "$bt");
1230     bson_append_double(&bsq1, "0", 0.95);
1231     bson_append_double(&bsq1, "1", 0.333333);
1232     bson_append_finish_array(&bsq1);
1233     bson_append_finish_object(&bsq1);
1234     bson_finish(&bsq1);
1235     CU_ASSERT_FALSE_FATAL(bsq1.err);
1236
1237
1238     bson_init_as_query(&bshints);
1239     bson_append_start_object(&bshints, "$orderby");
1240     bson_append_int(&bshints, "dblscore", 1); //ASC order on name
1241     bson_append_finish_object(&bshints);
1242     bson_finish(&bshints);
1243     CU_ASSERT_FALSE_FATAL(bshints.err);
1244
1245     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1246     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1247
1248     count = 0;
1249     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1250
1251     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1252     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
1253     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1254     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1255     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
1256     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1257     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
1258     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
1259     CU_ASSERT_EQUAL(count, 2);
1260     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
1261
1262     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1263         if (i == 0) {
1264             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
1265             CU_ASSERT_FALSE(bson_compare_double(0.333333, TCLISTVALPTR(q1res, i), "dblscore"));
1266         } else if (i == 1) {
1267             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
1268             CU_ASSERT_FALSE(bson_compare_double(0.93, TCLISTVALPTR(q1res, i), "dblscore"));
1269         } else {
1270             CU_ASSERT_TRUE(false);
1271         }
1272     }
1273
1274     bson_destroy(&bsq1);
1275     bson_destroy(&bshints);
1276     tclistdel(q1res);
1277     tcxstrdel(log);
1278     ejdbquerydel(q1);
1279 }
1280
1281 void testQuery18(void) {
1282     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
1283     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
1284     CU_ASSERT_TRUE(ejdbsetindex(contacts, "name", JBIDXARR));
1285
1286     //{"name" : {$strand : ["Travolta", "John"]}}
1287     bson bsq1;
1288     bson_init_as_query(&bsq1);
1289     bson_append_start_object(&bsq1, "name");
1290     bson_append_start_array(&bsq1, "$strand");
1291     bson_append_string(&bsq1, "0", "Travolta");
1292     bson_append_string(&bsq1, "1", "John");
1293     bson_append_finish_array(&bsq1);
1294     bson_append_finish_object(&bsq1);
1295     bson_finish(&bsq1);
1296     CU_ASSERT_FALSE_FATAL(bsq1.err);
1297
1298     bson bshints;
1299     bson_init_as_query(&bshints);
1300     /*bson_append_start_object(&bshints, "$orderby");
1301     bson_append_int(&bshints, "dblscore", 1); //ASC order on name
1302     bson_append_finish_object(&bshints);*/
1303     bson_finish(&bshints);
1304     CU_ASSERT_FALSE_FATAL(bshints.err);
1305
1306     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1307     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1308
1309     uint32_t count = 0;
1310     TCXSTR *log = tcxstrnew();
1311     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1312     //fprintf(stderr, "%s", TCXSTRPTR(log));
1313
1314     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1315     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'aname'"));
1316     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
1317     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1318     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
1319     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1320     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 4"));
1321     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"John\" 1"));
1322     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"Travolta\" 1"));
1323     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
1324     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 1"));
1325     CU_ASSERT_EQUAL(count, 1);
1326     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 1);
1327
1328     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1329         if (i == 0) {
1330             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
1331         } else {
1332             CU_ASSERT_TRUE(false);
1333         }
1334     }
1335
1336     //Second query
1337     tcxstrclear(log);
1338     tclistdel(q1res);
1339     CU_ASSERT_TRUE(ejdbsetindex(contacts, "name", JBIDXDROPALL));
1340
1341     count = 0;
1342     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1343
1344     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1345     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
1346     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
1347     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1348     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
1349     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1350     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
1351     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 1"));
1352     CU_ASSERT_EQUAL(count, 1);
1353     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 1);
1354
1355     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1356         if (i == 0) {
1357             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
1358         } else {
1359             CU_ASSERT_TRUE(false);
1360         }
1361     }
1362
1363     bson_destroy(&bsq1);
1364     bson_destroy(&bshints);
1365     tclistdel(q1res);
1366     ejdbquerydel(q1);
1367
1368     //Third query
1369     CU_ASSERT_TRUE(ejdbsetindex(contacts, "labels", JBIDXARR));
1370
1371     bson_init_as_query(&bsq1);
1372     bson_append_start_object(&bsq1, "labels");
1373     bson_append_start_array(&bsq1, "$strand");
1374     bson_append_string(&bsq1, "0", "red");
1375     bson_append_string(&bsq1, "1", "black");
1376     bson_append_finish_array(&bsq1);
1377     bson_append_finish_object(&bsq1);
1378     bson_finish(&bsq1);
1379     CU_ASSERT_FALSE_FATAL(bsq1.err);
1380
1381     count = 0;
1382     tcxstrclear(log);
1383     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
1384     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1385     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1386     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 1"));
1387     CU_ASSERT_EQUAL(count, 1);
1388     //fprintf(stderr, "%s", TCXSTRPTR(log));
1389
1390     bson_destroy(&bsq1);
1391     tclistdel(q1res);
1392     tcxstrdel(log);
1393     ejdbquerydel(q1);
1394 }
1395
1396 void testQuery19(void) {
1397     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
1398     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
1399     CU_ASSERT_TRUE(ejdbsetindex(contacts, "name", JBIDXARR));
1400
1401     //{"name" : {$stror : ["Travolta", "Антонов", "John"]}}
1402     bson bsq1;
1403     bson_init_as_query(&bsq1);
1404     bson_append_start_object(&bsq1, "name");
1405     bson_append_start_array(&bsq1, "$stror");
1406     bson_append_string(&bsq1, "0", "Travolta");
1407     bson_append_string(&bsq1, "1", "Антонов");
1408     bson_append_string(&bsq1, "2", "John");
1409     bson_append_finish_array(&bsq1);
1410     bson_append_finish_object(&bsq1);
1411     bson_finish(&bsq1);
1412     CU_ASSERT_FALSE_FATAL(bsq1.err);
1413
1414     bson bshints;
1415     bson_init_as_query(&bshints);
1416     bson_append_start_object(&bshints, "$orderby");
1417     bson_append_int(&bshints, "name", -1); //DESC order on name
1418     bson_append_finish_object(&bshints);
1419     bson_finish(&bshints);
1420     CU_ASSERT_FALSE_FATAL(bshints.err);
1421
1422     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1423     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1424
1425     uint32_t count = 0;
1426     TCXSTR *log = tcxstrnew();
1427     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1428     //fprintf(stderr, "%s", TCXSTRPTR(log));
1429
1430     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1431     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'aname'"));
1432     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1433     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1434     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
1435     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 5"));
1436     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"John\" 1"));
1437     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"Travolta\" 1"));
1438     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"Антонов\" 1"));
1439     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1440     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
1441     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
1442     CU_ASSERT_EQUAL(count, 2);
1443     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
1444
1445     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1446         if (i == 0) {
1447             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
1448         } else if (i == 1) {
1449             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
1450         } else {
1451             CU_ASSERT_TRUE(false);
1452         }
1453     }
1454
1455     //No-index query
1456     tcxstrclear(log);
1457     tclistdel(q1res);
1458     CU_ASSERT_TRUE(ejdbsetindex(contacts, "name", JBIDXDROPALL));
1459
1460     count = 0;
1461     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1462     //fprintf(stderr, "%s", TCXSTRPTR(log));
1463
1464     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1465     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
1466     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1467     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1468     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
1469     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1470     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
1471     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
1472     CU_ASSERT_EQUAL(count, 2);
1473     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
1474
1475     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1476         if (i == 0) {
1477             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
1478         } else if (i == 1) {
1479             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
1480         } else {
1481             CU_ASSERT_TRUE(false);
1482         }
1483     }
1484
1485     bson_destroy(&bsq1);
1486     bson_destroy(&bshints);
1487     tclistdel(q1res);
1488     tcxstrdel(log);
1489     ejdbquerydel(q1);
1490 }
1491
1492 void testQuery20(void) {
1493     //dblscore
1494     //{'dblscore' : {'$gte' : 0.93}}
1495     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
1496     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
1497     CU_ASSERT_TRUE(ejdbsetindex(contacts, "dblscore", JBIDXNUM));
1498
1499     bson bsq1;
1500     bson_init_as_query(&bsq1);
1501     bson_append_start_object(&bsq1, "dblscore");
1502     bson_append_double(&bsq1, "$gte", 0.93);
1503     bson_append_finish_object(&bsq1);
1504     bson_finish(&bsq1);
1505     CU_ASSERT_FALSE_FATAL(bsq1.err);
1506
1507     bson bshints;
1508     bson_init_as_query(&bshints);
1509     bson_append_start_object(&bshints, "$orderby");
1510     bson_append_int(&bshints, "dblscore", 1); //ASC order on dblscore
1511     bson_append_finish_object(&bshints);
1512     bson_finish(&bshints);
1513     CU_ASSERT_FALSE_FATAL(bshints.err);
1514
1515     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1516     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1517
1518     uint32_t count = 0;
1519     TCXSTR *log = tcxstrnew();
1520     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1521     //fprintf(stderr, "%s", TCXSTRPTR(log));
1522
1523     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1524     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'ndblscore'"));
1525     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1526     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1527     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
1528     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 10"));
1529     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1530     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
1531     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
1532     CU_ASSERT_EQUAL(count, 2);
1533     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
1534
1535     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1536         if (i == 0) {
1537             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
1538             CU_ASSERT_FALSE(bson_compare_double(0.93, TCLISTVALPTR(q1res, i), "dblscore"));
1539         } else if (i == 1) {
1540             CU_ASSERT_FALSE(bson_compare_string("Ivanov", TCLISTVALPTR(q1res, i), "name"));
1541             CU_ASSERT_FALSE(bson_compare_double(1.0, TCLISTVALPTR(q1res, i), "dblscore"));
1542         } else {
1543             CU_ASSERT_TRUE(false);
1544         }
1545     }
1546
1547     bson_destroy(&bsq1);
1548     bson_destroy(&bshints);
1549     tclistdel(q1res);
1550     tcxstrdel(log);
1551     ejdbquerydel(q1);
1552
1553     //GT
1554
1555     bson_init_as_query(&bsq1);
1556     bson_append_start_object(&bsq1, "dblscore");
1557     bson_append_double(&bsq1, "$gt", 0.93);
1558     bson_append_finish_object(&bsq1);
1559     bson_finish(&bsq1);
1560     CU_ASSERT_FALSE_FATAL(bsq1.err);
1561
1562     bson_init_as_query(&bshints);
1563     bson_append_start_object(&bshints, "$orderby");
1564     bson_append_int(&bshints, "dblscore", 1); //ASC order on dblscore
1565     bson_append_finish_object(&bshints);
1566     bson_finish(&bshints);
1567     CU_ASSERT_FALSE_FATAL(bshints.err);
1568
1569     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1570     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1571
1572     count = 0;
1573     log = tcxstrnew();
1574     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1575     //fprintf(stderr, "%s", TCXSTRPTR(log));
1576
1577     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1578     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'ndblscore'"));
1579     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1580     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1581     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
1582     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 9"));
1583     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1584     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
1585     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 1"));
1586     CU_ASSERT_EQUAL(count, 1);
1587     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 1);
1588
1589     bson_destroy(&bsq1);
1590     bson_destroy(&bshints);
1591     tclistdel(q1res);
1592     tcxstrdel(log);
1593     ejdbquerydel(q1);
1594
1595     //NOINDEX
1596     CU_ASSERT_TRUE(ejdbsetindex(contacts, "dblscore", JBIDXDROPALL));
1597
1598     //NOINDEX GTE
1599     bson_init_as_query(&bsq1);
1600     bson_append_start_object(&bsq1, "dblscore");
1601     bson_append_double(&bsq1, "$gte", 0.93);
1602     bson_append_finish_object(&bsq1);
1603     bson_finish(&bsq1);
1604     CU_ASSERT_FALSE_FATAL(bsq1.err);
1605
1606     bson_init_as_query(&bshints);
1607     bson_append_start_object(&bshints, "$orderby");
1608     bson_append_int(&bshints, "dblscore", -1); //DESC order on dblscore
1609     bson_append_finish_object(&bshints);
1610     bson_finish(&bshints);
1611     CU_ASSERT_FALSE_FATAL(bshints.err);
1612
1613     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1614     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1615
1616     count = 0;
1617     log = tcxstrnew();
1618     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1619     //fprintf(stderr, "%s", TCXSTRPTR(log));
1620
1621     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1622     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
1623     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1624     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1625     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
1626     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1627     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
1628     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
1629     CU_ASSERT_EQUAL(count, 2);
1630     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
1631
1632     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1633         if (i == 1) {
1634             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
1635             CU_ASSERT_FALSE(bson_compare_double(0.93, TCLISTVALPTR(q1res, i), "dblscore"));
1636         } else if (i == 0) {
1637             CU_ASSERT_FALSE(bson_compare_string("Ivanov", TCLISTVALPTR(q1res, i), "name"));
1638             CU_ASSERT_FALSE(bson_compare_double(1.0, TCLISTVALPTR(q1res, i), "dblscore"));
1639         } else {
1640             CU_ASSERT_TRUE(false);
1641         }
1642     }
1643
1644     bson_destroy(&bsq1);
1645     bson_destroy(&bshints);
1646     tclistdel(q1res);
1647     tcxstrdel(log);
1648     ejdbquerydel(q1);
1649 }
1650
1651 void testQuery21(void) {
1652     //{'dblscore' : {'lte' : 0.93}}
1653     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
1654     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
1655     CU_ASSERT_TRUE(ejdbsetindex(contacts, "dblscore", JBIDXNUM));
1656
1657     //LTE
1658     bson bsq1;
1659     bson_init_as_query(&bsq1);
1660     bson_append_start_object(&bsq1, "dblscore");
1661     bson_append_double(&bsq1, "$lte", 0.93);
1662     bson_append_finish_object(&bsq1);
1663     bson_finish(&bsq1);
1664     CU_ASSERT_FALSE_FATAL(bsq1.err);
1665
1666     bson bshints;
1667     bson_init_as_query(&bshints);
1668     bson_append_start_object(&bshints, "$orderby");
1669     bson_append_int(&bshints, "dblscore", -1); //DESC order on dblscore
1670     bson_append_finish_object(&bshints);
1671     bson_finish(&bshints);
1672     CU_ASSERT_FALSE_FATAL(bshints.err);
1673
1674     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1675     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1676
1677     uint32_t count = 0;
1678     TCXSTR *log = tcxstrnew();
1679     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1680     //fprintf(stderr, "%s", TCXSTRPTR(log));
1681
1682     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1683     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'ndblscore'"));
1684     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1685     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1686     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
1687     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 12"));
1688     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1689     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
1690     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
1691     CU_ASSERT_EQUAL(count, 2);
1692     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
1693
1694     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1695         if (i == 0) {
1696             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
1697             CU_ASSERT_FALSE(bson_compare_double(0.93, TCLISTVALPTR(q1res, i), "dblscore"));
1698         } else if (i == 1) {
1699             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
1700             CU_ASSERT_FALSE(bson_compare_double(0.333333, TCLISTVALPTR(q1res, i), "dblscore"));
1701         } else {
1702             CU_ASSERT_TRUE(false);
1703         }
1704     }
1705
1706     bson_destroy(&bsq1);
1707     bson_destroy(&bshints);
1708     tclistdel(q1res);
1709     tcxstrdel(log);
1710     ejdbquerydel(q1);
1711
1712     //LT
1713     //{'dblscore' : {'$lt' : 0.93}}
1714     bson_init_as_query(&bsq1);
1715     bson_append_start_object(&bsq1, "dblscore");
1716     bson_append_double(&bsq1, "$lt", 0.93);
1717     bson_append_finish_object(&bsq1);
1718     bson_finish(&bsq1);
1719     CU_ASSERT_FALSE_FATAL(bsq1.err);
1720
1721     bson_init_as_query(&bshints);
1722     bson_append_start_object(&bshints, "$orderby");
1723     bson_append_int(&bshints, "dblscore", -1); //DESC order on dblscore
1724     bson_append_finish_object(&bshints);
1725     bson_finish(&bshints);
1726     CU_ASSERT_FALSE_FATAL(bshints.err);
1727
1728     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1729     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1730
1731     count = 0;
1732     log = tcxstrnew();
1733     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1734     //fprintf(stderr, "%s", TCXSTRPTR(log));
1735
1736     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1737     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'ndblscore'"));
1738     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1739     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1740     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
1741     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 11"));
1742     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1743     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
1744     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 1"));
1745     CU_ASSERT_EQUAL(count, 1);
1746     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 1);
1747
1748     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1749         if (i == 0) {
1750             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
1751             CU_ASSERT_FALSE(bson_compare_double(0.333333, TCLISTVALPTR(q1res, i), "dblscore"));
1752         } else {
1753             CU_ASSERT_TRUE(false);
1754         }
1755     }
1756
1757     bson_destroy(&bsq1);
1758     bson_destroy(&bshints);
1759     tclistdel(q1res);
1760     tcxstrdel(log);
1761     ejdbquerydel(q1);
1762
1763     CU_ASSERT_TRUE(ejdbsetindex(contacts, "dblscore", JBIDXDROPALL));
1764
1765     //NOINDEX GTE
1766     bson_init_as_query(&bsq1);
1767     bson_append_start_object(&bsq1, "dblscore");
1768     bson_append_double(&bsq1, "$lte", 0.93);
1769     bson_append_finish_object(&bsq1);
1770     bson_finish(&bsq1);
1771     CU_ASSERT_FALSE_FATAL(bsq1.err);
1772
1773     bson_init_as_query(&bshints);
1774     bson_append_start_object(&bshints, "$orderby");
1775     bson_append_int(&bshints, "dblscore", -1); //DESC order on dblscore
1776     bson_append_finish_object(&bshints);
1777     bson_finish(&bshints);
1778     CU_ASSERT_FALSE_FATAL(bshints.err);
1779
1780     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1781     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1782
1783     count = 0;
1784     log = tcxstrnew();
1785     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1786     //fprintf(stderr, "%s", TCXSTRPTR(log));
1787
1788     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1789     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
1790     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1791     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1792     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
1793     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1794     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
1795     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
1796     CU_ASSERT_EQUAL(count, 2);
1797     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
1798
1799     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1800         if (i == 0) {
1801             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
1802             CU_ASSERT_FALSE(bson_compare_double(0.93, TCLISTVALPTR(q1res, i), "dblscore"));
1803         } else if (i == 1) {
1804             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
1805             CU_ASSERT_FALSE(bson_compare_double(0.333333, TCLISTVALPTR(q1res, i), "dblscore"));
1806         } else {
1807             CU_ASSERT_TRUE(false);
1808         }
1809     }
1810
1811     bson_destroy(&bsq1);
1812     bson_destroy(&bshints);
1813     tclistdel(q1res);
1814     tcxstrdel(log);
1815     ejdbquerydel(q1);
1816 }
1817
1818 void testQuery22(void) {
1819     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
1820     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
1821     CU_ASSERT_TRUE(ejdbsetindex(contacts, "address.country", JBIDXSTR));
1822
1823     //{"address.country" : {$begin : "Ru"}}
1824     bson bsq1;
1825     bson_init_as_query(&bsq1);
1826     bson_append_start_object(&bsq1, "address.country");
1827     bson_append_string(&bsq1, "$begin", "Ru");
1828     bson_append_finish_object(&bsq1);
1829     bson_finish(&bsq1);
1830     CU_ASSERT_FALSE_FATAL(bsq1.err);
1831
1832     bson bshints;
1833     bson_init_as_query(&bshints);
1834     bson_append_start_object(&bshints, "$orderby");
1835     bson_append_int(&bshints, "dblscore", -1); //DESC order on dblscore
1836     bson_append_finish_object(&bshints);
1837     bson_finish(&bshints);
1838     CU_ASSERT_FALSE_FATAL(bshints.err);
1839
1840     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1841     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1842
1843     uint32_t count = 0;
1844     TCXSTR *log = tcxstrnew();
1845     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1846     //fprintf(stderr, "%s", TCXSTRPTR(log));
1847
1848     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1849     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'saddress.country'"));
1850     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1851     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1852     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
1853     CU_ASSERT_PTR_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1854     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 2"));
1855     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 3"));
1856     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
1857     CU_ASSERT_EQUAL(count, 3);
1858     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 3);
1859
1860     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1861         if (i == 0) {
1862             CU_ASSERT_FALSE(bson_compare_string("Ivanov", TCLISTVALPTR(q1res, i), "name"));
1863             CU_ASSERT_FALSE(bson_compare_double(1.0, TCLISTVALPTR(q1res, i), "dblscore"));
1864             CU_ASSERT_FALSE(bson_compare_string("Russian Federation", TCLISTVALPTR(q1res, i), "address.country"));
1865         } else if (i == 1) {
1866             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
1867             CU_ASSERT_FALSE(bson_compare_double(0.93, TCLISTVALPTR(q1res, i), "dblscore"));
1868             CU_ASSERT_FALSE(bson_compare_string("Russian Federation", TCLISTVALPTR(q1res, i), "address.country"));
1869         } else if (i == 2) {
1870             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
1871             CU_ASSERT_FALSE(bson_compare_double(0.333333, TCLISTVALPTR(q1res, i), "dblscore"));
1872             CU_ASSERT_FALSE(bson_compare_string("Russian Federation", TCLISTVALPTR(q1res, i), "address.country"));
1873         } else {
1874             CU_ASSERT_TRUE(false);
1875         }
1876     }
1877
1878     bson_destroy(&bsq1);
1879     bson_destroy(&bshints);
1880     tclistdel(q1res);
1881     tcxstrdel(log);
1882     ejdbquerydel(q1);
1883
1884     CU_ASSERT_TRUE(ejdbsetindex(contacts, "address.country", JBIDXDROPALL));
1885
1886     bson_init_as_query(&bsq1);
1887     bson_append_start_object(&bsq1, "address.country");
1888     bson_append_string(&bsq1, "$begin", "R");
1889     bson_append_finish_object(&bsq1);
1890     bson_finish(&bsq1);
1891     CU_ASSERT_FALSE_FATAL(bsq1.err);
1892
1893     bson_init_as_query(&bshints);
1894     bson_append_start_object(&bshints, "$orderby");
1895     bson_append_int(&bshints, "dblscore", -1); //DESC order on dblscore
1896     bson_append_finish_object(&bshints);
1897     bson_finish(&bshints);
1898     CU_ASSERT_FALSE_FATAL(bshints.err);
1899
1900     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1901     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1902
1903     count = 0;
1904     log = tcxstrnew();
1905     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1906     //fprintf(stderr, "%s", TCXSTRPTR(log));
1907
1908     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1909     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
1910     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1911     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1912     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
1913     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1914     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 3"));
1915     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
1916     CU_ASSERT_EQUAL(count, 3);
1917     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 3);
1918
1919     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1920         if (i == 0) {
1921             CU_ASSERT_FALSE(bson_compare_string("Ivanov", TCLISTVALPTR(q1res, i), "name"));
1922             CU_ASSERT_FALSE(bson_compare_double(1.0, TCLISTVALPTR(q1res, i), "dblscore"));
1923             CU_ASSERT_FALSE(bson_compare_string("Russian Federation", TCLISTVALPTR(q1res, i), "address.country"));
1924         } else if (i == 1) {
1925             CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name"));
1926             CU_ASSERT_FALSE(bson_compare_double(0.93, TCLISTVALPTR(q1res, i), "dblscore"));
1927             CU_ASSERT_FALSE(bson_compare_string("Russian Federation", TCLISTVALPTR(q1res, i), "address.country"));
1928         } else if (i == 2) {
1929             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
1930             CU_ASSERT_FALSE(bson_compare_double(0.333333, TCLISTVALPTR(q1res, i), "dblscore"));
1931             CU_ASSERT_FALSE(bson_compare_string("Russian Federation", TCLISTVALPTR(q1res, i), "address.country"));
1932         } else {
1933             CU_ASSERT_TRUE(false);
1934         }
1935     }
1936
1937     bson_destroy(&bsq1);
1938     bson_destroy(&bshints);
1939     tclistdel(q1res);
1940     tcxstrdel(log);
1941     ejdbquerydel(q1);
1942 }
1943
1944 void testQuery23(void) {
1945     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
1946     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
1947
1948     bson bsq1;
1949     bson_init_as_query(&bsq1);
1950     bson_append_regex(&bsq1, "name", "(IvaNov$|John\\ TraVolta$)", "i");
1951     bson_finish(&bsq1);
1952     CU_ASSERT_FALSE_FATAL(bsq1.err);
1953
1954     bson bshints;
1955     bson_init_as_query(&bshints);
1956     bson_append_start_object(&bshints, "$orderby");
1957     bson_append_int(&bshints, "name", -1); //DESC order on dblscore
1958     bson_append_finish_object(&bshints);
1959     bson_finish(&bshints);
1960     CU_ASSERT_FALSE_FATAL(bshints.err);
1961
1962     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
1963     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
1964
1965     uint32_t count = 0;
1966     TCXSTR *log = tcxstrnew();
1967     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
1968
1969     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
1970     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
1971     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
1972     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
1973     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
1974     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
1975     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
1976     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
1977     CU_ASSERT_EQUAL(count, 2);
1978     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
1979
1980     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
1981         if (i == 0) {
1982             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
1983         } else if (i == 1) {
1984             CU_ASSERT_FALSE(bson_compare_string("Ivanov", TCLISTVALPTR(q1res, i), "name"));
1985         } else {
1986             CU_ASSERT_TRUE(false);
1987         }
1988     }
1989
1990     bson_destroy(&bsq1);
1991     bson_destroy(&bshints);
1992     tclistdel(q1res);
1993     tcxstrdel(log);
1994     ejdbquerydel(q1);
1995 }
1996
1997 void testQuery24(void) {
1998     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
1999     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
2000
2001     bson bsq1;
2002     bson_init_as_query(&bsq1);
2003     bson_finish(&bsq1);
2004     CU_ASSERT_FALSE_FATAL(bsq1.err);
2005
2006     bson bshints;
2007     bson_init_as_query(&bshints);
2008     bson_append_start_object(&bshints, "$orderby");
2009     bson_append_int(&bshints, "name", -1); //DESC order on name
2010     bson_append_finish_object(&bshints);
2011     bson_append_long(&bshints, "$skip", 1);
2012     bson_finish(&bshints);
2013     CU_ASSERT_FALSE_FATAL(bshints.err);
2014
2015     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
2016     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2017
2018     uint32_t count = 0;
2019     TCXSTR *log = tcxstrnew();
2020     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2021     //fprintf(stderr, "%s", TCXSTRPTR(log));
2022
2023     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 4294967295"));
2024     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 1"));
2025     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2026     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2027     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
2028     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 0"));
2029     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
2030     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2031     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 3"));
2032     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
2033     CU_ASSERT_EQUAL(count, 3);
2034     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 3);
2035
2036     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2037         if (i == TCLISTNUM(q1res) - 1) {
2038             CU_ASSERT_FALSE(bson_compare_string("Ivanov", TCLISTVALPTR(q1res, i), "name"));
2039         }
2040     }
2041
2042     bson_destroy(&bsq1);
2043     bson_destroy(&bshints);
2044     tclistdel(q1res);
2045     tcxstrdel(log);
2046     ejdbquerydel(q1);
2047
2048     bson_init_as_query(&bsq1);
2049     bson_finish(&bsq1);
2050     CU_ASSERT_FALSE_FATAL(bsq1.err);
2051
2052     bson_init_as_query(&bshints);
2053     bson_append_start_object(&bshints, "$orderby");
2054     bson_append_int(&bshints, "name", -1); //DESC order on name
2055     bson_append_finish_object(&bshints);
2056     bson_append_long(&bshints, "$skip", 1);
2057     bson_append_long(&bshints, "$max", 2);
2058     bson_finish(&bshints);
2059     CU_ASSERT_FALSE_FATAL(bshints.err);
2060     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
2061     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2062
2063     count = 0;
2064     log = tcxstrnew();
2065     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2066     //fprintf(stderr, "%s", TCXSTRPTR(log));
2067
2068     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 2"));
2069     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 1"));
2070     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2071     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2072     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 1"));
2073     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 0"));
2074     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: YES"));
2075     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2076     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
2077     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2"));
2078     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: YES"));
2079     CU_ASSERT_EQUAL(count, 2);
2080     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
2081
2082     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2083         if (i == TCLISTNUM(q1res) - 1) {
2084             CU_ASSERT_FALSE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
2085         }
2086     }
2087
2088     bson_destroy(&bsq1);
2089     bson_destroy(&bshints);
2090     tclistdel(q1res);
2091     tcxstrdel(log);
2092     ejdbquerydel(q1);
2093
2094     //No order specified
2095     bson_init_as_query(&bsq1);
2096     bson_finish(&bsq1);
2097     CU_ASSERT_FALSE_FATAL(bsq1.err);
2098
2099     bson_init_as_query(&bshints);
2100     bson_append_long(&bshints, "$skip", 1);
2101     bson_append_long(&bshints, "$max", 2);
2102     bson_finish(&bshints);
2103     CU_ASSERT_FALSE_FATAL(bshints.err);
2104     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
2105     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2106
2107     count = 0;
2108     log = tcxstrnew();
2109     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2110     //fprintf(stderr, "%s", TCXSTRPTR(log));
2111
2112     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 2"));
2113     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 1"));
2114     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2115     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2116     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
2117     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 0"));
2118     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
2119     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2120     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
2121     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2"));
2122     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
2123     CU_ASSERT_EQUAL(count, 2);
2124     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
2125
2126     bson_destroy(&bsq1);
2127     bson_destroy(&bshints);
2128     tclistdel(q1res);
2129     tcxstrdel(log);
2130     ejdbquerydel(q1);
2131
2132     bson_init_as_query(&bsq1);
2133     bson_finish(&bsq1);
2134     CU_ASSERT_FALSE_FATAL(bsq1.err);
2135
2136     bson_init_as_query(&bshints);
2137     bson_append_long(&bshints, "$skip", 4);
2138     bson_append_long(&bshints, "$max", 2);
2139     bson_finish(&bshints);
2140     CU_ASSERT_FALSE_FATAL(bshints.err);
2141     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
2142     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2143
2144     count = 0;
2145     log = tcxstrnew();
2146     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2147     //fprintf(stderr, "%s", TCXSTRPTR(log));
2148
2149     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 2"));
2150     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 4"));
2151     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2152     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2153     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
2154     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 0"));
2155     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
2156     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2157     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 0"));
2158     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 0"));
2159     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
2160     CU_ASSERT_EQUAL(count, 0);
2161     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 0);
2162
2163     bson_destroy(&bsq1);
2164     bson_destroy(&bshints);
2165     tclistdel(q1res);
2166     tcxstrdel(log);
2167     ejdbquerydel(q1);
2168
2169
2170     bson_init_as_query(&bsq1);
2171     bson_finish(&bsq1);
2172     CU_ASSERT_FALSE_FATAL(bsq1.err);
2173
2174     bson_init_as_query(&bshints);
2175     bson_append_start_object(&bshints, "$orderby");
2176     bson_append_int(&bshints, "name", 1); //ASC
2177     bson_append_finish_object(&bshints);
2178     bson_append_long(&bshints, "$skip", 3);
2179     bson_finish(&bshints);
2180     CU_ASSERT_FALSE_FATAL(bshints.err);
2181
2182     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
2183     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2184
2185     count = 0;
2186     log = tcxstrnew();
2187     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2188     //fprintf(stderr, "%s", TCXSTRPTR(log));
2189
2190     CU_ASSERT_EQUAL(count, 1);
2191     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 1);
2192
2193     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2194         if (i == TCLISTNUM(q1res) - 1) {
2195             CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
2196         }
2197     }
2198
2199     bson_destroy(&bsq1);
2200     bson_destroy(&bshints);
2201     tclistdel(q1res);
2202     tcxstrdel(log);
2203     ejdbquerydel(q1);
2204
2205 }
2206
2207 void testQuery25(void) { //$or
2208     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
2209     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
2210
2211     bson bsq1;
2212     bson_init_as_query(&bsq1);
2213     bson_finish(&bsq1);
2214     CU_ASSERT_FALSE_FATAL(bsq1.err);
2215
2216     bson obs[2];
2217     bson_init_as_query(&obs[0]);
2218     bson_append_string(&obs[0], "name", "Ivanov");
2219     bson_finish(&obs[0]);
2220     CU_ASSERT_FALSE_FATAL(obs[0].err);
2221
2222     bson_init_as_query(&obs[1]);
2223     bson_append_string(&obs[1], "name", "Антонов");
2224     bson_finish(&obs[1]);
2225     CU_ASSERT_FALSE_FATAL(obs[1].err);
2226
2227     EJQ *q1 = ejdbcreatequery(jb, &bsq1, obs, 2, NULL);
2228     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2229
2230     uint32_t count = 0;
2231     TCXSTR *log = tcxstrnew();
2232     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2233     //fprintf(stderr, "%s", TCXSTRPTR(log));
2234
2235     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 4294967295"));
2236     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 0"));
2237     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2238     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2239     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
2240     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 0"));
2241     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "$OR QUERIES: 2"));
2242     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
2243     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2244     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
2245     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2"));
2246     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
2247     CU_ASSERT_EQUAL(count, 2);
2248     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
2249
2250     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2251         CU_ASSERT_TRUE(
2252             !bson_compare_string("Ivanov", TCLISTVALPTR(q1res, i), "name") ||
2253             !bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
2254
2255     }
2256     bson_destroy(&bsq1);
2257     tclistdel(q1res);
2258     tcxstrdel(log);
2259     ejdbquerydel(q1);
2260
2261     for (int i = 0; i < 2; ++i) {
2262         bson_destroy(&obs[i]);
2263     }
2264 }
2265
2266 void testQuery25_2(void) { //$or alternative
2267     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
2268     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
2269
2270     bson bsq1;
2271     bson_init_as_query(&bsq1);
2272     bson_append_start_array(&bsq1, "$or");
2273
2274     bson_append_start_object(&bsq1, "0");
2275     bson_append_string(&bsq1, "name", "Ivanov");
2276     bson_append_finish_object(&bsq1);
2277
2278     bson_append_start_object(&bsq1, "1");
2279     bson_append_string(&bsq1, "name", "Антонов");
2280     bson_append_finish_object(&bsq1);
2281
2282     bson_append_finish_array(&bsq1);
2283     bson_finish(&bsq1);
2284     CU_ASSERT_FALSE_FATAL(bsq1.err);
2285
2286     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2287     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2288
2289     uint32_t count = 0;
2290     TCXSTR *log = tcxstrnew();
2291     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2292     //fprintf(stderr, "%s", TCXSTRPTR(log));
2293
2294     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 4294967295"));
2295     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 0"));
2296     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2297     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2298     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
2299     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 0"));
2300     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "$OR QUERIES: 2"));
2301     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
2302     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2303     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
2304     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2"));
2305     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
2306     CU_ASSERT_EQUAL(count, 2);
2307     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
2308
2309     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2310         CU_ASSERT_TRUE(
2311             !bson_compare_string("Ivanov", TCLISTVALPTR(q1res, i), "name") ||
2312             !bson_compare_string("Антонов", TCLISTVALPTR(q1res, i), "name"));
2313
2314     }
2315     bson_destroy(&bsq1);
2316     tclistdel(q1res);
2317     tcxstrdel(log);
2318     ejdbquerydel(q1);
2319 }
2320
2321 void testQuery26(void) { //$not $nin
2322     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
2323     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
2324
2325     //{'address.city' : {$not : 'Novosibirsk'}}
2326     bson bsq1;
2327     bson_init_as_query(&bsq1);
2328     bson_append_start_object(&bsq1, "address.city");
2329     bson_append_string(&bsq1, "$not", "Novosibirsk");
2330     bson_append_finish_object(&bsq1);
2331     bson_finish(&bsq1);
2332     CU_ASSERT_FALSE_FATAL(bsq1.err);
2333
2334     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2335     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2336
2337     uint32_t count = 0;
2338     TCXSTR *log = tcxstrnew();
2339     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2340     //fprintf(stderr, "%s", TCXSTRPTR(log));
2341
2342     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 4294967295"));
2343     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 0"));
2344     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2345     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2346     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
2347     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
2348     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "$OR QUERIES: 0"));
2349     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
2350     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2351     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
2352     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2"));
2353     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
2354     CU_ASSERT_EQUAL(count, 2);
2355     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
2356
2357     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2358         CU_ASSERT_TRUE(bson_compare_string("Novosibirsk", TCLISTVALPTR(q1res, i), "address.city"));
2359     }
2360
2361     bson_destroy(&bsq1);
2362     tclistdel(q1res);
2363     tcxstrdel(log);
2364     ejdbquerydel(q1);
2365
2366     //Double negation {'address.city' : {$not : {'$not' : 'Novosibirsk'}}}
2367     bson_init_as_query(&bsq1);
2368     bson_append_start_object(&bsq1, "address.city");
2369     bson_append_start_object(&bsq1, "$not");
2370     bson_append_string(&bsq1, "$not", "Novosibirsk");
2371     bson_append_finish_object(&bsq1);
2372     bson_append_finish_object(&bsq1);
2373     bson_finish(&bsq1);
2374     CU_ASSERT_FALSE_FATAL(bsq1.err);
2375
2376     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2377     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2378
2379     count = 0;
2380     log = tcxstrnew();
2381     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2382     //fprintf(stderr, "%s", TCXSTRPTR(log));
2383     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 4294967295"));
2384     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 0"));
2385     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2386     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2387     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
2388     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
2389     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "$OR QUERIES: 0"));
2390     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
2391     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2392     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
2393     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2"));
2394     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
2395     CU_ASSERT_EQUAL(count, 2);
2396     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
2397
2398     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2399         CU_ASSERT_TRUE(!bson_compare_string("Novosibirsk", TCLISTVALPTR(q1res, i), "address.city"));
2400     }
2401
2402     bson_destroy(&bsq1);
2403     tclistdel(q1res);
2404     tcxstrdel(log);
2405     ejdbquerydel(q1);
2406
2407     //"name" : {"$nin" : ["John Travolta", "Ivanov"]}
2408     bson_init_as_query(&bsq1);
2409     bson_append_start_object(&bsq1, "name");
2410     bson_append_start_array(&bsq1, "$nin");
2411     bson_append_string(&bsq1, "0", "John Travolta");
2412     bson_append_string(&bsq1, "1", "Ivanov");
2413     bson_append_finish_array(&bsq1);
2414     bson_append_finish_object(&bsq1);
2415     bson_finish(&bsq1);
2416     CU_ASSERT_FALSE_FATAL(bsq1.err);
2417
2418     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2419     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2420
2421     count = 0;
2422     log = tcxstrnew();
2423     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2424     //fprintf(stderr, "%s", TCXSTRPTR(log));
2425
2426     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 4294967295"));
2427     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 0"));
2428     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2429     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2430     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
2431     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
2432     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "$OR QUERIES: 0"));
2433     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
2434     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2435     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 2"));
2436     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2"));
2437     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
2438     CU_ASSERT_EQUAL(count, 2);
2439     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
2440
2441     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2442         CU_ASSERT_TRUE(bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
2443         CU_ASSERT_TRUE(bson_compare_string("Ivanov", TCLISTVALPTR(q1res, i), "name"));
2444     }
2445
2446     bson_destroy(&bsq1);
2447     tclistdel(q1res);
2448     tcxstrdel(log);
2449     ejdbquerydel(q1);
2450 }
2451
2452 void testQuery27(void) { //$exists
2453     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
2454     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
2455
2456     //{'address.room' : {$exists : true}}
2457     bson bsq1;
2458     bson_init_as_query(&bsq1);
2459     bson_append_start_object(&bsq1, "address.room");
2460     bson_append_bool(&bsq1, "$exists", true);
2461     bson_append_finish_object(&bsq1);
2462     bson_finish(&bsq1);
2463     CU_ASSERT_FALSE_FATAL(bsq1.err);
2464
2465     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2466     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2467
2468     uint32_t count = 0;
2469     TCXSTR *log = tcxstrnew();
2470     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2471     //fprintf(stderr, "%s", TCXSTRPTR(log));
2472
2473     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 4294967295"));
2474     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 0"));
2475     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2476     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2477     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
2478     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
2479     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "$OR QUERIES: 0"));
2480     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
2481     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2482     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 1"));
2483     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
2484     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
2485     CU_ASSERT_EQUAL(count, 1);
2486     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 1);
2487
2488     bson_destroy(&bsq1);
2489     tclistdel(q1res);
2490     tcxstrdel(log);
2491     ejdbquerydel(q1);
2492
2493
2494     //{'address.room' : {$exists : true}}
2495     bson_init_as_query(&bsq1);
2496     bson_append_start_object(&bsq1, "address.room");
2497     bson_append_bool(&bsq1, "$exists", false);
2498     bson_append_finish_object(&bsq1);
2499     bson_finish(&bsq1);
2500     CU_ASSERT_FALSE_FATAL(bsq1.err);
2501
2502     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2503     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2504
2505     count = 0;
2506     log = tcxstrnew();
2507     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2508     //fprintf(stderr, "%s", TCXSTRPTR(log));
2509
2510     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 4294967295"));
2511     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 0"));
2512     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2513     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2514     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
2515     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
2516     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "$OR QUERIES: 0"));
2517     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
2518     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2519     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 3"));
2520     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 3"));
2521     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
2522     CU_ASSERT_EQUAL(count, 3);
2523     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 3);
2524
2525     bson_destroy(&bsq1);
2526     tclistdel(q1res);
2527     tcxstrdel(log);
2528     ejdbquerydel(q1);
2529
2530     //{'address.room' : {$not :  {$exists : true}}} is equivalent to {'address.room' : {$exists : false}}
2531     bson_init_as_query(&bsq1);
2532     bson_append_start_object(&bsq1, "address.room");
2533     bson_append_start_object(&bsq1, "$not");
2534     bson_append_bool(&bsq1, "$exists", true);
2535     bson_append_finish_object(&bsq1);
2536     bson_append_finish_object(&bsq1);
2537     bson_finish(&bsq1);
2538     CU_ASSERT_FALSE_FATAL(bsq1.err);
2539
2540     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2541     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2542
2543     count = 0;
2544     log = tcxstrnew();
2545     q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2546     //fprintf(stderr, "%s", TCXSTRPTR(log));
2547
2548     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAX: 4294967295"));
2549     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SKIP: 0"));
2550     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "COUNT ONLY: NO"));
2551     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2552     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ORDER FIELDS: 0"));
2553     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
2554     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "$OR QUERIES: 0"));
2555     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FETCH ALL: NO"));
2556     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
2557     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 3"));
2558     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 3"));
2559     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FINAL SORTING: NO"));
2560     CU_ASSERT_EQUAL(count, 3);
2561     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 3);
2562
2563     bson_destroy(&bsq1);
2564     tclistdel(q1res);
2565     tcxstrdel(log);
2566     ejdbquerydel(q1);
2567 }
2568
2569 void testQuery28(void) { // $gte: 64 bit number
2570         // TEST for #127: int64_t large numbers
2571         int64_t int64value = 0xFFFFFFFFFF02LL;
2572     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
2573     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
2574
2575     bson bsq1;
2576     bson_init_as_query(&bsq1);
2577         bson_append_start_object(&bsq1, "longscore");
2578     bson_append_long(&bsq1, "$gte", int64value);
2579     bson_append_finish_object(&bsq1);
2580     bson_finish(&bsq1);
2581     CU_ASSERT_FALSE_FATAL(bsq1.err);
2582
2583     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2584     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2585
2586     uint32_t count = 0;
2587     TCXSTR *log = tcxstrnew();
2588     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2589     //fprintf(stderr, "%s", TCXSTRPTR(log));
2590
2591     CU_ASSERT_EQUAL(count, 1);
2592     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 1);
2593
2594     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2595         if (i == 0) {
2596             CU_ASSERT_FALSE(bson_compare_string("444-123-333", TCLISTVALPTR(q1res, i), "phone"));
2597             CU_ASSERT_FALSE(bson_compare_long(int64value, TCLISTVALPTR(q1res, i), "longscore"));
2598         } else {
2599             CU_ASSERT_TRUE(false);
2600         }
2601     }
2602
2603     bson_destroy(&bsq1);
2604     tclistdel(q1res);
2605     tcxstrdel(log);
2606     ejdbquerydel(q1);
2607 }
2608
2609 void testQuery29(void) { 
2610         // #129: Test $begin Query with Symbols
2611     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
2612     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
2613
2614     bson bsq1;
2615     bson_init_as_query(&bsq1);
2616     bson_append_start_object(&bsq1, "symbol");
2617     bson_append_string(&bsq1, "$begin", "app");
2618     bson_append_finish_object(&bsq1);
2619     bson_finish(&bsq1);
2620     CU_ASSERT_FALSE_FATAL(bsq1.err);
2621
2622     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2623     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2624
2625     uint32_t count = 0;
2626     TCXSTR *log = tcxstrnew();
2627     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2628     //fprintf(stderr, "%s", TCXSTRPTR(log));
2629
2630     CU_ASSERT_EQUAL(count, 2);  // should match symbol_info: apple, application
2631     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
2632
2633     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2634         if (i == 0) CU_ASSERT_FALSE(bson_compare_string("apple", TCLISTVALPTR(q1res, i), "symbol"));
2635         if (i == 1) CU_ASSERT_FALSE(bson_compare_string("application", TCLISTVALPTR(q1res, i), "symbol"));
2636     }
2637
2638     bson_destroy(&bsq1);
2639     tclistdel(q1res);
2640     tcxstrdel(log);
2641     ejdbquerydel(q1);
2642 }
2643
2644 void testQuery30(void) { 
2645         // #129: Test equal with Symbols
2646     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
2647     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
2648
2649     bson bsq1;
2650     bson_init_as_query(&bsq1);
2651     bson_append_string(&bsq1, "symbol", "bison");
2652     bson_finish(&bsq1);
2653     CU_ASSERT_FALSE_FATAL(bsq1.err);
2654
2655     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2656     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2657
2658     uint32_t count = 0;
2659     TCXSTR *log = tcxstrnew();
2660     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2661     //fprintf(stderr, "%s", TCXSTRPTR(log));
2662
2663     CU_ASSERT_EQUAL(count, 1);  // should match symbol_info: bison
2664     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 1);
2665
2666     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2667         if (i == 0) CU_ASSERT_FALSE(bson_compare_string("bison", TCLISTVALPTR(q1res, i), "symbol"));
2668     }
2669
2670     bson_destroy(&bsq1);
2671     tclistdel(q1res);
2672     tcxstrdel(log);
2673     ejdbquerydel(q1);
2674 }
2675
2676 void testQuery31(void) { 
2677         // #129: Test $in array Query with Symbols
2678     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
2679     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
2680
2681     bson bsq1;
2682     bson_init_as_query(&bsq1);
2683     bson_append_start_object(&bsq1, "symbol");
2684     bson_append_start_array(&bsq1, "$in");
2685     bson_append_string(&bsq1, "0", "apple");
2686     bson_append_string(&bsq1, "1", "bison");
2687     bson_append_finish_array(&bsq1);
2688     bson_append_finish_object(&bsq1);
2689     bson_finish(&bsq1);
2690     CU_ASSERT_FALSE_FATAL(bsq1.err);
2691
2692     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2693     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2694
2695     uint32_t count = 0;
2696     TCXSTR *log = tcxstrnew();
2697     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2698     //fprintf(stderr, "%s", TCXSTRPTR(log));
2699
2700     CU_ASSERT_EQUAL(count, 2);  // should match symbol_info: apple, bison
2701     CU_ASSERT_TRUE(TCLISTNUM(q1res) == 2);
2702
2703     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2704         if (i == 0) CU_ASSERT_FALSE(bson_compare_string("apple", TCLISTVALPTR(q1res, i), "symbol"));
2705         if (i == 1) CU_ASSERT_FALSE(bson_compare_string("bison", TCLISTVALPTR(q1res, i), "symbol"));
2706     }
2707
2708     bson_destroy(&bsq1);
2709     tclistdel(q1res);
2710     tcxstrdel(log);
2711     ejdbquerydel(q1);
2712 }
2713
2714 void testOIDSMatching(void) { //OID matching
2715     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
2716     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
2717
2718     bson_type bt;
2719     bson bsq1;
2720     bson_init_as_query(&bsq1);
2721     bson_finish(&bsq1);
2722     CU_ASSERT_FALSE_FATAL(bsq1.err);
2723
2724     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2725     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2726
2727     uint32_t count = 0;
2728     TCXSTR *log = tcxstrnew();
2729     TCLIST *q1res = ejdbqryexecute(contacts, q1, &count, 0, log);
2730     CU_ASSERT_TRUE(count > 0);
2731     //fprintf(stderr, "%s", TCXSTRPTR(log));
2732
2733     for (int i = 0; i < TCLISTNUM(q1res); ++i) { //first
2734         char soid[25];
2735         bson_oid_t *oid;
2736         void *bsdata = TCLISTVALPTR(q1res, i);
2737         bson_iterator it2;
2738         bt = bson_find_from_buffer(&it2, bsdata, JDBIDKEYNAME);
2739         CU_ASSERT_EQUAL_FATAL(bt, BSON_OID);
2740         oid = bson_iterator_oid(&it2);
2741         bson_oid_to_string(oid, soid);
2742         //fprintf(stderr, "\nOID: %s", soid);
2743
2744         //OID in string form maching
2745         bson bsq2;
2746         bson_init_as_query(&bsq2);
2747
2748         if (i % 2 == 0) {
2749             bson_append_string(&bsq2, JDBIDKEYNAME, soid);
2750         } else {
2751             bson_append_oid(&bsq2, JDBIDKEYNAME, oid);
2752         }
2753
2754         bson_finish(&bsq2);
2755         CU_ASSERT_FALSE_FATAL(bsq2.err);
2756
2757         TCXSTR *log2 = tcxstrnew();
2758         EJQ *q2 = ejdbcreatequery(jb, &bsq2, NULL, 0, NULL);
2759         TCLIST *q2res = ejdbqryexecute(contacts, q2, &count, 0, log2);
2760         CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log2), "PRIMARY KEY MATCHING:"));
2761         CU_ASSERT_EQUAL(count, 1);
2762
2763         tcxstrdel(log2);
2764         ejdbquerydel(q2);
2765         tclistdel(q2res);
2766         bson_destroy(&bsq2);
2767     }
2768
2769     bson_destroy(&bsq1);
2770     tclistdel(q1res);
2771     tcxstrdel(log);
2772     ejdbquerydel(q1);
2773 }
2774
2775 void testEmptyFieldIndex(void) {
2776     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
2777     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
2778     CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXDROPALL));
2779
2780     bson a1;
2781     bson_oid_t oid;
2782     bson_init(&a1);
2783     bson_append_string(&a1, "name", ""); //Empty but indexed field
2784     CU_ASSERT_FALSE_FATAL(a1.err);
2785     bson_finish(&a1);
2786     CU_ASSERT_TRUE(ejdbsavebson(coll, &a1, &oid));
2787     bson_destroy(&a1);
2788     CU_ASSERT_EQUAL(ejdbecode(coll->jb), 0);
2789
2790     CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXISTR)); //Ignore case string index
2791     CU_ASSERT_EQUAL(ejdbecode(coll->jb), 0);
2792
2793     bson_init(&a1);
2794     bson_append_string(&a1, "name", ""); //Empty but indexed field
2795     CU_ASSERT_FALSE_FATAL(a1.err);
2796     bson_finish(&a1);
2797     CU_ASSERT_TRUE(ejdbsavebson(coll, &a1, &oid));
2798     bson_destroy(&a1);
2799     CU_ASSERT_EQUAL(ejdbecode(coll->jb), 0);
2800 }
2801
2802 void testICaseIndex(void) {
2803     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
2804     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
2805     CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXISTR)); //Ignore case string index
2806
2807     //Save one more record
2808     bson a1;
2809     bson_oid_t oid;
2810     bson_init(&a1);
2811     bson_append_string(&a1, "name", "HeLlo WorlD"); //#1
2812     CU_ASSERT_FALSE_FATAL(a1.err);
2813     bson_finish(&a1);
2814     CU_ASSERT_TRUE(ejdbsavebson(coll, &a1, &oid));
2815     bson_destroy(&a1);
2816     CU_ASSERT_EQUAL(ejdbecode(coll->jb), 0);
2817
2818     bson_init(&a1);
2819     bson_append_string(&a1, "name", "THéÂtRE — театр"); //#2
2820     CU_ASSERT_FALSE_FATAL(a1.err);
2821     bson_finish(&a1);
2822     CU_ASSERT_TRUE(ejdbsavebson(coll, &a1, &oid));
2823     bson_destroy(&a1);
2824     CU_ASSERT_EQUAL(ejdbecode(coll->jb), 0);
2825
2826
2827     //Case insensitive query using index
2828     // {"name" : {"$icase" : "HellO woRLD"}}
2829     bson bsq1;
2830     bson_init_as_query(&bsq1);
2831     bson_append_start_object(&bsq1, "name");
2832     bson_append_string(&bsq1, "$icase", "HellO woRLD");
2833     bson_append_finish_object(&bsq1);
2834     bson_finish(&bsq1);
2835     CU_ASSERT_FALSE_FATAL(bsq1.err);
2836
2837     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2838     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2839
2840     uint32_t count = 0;
2841     TCXSTR *log = tcxstrnew();
2842     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
2843     CU_ASSERT_TRUE(count == 1);
2844     //fprintf(stderr, "%s", TCXSTRPTR(log));
2845     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'iname'"));
2846     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
2847
2848     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2849         CU_ASSERT_TRUE(!bson_compare_string("HeLlo WorlD", TCLISTVALPTR(q1res, i), "name"));
2850     }
2851
2852     bson_destroy(&bsq1);
2853     tclistdel(q1res);
2854     tcxstrdel(log);
2855     ejdbquerydel(q1);
2856
2857     //OK then drop icase index
2858     CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXISTR | JBIDXDROP)); //Ignore case string index
2859
2860     //Same query:
2861     //{"name" : {"$icase" : {$in : ["théâtre - театр", "hello world"]}}}
2862     bson_init_as_query(&bsq1);
2863     bson_append_start_object(&bsq1, "name");
2864     bson_append_start_object(&bsq1, "$icase");
2865     bson_append_start_array(&bsq1, "$in");
2866     bson_append_string(&bsq1, "0", "théâtre - театр");
2867     bson_append_string(&bsq1, "1", "hello world");
2868     bson_append_finish_array(&bsq1);
2869     bson_append_finish_object(&bsq1);
2870     bson_append_finish_object(&bsq1);
2871     bson_finish(&bsq1);
2872     CU_ASSERT_FALSE_FATAL(bsq1.err);
2873
2874     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2875     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2876
2877     count = 0;
2878     log = tcxstrnew();
2879     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
2880     //fprintf(stderr, "%s", TCXSTRPTR(log));
2881     CU_ASSERT_TRUE(count == 2);
2882     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
2883     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2"));
2884
2885     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
2886         CU_ASSERT_TRUE(
2887             !bson_compare_string("HeLlo WorlD", TCLISTVALPTR(q1res, i), "name") ||
2888             !bson_compare_string("THéÂtRE — театр", TCLISTVALPTR(q1res, i), "name")
2889         );
2890     }
2891
2892     bson_destroy(&bsq1);
2893     tclistdel(q1res);
2894     tcxstrdel(log);
2895     ejdbquerydel(q1);
2896 }
2897
2898 void testTicket7(void) { //https://github.com/Softmotions/ejdb/issues/7
2899     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
2900     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
2901
2902     char xoid[25];
2903     bson_iterator it;
2904     bson_type bt;
2905     bson bsq1;
2906     bson_init_as_query(&bsq1);
2907     bson_finish(&bsq1);
2908     CU_ASSERT_FALSE_FATAL(bsq1.err);
2909
2910     const int onum = 3; //number of saved bsons
2911     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
2912     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
2913     uint32_t count = 0;
2914     TCXSTR *log = tcxstrnew();
2915     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
2916     //fprintf(stderr, "%s", TCXSTRPTR(log));
2917     CU_ASSERT_TRUE_FATAL(count >= onum);
2918
2919     for (int i = 0; i < TCLISTNUM(q1res) && i < onum; ++i) {
2920         void *bsdata = TCLISTVALPTR(q1res, i);
2921         CU_ASSERT_PTR_NOT_NULL_FATAL(bsdata);
2922     }
2923     //Now perform $in qry
2924     //{_id : {$in : ["oid1", "oid2", "oid3"]}}
2925     bson bsq2;
2926     bson_init_as_query(&bsq2);
2927     bson_append_start_object(&bsq2, "_id");
2928     bson_append_start_array(&bsq2, "$in");
2929     for (int i = 0; i < onum; ++i) {
2930         char ibuf[10];
2931         snprintf(ibuf, 10, "%d", i);
2932         bson_oid_t *oid = NULL;
2933         bt = bson_find_from_buffer(&it, TCLISTVALPTR(q1res, i), "_id");
2934         CU_ASSERT_TRUE_FATAL(bt == BSON_OID);
2935         oid = bson_iterator_oid(&it);
2936         CU_ASSERT_PTR_NOT_NULL_FATAL(oid);
2937         bson_oid_to_string(oid, xoid);
2938         //fprintf(stderr, "\ni=%s oid=%s", ibuf, xoid);
2939         if (i % 2 == 0) {
2940             bson_append_oid(&bsq2, ibuf, oid);
2941         } else {
2942             bson_append_string(&bsq2, ibuf, xoid);
2943         }
2944     }
2945     bson_append_finish_array(&bsq2);
2946     bson_append_finish_object(&bsq2);
2947     bson_finish(&bsq2);
2948     CU_ASSERT_FALSE_FATAL(bsq2.err);
2949
2950     EJQ *q2 = ejdbcreatequery(jb, &bsq2, NULL, 0, NULL);
2951     CU_ASSERT_PTR_NOT_NULL_FATAL(q2);
2952     uint32_t count2 = 0;
2953     TCXSTR *log2 = tcxstrnew();
2954     TCLIST *q2res = ejdbqryexecute(coll, q2, &count2, 0, log2);
2955     //fprintf(stderr, "\n%s", TCXSTRPTR(log2));
2956     CU_ASSERT_TRUE(count2 == 3);
2957     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log2), "MAIN IDX: 'NONE'"));
2958     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log2), "PRIMARY KEY MATCHING: TRUE"));
2959     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log2), "RS COUNT: 3"));
2960
2961     for (int i = 0; i < TCLISTNUM(q2res); ++i) {
2962         bson_oid_t *oid1 = NULL;
2963         bt = bson_find_from_buffer(&it, TCLISTVALPTR(q2res, i), "_id");
2964         CU_ASSERT_TRUE_FATAL(bt == BSON_OID);
2965         oid1 = bson_iterator_oid(&it);
2966         bool matched = false;
2967         for (int j = 0; j < TCLISTNUM(q1res); ++j) {
2968             bson_oid_t *oid2 = NULL;
2969             bt = bson_find_from_buffer(&it, TCLISTVALPTR(q1res, j), "_id");
2970             CU_ASSERT_TRUE_FATAL(bt == BSON_OID);
2971             oid2 = bson_iterator_oid(&it);
2972             if (!memcmp(oid1, oid2, sizeof (bson_oid_t))) {
2973                 matched = true;
2974                 void *ptr = tclistremove2(q1res, j);
2975                 if (ptr) {
2976                     TCFREE(ptr);
2977                 }
2978                 break;
2979             }
2980         }
2981         CU_ASSERT_TRUE(matched);
2982     }
2983
2984     bson_destroy(&bsq1);
2985     tclistdel(q1res);
2986     tcxstrdel(log);
2987     ejdbquerydel(q1);
2988
2989     bson_destroy(&bsq2);
2990     tclistdel(q2res);
2991     tcxstrdel(log2);
2992     ejdbquerydel(q2);
2993 }
2994
2995 void testTicket8(void) { //https://github.com/Softmotions/ejdb/issues/8
2996     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
2997     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
2998
2999     bson bsq1;
3000     bson_init_as_query(&bsq1);
3001     bson_finish(&bsq1);
3002     CU_ASSERT_FALSE_FATAL(bsq1.err);
3003
3004     bson bshits1;
3005     bson_init_as_query(&bshits1);
3006     bson_append_start_object(&bshits1, "$fields");
3007     bson_append_int(&bshits1, "_id", 1);
3008     bson_append_int(&bshits1, "phone", 1);
3009     bson_append_int(&bshits1, "address.city", 1);
3010     bson_append_int(&bshits1, "labels", 1);
3011     bson_append_finish_object(&bshits1);
3012     bson_finish(&bshits1);
3013     CU_ASSERT_FALSE_FATAL(bshits1.err);
3014
3015
3016     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshits1);
3017     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3018     uint32_t count = 0;
3019     TCXSTR *log = tcxstrnew();
3020     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3021     //fprintf(stderr, "%s", TCXSTRPTR(log));
3022
3023     //    for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3024     //        void *bsdata = TCLISTVALPTR(q1res, i);
3025     //        bson_print_raw(bsdata, 0);
3026     //    }
3027
3028     bson_type bt;
3029     bson_iterator it;
3030     int ccount = 0;
3031     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3032         void *bsdata = TCLISTVALPTR(q1res, i);
3033         CU_ASSERT_PTR_NOT_NULL_FATAL(bsdata);
3034
3035         if (!bson_compare_string("333-222-333", TCLISTVALPTR(q1res, i), "phone")) {
3036             ++ccount;
3037             bson_iterator_from_buffer(&it, bsdata);
3038             bt = bson_find_fieldpath_value("_id", &it);
3039             CU_ASSERT_TRUE(bt == BSON_OID);
3040             bson_iterator_from_buffer(&it, bsdata);
3041             bt = bson_find_fieldpath_value("address", &it);
3042             CU_ASSERT_TRUE(bt == BSON_OBJECT);
3043             bson_iterator_from_buffer(&it, bsdata);
3044             bt = bson_find_fieldpath_value("address.city", &it);
3045             CU_ASSERT_TRUE(bt == BSON_STRING);
3046             CU_ASSERT_FALSE(strcmp("Novosibirsk", bson_iterator_string(&it)));
3047             bson_iterator_from_buffer(&it, bsdata);
3048             bt = bson_find_fieldpath_value("address.zip", &it);
3049             CU_ASSERT_TRUE(bt == BSON_EOO);
3050             bson_iterator_from_buffer(&it, bsdata);
3051             bt = bson_find_fieldpath_value("age", &it);
3052             CU_ASSERT_TRUE(bt == BSON_EOO);
3053             bson_iterator_from_buffer(&it, bsdata);
3054             bt = bson_find_fieldpath_value("name", &it);
3055             CU_ASSERT_TRUE(bt == BSON_EOO);
3056             bson_iterator_from_buffer(&it, bsdata);
3057             bt = bson_find_fieldpath_value("labels", &it);
3058             CU_ASSERT_TRUE(bt == BSON_EOO);
3059         } else if (!bson_compare_string("444-123-333", TCLISTVALPTR(q1res, i), "phone")) {
3060             ++ccount;
3061             bson_iterator_from_buffer(&it, bsdata);
3062             bt = bson_find_fieldpath_value("_id", &it);
3063             CU_ASSERT_TRUE(bt == BSON_OID);
3064             bson_iterator_from_buffer(&it, bsdata);
3065             bt = bson_find_fieldpath_value("address", &it);
3066             CU_ASSERT_TRUE(bt == BSON_OBJECT);
3067             bson_iterator_from_buffer(&it, bsdata);
3068             bt = bson_find_fieldpath_value("address.city", &it);
3069             CU_ASSERT_TRUE(bt == BSON_STRING);
3070             CU_ASSERT_FALSE(strcmp("Novosibirsk", bson_iterator_string(&it)));
3071             bson_iterator_from_buffer(&it, bsdata);
3072             bt = bson_find_fieldpath_value("address.zip", &it);
3073             CU_ASSERT_TRUE(bt == BSON_EOO);
3074             bson_iterator_from_buffer(&it, bsdata);
3075             bt = bson_find_fieldpath_value("age", &it);
3076             CU_ASSERT_TRUE(bt == BSON_EOO);
3077             bson_iterator_from_buffer(&it, bsdata);
3078             bt = bson_find_fieldpath_value("name", &it);
3079             CU_ASSERT_TRUE(bt == BSON_EOO);
3080             bson_iterator_from_buffer(&it, bsdata);
3081             bt = bson_find_fieldpath_value("labels", &it);
3082             CU_ASSERT_TRUE(bt == BSON_ARRAY);
3083             CU_ASSERT_FALSE(bson_compare_string("red", bsdata, "labels.0"));
3084             CU_ASSERT_FALSE(bson_compare_string("green", bsdata, "labels.1"));
3085             CU_ASSERT_FALSE(bson_compare_string("with gap, label", bsdata, "labels.2"));
3086         }
3087     }
3088     CU_ASSERT_TRUE(ccount == 2);
3089     bson_destroy(&bshits1);
3090     tclistdel(q1res);
3091     tcxstrclear(log);
3092     ejdbquerydel(q1);
3093
3094     //NEXT Q
3095     bson_init_as_query(&bshits1);
3096     bson_append_start_object(&bshits1, "$fields");
3097     bson_append_int(&bshits1, "phone", 1);
3098     bson_append_int(&bshits1, "address.city", 0);
3099     bson_append_int(&bshits1, "labels", 0);
3100     bson_append_finish_object(&bshits1);
3101     bson_finish(&bshits1);
3102     CU_ASSERT_FALSE_FATAL(bshits1.err);
3103
3104     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshits1);
3105     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3106     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3107     CU_ASSERT_PTR_NULL_FATAL(q1res);
3108     CU_ASSERT_EQUAL(ejdbecode(jb), JBEQINCEXCL);
3109     ejdbquerydel(q1);
3110     tcxstrclear(log);
3111     bson_destroy(&bshits1);
3112     bson_destroy(&bsq1);
3113
3114     //NEXT Q
3115     bson_init_as_query(&bsq1);
3116     //bson_append_string(&bsq1, "name", "Антонов");
3117     bson_append_start_object(&bsq1, "address");
3118     bson_append_bool(&bsq1, "$exists", true);
3119     bson_append_finish_object(&bsq1);
3120     bson_finish(&bsq1);
3121     CU_ASSERT_FALSE_FATAL(bsq1.err);
3122
3123     bson_init_as_query(&bshits1);
3124     bson_append_start_object(&bshits1, "$fields");
3125     bson_append_int(&bshits1, "phone", 0);
3126     bson_append_int(&bshits1, "address.city", 0);
3127     bson_append_int(&bshits1, "address.room", 0);
3128     bson_append_int(&bshits1, "labels", 0);
3129     bson_append_int(&bshits1, "complexarr.0", 0);
3130     bson_append_int(&bshits1, "_id", 0);
3131     bson_append_finish_object(&bshits1);
3132     bson_finish(&bshits1);
3133     CU_ASSERT_FALSE_FATAL(bshits1.err);
3134     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshits1);
3135     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3136     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3137     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
3138     CU_ASSERT_EQUAL(ejdbecode(jb), TCESUCCESS);
3139
3140     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3141         void *bsdata = TCLISTVALPTR(q1res, i);
3142         bson_type bt;
3143         bson_iterator_from_buffer(&it, bsdata);
3144         bt = bson_find_fieldpath_value("_id", &it);
3145         CU_ASSERT_TRUE(bt == BSON_EOO);
3146         bson_iterator_from_buffer(&it, bsdata);
3147         bt = bson_find_fieldpath_value("phone", &it);
3148         CU_ASSERT_TRUE(bt == BSON_EOO);
3149         bson_iterator_from_buffer(&it, bsdata);
3150         bt = bson_find_fieldpath_value("address", &it);
3151         CU_ASSERT_TRUE(bt == BSON_OBJECT);
3152         bson_iterator_from_buffer(&it, bsdata);
3153         //bt = bson_find_fieldpath_value("address.country", &it);
3154         //CU_ASSERT_TRUE(bt == BSON_STRING);
3155         bson_iterator_from_buffer(&it, bsdata);
3156         bt = bson_find_fieldpath_value("address.city", &it);
3157         CU_ASSERT_TRUE(bt == BSON_EOO);
3158         bson_iterator_from_buffer(&it, bsdata);
3159         bt = bson_find_fieldpath_value("address.room", &it);
3160         CU_ASSERT_TRUE(bt == BSON_EOO);
3161         bson_iterator_from_buffer(&it, bsdata);
3162         bt = bson_find_fieldpath_value("labels", &it);
3163         CU_ASSERT_TRUE(bt == BSON_EOO);
3164         //bson_print_raw(bsdata, 0);
3165     }
3166
3167     bson_destroy(&bsq1);
3168     bson_destroy(&bshits1);
3169     tclistdel(q1res);
3170     tcxstrdel(log);
3171     ejdbquerydel(q1);
3172
3173 }
3174
3175 void testUpdate1(void) { //https://github.com/Softmotions/ejdb/issues/9
3176     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
3177     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
3178
3179     bson_iterator it;
3180
3181     //q: {name : 'John Travolta', $set : {'labels' : ['black', 'blue'], 'age' : 58}}
3182     bson bsq1;
3183     bson_init_as_query(&bsq1);
3184     bson_append_string(&bsq1, "name", "John Travolta");
3185     bson_append_start_object(&bsq1, "$set");
3186     bson_append_start_array(&bsq1, "labels");
3187     bson_append_string(&bsq1, "0", "black");
3188     bson_append_string(&bsq1, "1", "blue");
3189     bson_append_finish_array(&bsq1);
3190     bson_append_int(&bsq1, "age", 58);
3191     bson_append_finish_object(&bsq1);
3192     bson_finish(&bsq1);
3193     CU_ASSERT_FALSE_FATAL(bsq1.err);
3194
3195     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3196     CU_ASSERT_TRUE(ejdbecode(jb) == 0);
3197     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3198     uint32_t count = 0;
3199     TCXSTR *log = tcxstrnew();
3200     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3201     CU_ASSERT_TRUE(ejdbecode(jb) == 0);
3202     //fprintf(stderr, "%s", TCXSTRPTR(log));
3203     CU_ASSERT_EQUAL(1, count);
3204     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: YES"));
3205
3206     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3207         CU_ASSERT_TRUE(!bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
3208         bson_iterator_from_buffer(&it, TCLISTVALPTR(q1res, i));
3209         CU_ASSERT_TRUE(bson_find_from_buffer(&it, TCLISTVALPTR(q1res, i), "age") == BSON_EOO);
3210     }
3211
3212     bson_destroy(&bsq1);
3213     tclistdel(q1res);
3214     tcxstrdel(log);
3215     ejdbquerydel(q1);
3216
3217     //q2: {name : 'John Travolta', age: 58}
3218     bson_init_as_query(&bsq1);
3219     bson_append_string(&bsq1, "name", "John Travolta");
3220     bson_append_int(&bsq1, "age", 58);
3221     bson_append_finish_object(&bsq1);
3222     bson_finish(&bsq1);
3223     CU_ASSERT_FALSE_FATAL(bsq1.err);
3224
3225     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3226     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3227     count = 0;
3228     log = tcxstrnew();
3229     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3230     //fprintf(stderr, "%s", TCXSTRPTR(log));
3231     CU_ASSERT_EQUAL(1, TCLISTNUM(q1res));
3232     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: NO"));
3233
3234     int age = 58;
3235     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3236         CU_ASSERT_FALSE(bson_compare_long(age, TCLISTVALPTR(q1res, i), "age"));
3237         CU_ASSERT_FALSE(bson_compare_string("black", TCLISTVALPTR(q1res, i), "labels.0"));
3238         CU_ASSERT_FALSE(bson_compare_string("blue", TCLISTVALPTR(q1res, i), "labels.1"));
3239     }
3240     bson_destroy(&bsq1);
3241     tclistdel(q1res);
3242     tcxstrdel(log);
3243     ejdbquerydel(q1);
3244
3245     //q3: {name : 'John Travolta', '$inc' : {'age' : -1}}
3246     bson_init_as_query(&bsq1);
3247     bson_append_string(&bsq1, "name", "John Travolta");
3248     bson_append_start_object(&bsq1, "$inc");
3249     bson_append_int(&bsq1, "age", -1);
3250     bson_append_finish_object(&bsq1);
3251     bson_append_finish_object(&bsq1);
3252     bson_finish(&bsq1);
3253     CU_ASSERT_FALSE_FATAL(bsq1.err);
3254
3255     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3256     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3257     count = 0;
3258     log = tcxstrnew();
3259     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3260     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: YES"));
3261     bson_destroy(&bsq1);
3262     tclistdel(q1res);
3263     tcxstrdel(log);
3264     ejdbquerydel(q1);
3265
3266
3267     //q4: {name : 'John Travolta', age: 57}
3268     bson_init_as_query(&bsq1);
3269     bson_append_string(&bsq1, "name", "John Travolta");
3270     bson_append_int(&bsq1, "age", 57);
3271     bson_append_finish_object(&bsq1);
3272     bson_finish(&bsq1);
3273     CU_ASSERT_FALSE_FATAL(bsq1.err);
3274
3275     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3276     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3277     count = 0;
3278     log = tcxstrnew();
3279     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3280     //fprintf(stderr, "%s", TCXSTRPTR(log));
3281     CU_ASSERT_EQUAL(1, TCLISTNUM(q1res));
3282     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: NO"));
3283
3284     --age;
3285     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3286         CU_ASSERT_FALSE(bson_compare_long(age, TCLISTVALPTR(q1res, i), "age"));
3287     }
3288
3289     bson_destroy(&bsq1);
3290     tclistdel(q1res);
3291     tcxstrdel(log);
3292     ejdbquerydel(q1);
3293         
3294 }
3295
3296 void testUpdate2(void) { //https://github.com/Softmotions/ejdb/issues/9
3297     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
3298     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
3299     CU_ASSERT_TRUE(ejdbsetindex(coll, "age", JBIDXNUM));
3300
3301     //q: {name : 'John Travolta', '$inc' : {'age' : 1}}
3302     bson bsq1;
3303     bson_init_as_query(&bsq1);
3304     bson_append_string(&bsq1, "name", "John Travolta");
3305     bson_append_start_object(&bsq1, "$inc");
3306     bson_append_int(&bsq1, "age", 1);
3307     bson_append_finish_object(&bsq1);
3308     bson_append_start_object(&bsq1, "$set");
3309     bson_append_bool(&bsq1, "visited", true);
3310     bson_append_finish_object(&bsq1);
3311     bson_append_finish_object(&bsq1);
3312     bson_finish(&bsq1);
3313     CU_ASSERT_FALSE_FATAL(bsq1.err);
3314
3315     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3316     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3317     uint32_t count = 0;
3318     TCXSTR *log = tcxstrnew();
3319     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3320     //fprintf(stderr, "%s", TCXSTRPTR(log));
3321
3322     bson_destroy(&bsq1);
3323     tclistdel(q1res);
3324     tcxstrdel(log);
3325     ejdbquerydel(q1);
3326
3327     bson_init_as_query(&bsq1);
3328     bson_append_string(&bsq1, "name", "John Travolta");
3329     bson_append_int(&bsq1, "age", 58);
3330     bson_append_finish_object(&bsq1);
3331     bson_finish(&bsq1);
3332     CU_ASSERT_FALSE_FATAL(bsq1.err);
3333
3334     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3335     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3336     count = 0;
3337     log = tcxstrnew();
3338     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3339     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'nage'"));
3340     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 8"));
3341     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
3342     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3343         CU_ASSERT_FALSE(bson_compare_bool(true, TCLISTVALPTR(q1res, i), "visited"));
3344     }
3345
3346     bson_destroy(&bsq1);
3347     tclistdel(q1res);
3348     tcxstrdel(log);
3349     ejdbquerydel(q1);
3350
3351 }
3352
3353 void testUpdate3(void) {
3354     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
3355     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
3356
3357         //q5: {name: 'John Travolta', $rename: { "name" : "fullName"}}
3358     bson bsq1;
3359     bson_iterator it;
3360
3361         bson_init_as_query(&bsq1);
3362     bson_append_string(&bsq1, "name", "John Travolta");
3363     bson_append_start_object(&bsq1, "$rename");
3364     bson_append_string(&bsq1, "name", "fullName");
3365     //bson_append_finish_object(&bsq1);
3366     bson_append_finish_object(&bsq1);
3367     bson_finish(&bsq1);
3368     CU_ASSERT_FALSE_FATAL(bsq1.err);
3369
3370     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3371     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3372     uint32_t count = 0;
3373     TCXSTR *log = tcxstrnew();
3374     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3375
3376     //fprintf(stderr, "%s", TCXSTRPTR(log));
3377     CU_ASSERT_EQUAL(1, count);
3378     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: YES"));
3379
3380
3381     bson_destroy(&bsq1);
3382     tclistdel(q1res);
3383     tcxstrdel(log);
3384     ejdbquerydel(q1);
3385
3386     bson_init_as_query(&bsq1);
3387     bson_append_string(&bsq1, "fullName", "John Travolta");
3388     bson_append_finish_object(&bsq1);
3389     bson_finish(&bsq1);
3390     CU_ASSERT_FALSE_FATAL(bsq1.err);
3391
3392     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3393     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3394     count = 0;
3395     log = tcxstrnew();
3396     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3397
3398     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3399         CU_ASSERT_TRUE(!bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "fullName"));
3400         bson_iterator_from_buffer(&it, TCLISTVALPTR(q1res, i));
3401         CU_ASSERT_TRUE(bson_find_from_buffer(&it, TCLISTVALPTR(q1res, i), "name") == BSON_EOO);
3402     }
3403
3404     bson_destroy(&bsq1);
3405     tclistdel(q1res);
3406     tcxstrdel(log);
3407     ejdbquerydel(q1);
3408         
3409         //q6: {name: 'John Travolta', $rename: { "fullName" : "name"}}
3410         bson_init_as_query(&bsq1);
3411     bson_append_string(&bsq1, "fullName", "John Travolta");
3412     bson_append_start_object(&bsq1, "$rename");
3413     bson_append_string(&bsq1, "fullName", "name");
3414     //bson_append_finish_object(&bsq1);
3415     bson_append_finish_object(&bsq1);
3416     bson_finish(&bsq1);
3417     CU_ASSERT_FALSE_FATAL(bsq1.err);
3418
3419     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3420     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3421     count = 0;
3422     log = tcxstrnew();
3423     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3424
3425     //fprintf(stderr, "%s", TCXSTRPTR(log));
3426     CU_ASSERT_EQUAL(1, count);
3427     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: YES"));
3428
3429     bson_destroy(&bsq1);
3430     tclistdel(q1res);
3431     tcxstrdel(log);
3432     ejdbquerydel(q1);
3433
3434     bson_init_as_query(&bsq1);
3435     bson_append_string(&bsq1, "fullName", "John Travolta");
3436     bson_append_finish_object(&bsq1);
3437     bson_finish(&bsq1);
3438     CU_ASSERT_FALSE_FATAL(bsq1.err);
3439
3440     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3441     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3442     count = 0;
3443     log = tcxstrnew();
3444     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3445
3446     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3447         CU_ASSERT_TRUE(!bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
3448         bson_iterator_from_buffer(&it, TCLISTVALPTR(q1res, i));
3449         CU_ASSERT_TRUE(bson_find_from_buffer(&it, TCLISTVALPTR(q1res, i), "fullName") == BSON_EOO);
3450     }
3451
3452     bson_destroy(&bsq1);
3453     tclistdel(q1res);
3454     tcxstrdel(log);
3455     ejdbquerydel(q1);
3456         
3457 }
3458
3459 void testTicket88(void) { //https://github.com/Softmotions/ejdb/issues/88
3460     EJCOLL *ccoll = ejdbcreatecoll(jb, "ticket88", NULL);
3461     CU_ASSERT_PTR_NOT_NULL(ccoll);
3462
3463     bson r;
3464     bson_oid_t oid;
3465     for (int i = 0; i < 10; ++i) {
3466         bson_init(&r);
3467         bson_append_start_array(&r, "arr1");
3468         bson_append_start_object(&r, "0");
3469         bson_append_int(&r, "f1", 1 + i);
3470         bson_append_finish_object(&r);
3471         bson_append_start_object(&r, "1");
3472         bson_append_int(&r, "f1", 2 + i);
3473         bson_append_finish_object(&r);
3474         bson_append_finish_array(&r);
3475         bson_finish(&r);
3476         CU_ASSERT_TRUE(ejdbsavebson(ccoll, &r, &oid));
3477         bson_destroy(&r);
3478     }
3479
3480     bson bsq1;
3481     bson_init_as_query(&bsq1);
3482     bson_append_start_object(&bsq1, "$set");
3483     bson_append_string(&bsq1, "arr1.0.f2", "x");
3484     bson_append_int(&bsq1, "arr1.1", 1111);
3485     bson_append_string(&bsq1, "a.b", "c");
3486     bson_append_finish_object(&bsq1);
3487     bson_finish(&bsq1);
3488
3489     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3490     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3491     uint32_t count = 0;
3492     ejdbqryexecute(ccoll, q1, &count, JBQRYCOUNT, NULL);
3493     CU_ASSERT_TRUE(ejdbecode(jb) == 0);
3494     CU_ASSERT_EQUAL(count, 10);
3495     ejdbquerydel(q1);
3496     bson_destroy(&bsq1);
3497
3498     bson bsq2;
3499     bson_init_as_query(&bsq2);
3500     bson_append_string(&bsq2, "arr1.0.f2", "x");
3501     bson_append_int(&bsq2, "arr1.1", 1111);
3502     bson_append_string(&bsq2, "a.b", "c");
3503     bson_finish(&bsq2);
3504     q1 = ejdbcreatequery(jb, &bsq2, NULL, 0, NULL);
3505     ejdbqryexecute(ccoll, q1, &count, JBQRYCOUNT, NULL);
3506     CU_ASSERT_EQUAL(count, 10);
3507     ejdbquerydel(q1);
3508     bson_destroy(&bsq2);
3509 }
3510
3511 void testTicket89(void) { //https://github.com/Softmotions/ejdb/issues/89
3512     EJCOLL *ccoll = ejdbcreatecoll(jb, "ticket89", NULL);
3513     CU_ASSERT_PTR_NOT_NULL(ccoll);
3514
3515     bson r;
3516     bson_oid_t oid;
3517
3518     bson_init(&r);
3519     //{"test":[["aaa"],["bbb"]]}
3520     bson_append_start_array(&r, "test");
3521     bson_append_start_array(&r, "0");
3522     bson_append_string(&r, "0", "aaa");
3523     bson_append_finish_array(&r);
3524     bson_append_start_array(&r, "1");
3525     bson_append_string(&r, "0", "bbb");
3526     bson_append_finish_array(&r);
3527     bson_append_finish_array(&r);
3528     bson_finish(&r);
3529     CU_ASSERT_TRUE(ejdbsavebson(ccoll, &r, &oid));
3530     bson_destroy(&r);
3531
3532     bson bsq1;
3533     bson_init_as_query(&bsq1);
3534     bson_append_start_object(&bsq1, "$addToSet");
3535     bson_append_string(&bsq1, "test.0", "bbb");
3536     bson_append_finish_object(&bsq1);
3537     bson_finish(&bsq1);
3538
3539     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3540     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3541     uint32_t count = 0;
3542     ejdbqryexecute(ccoll, q1, &count, JBQRYCOUNT, NULL);
3543     CU_ASSERT_TRUE(ejdbecode(jb) == 0);
3544     CU_ASSERT_EQUAL(count, 1);
3545     ejdbquerydel(q1);
3546     bson_destroy(&bsq1);
3547
3548     bson_init_as_query(&bsq1);
3549     bson_append_string(&bsq1, "test.0.1", "bbb");
3550     bson_finish(&bsq1);
3551     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3552     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3553     ejdbqryexecute(ccoll, q1, &count, JBQRYCOUNT, NULL);
3554     CU_ASSERT_TRUE(ejdbecode(jb) == 0);
3555     CU_ASSERT_EQUAL(count, 1);
3556     ejdbquerydel(q1);
3557     bson_destroy(&bsq1);
3558 }
3559
3560 void testQueryBool(void) {
3561     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
3562     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
3563
3564     bson bsq1;
3565     bson_init_as_query(&bsq1);
3566     bson_append_bool(&bsq1, "visited", true);
3567     bson_finish(&bsq1);
3568     CU_ASSERT_FALSE_FATAL(bsq1.err);
3569
3570
3571     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3572     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3573     uint32_t count = 0;
3574     TCXSTR *log = tcxstrnew();
3575     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3576     //fprintf(stderr, "%s", TCXSTRPTR(log));
3577     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
3578     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
3579     CU_ASSERT_EQUAL(count, 1);
3580
3581     bson_destroy(&bsq1);
3582     tclistdel(q1res);
3583     tcxstrdel(log);
3584     ejdbquerydel(q1);
3585
3586     CU_ASSERT_TRUE(ejdbsetindex(coll, "visited", JBIDXNUM));
3587
3588     bson_init_as_query(&bsq1);
3589     bson_append_bool(&bsq1, "visited", true);
3590     bson_finish(&bsq1);
3591     CU_ASSERT_FALSE_FATAL(bsq1.err);
3592
3593     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3594     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3595     log = tcxstrnew();
3596     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3597     //fprintf(stderr, "%s", TCXSTRPTR(log));
3598     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'nvisited'"));
3599     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
3600     CU_ASSERT_EQUAL(count, 1);
3601
3602     bson_destroy(&bsq1);
3603     tclistdel(q1res);
3604     tcxstrdel(log);
3605     ejdbquerydel(q1);
3606 }
3607
3608 void testDropAll(void) {
3609     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
3610     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
3611     CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXSTR));
3612
3613     bson bsq1;
3614     bson_init_as_query(&bsq1);
3615     bson_append_string(&bsq1, "name", "HeLlo WorlD");
3616     bson_append_bool(&bsq1, "$dropall", true);
3617     bson_finish(&bsq1);
3618     CU_ASSERT_FALSE_FATAL(bsq1.err);
3619
3620
3621     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3622     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3623     uint32_t count = 0;
3624     TCXSTR *log = tcxstrnew();
3625     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3626     //fprintf(stderr, "%s", TCXSTRPTR(log));
3627     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "$DROPALL ON:"));
3628     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'sname'"));
3629     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
3630
3631     bson_destroy(&bsq1);
3632     tclistdel(q1res);
3633     tcxstrdel(log);
3634     ejdbquerydel(q1);
3635
3636     //Select again
3637     bson_init_as_query(&bsq1);
3638     bson_append_string(&bsq1, "name", "HeLlo WorlD");
3639     bson_finish(&bsq1);
3640     CU_ASSERT_FALSE_FATAL(bsq1.err);
3641
3642     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3643     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3644     log = tcxstrnew();
3645     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3646     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'sname'"));
3647     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 0"));
3648     //fprintf(stderr, "\n\n%s", TCXSTRPTR(log));
3649
3650     bson_destroy(&bsq1);
3651     tclistdel(q1res);
3652     tcxstrdel(log);
3653     ejdbquerydel(q1);
3654 }
3655
3656 void testTokensBegin(void) {
3657     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
3658     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
3659     CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXSTR));
3660
3661     //q: {'name' : {'$begin' : ['Ада', 'John T']}}
3662     bson bsq1;
3663     bson_init_as_query(&bsq1);
3664     bson_append_start_object(&bsq1, "name");
3665     bson_append_start_array(&bsq1, "$begin");
3666     bson_append_string(&bsq1, "0", "Ада");
3667     bson_append_string(&bsq1, "1", "John T");
3668     bson_append_string(&bsq1, "2", "QWE J");
3669     bson_append_finish_array(&bsq1);
3670     bson_append_finish_object(&bsq1);
3671     bson_finish(&bsq1);
3672     CU_ASSERT_FALSE_FATAL(bsq1.err);
3673
3674     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3675     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3676     uint32_t count = 0;
3677     TCXSTR *log = tcxstrnew();
3678     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3679     //fprintf(stderr, "%s", TCXSTRPTR(log));
3680
3681     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'sname'"));
3682     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX TCOP: 22"));
3683     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2"));
3684     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3685         CU_ASSERT_TRUE(!bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name") ||
3686                        !bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
3687     }
3688
3689     bson_destroy(&bsq1);
3690     tclistdel(q1res);
3691     tcxstrdel(log);
3692     ejdbquerydel(q1);
3693
3694     //q: {'name' : {'$begin' : ['Ада', 'John T']}}
3695     bson_init_as_query(&bsq1);
3696     bson_append_start_object(&bsq1, "name");
3697     bson_append_start_array(&bsq1, "$begin");
3698     bson_append_string(&bsq1, "0", "Ада");
3699     bson_append_string(&bsq1, "1", "John T");
3700     bson_append_string(&bsq1, "2", "QWE J");
3701     bson_append_finish_array(&bsq1);
3702     bson_append_finish_object(&bsq1);
3703     bson_finish(&bsq1);
3704     CU_ASSERT_FALSE_FATAL(bsq1.err);
3705
3706
3707     CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXDROPALL));
3708
3709     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3710     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3711     log = tcxstrnew();
3712     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3713     //fprintf(stderr, "%s", TCXSTRPTR(log));
3714
3715     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'NONE'"));
3716     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RUN FULLSCAN"));
3717     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 2"));
3718     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3719         CU_ASSERT_TRUE(!bson_compare_string("Адаманский", TCLISTVALPTR(q1res, i), "name") ||
3720                        !bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
3721     }
3722
3723     bson_destroy(&bsq1);
3724     tclistdel(q1res);
3725     tcxstrdel(log);
3726     ejdbquerydel(q1);
3727 }
3728
3729 void testOneFieldManyConditions(void) {
3730     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
3731     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
3732
3733     bson bsq1;
3734     bson_init_as_query(&bsq1);
3735     bson_append_start_object(&bsq1, "age");
3736     bson_append_int(&bsq1, "$lt", 60);
3737     bson_append_int(&bsq1, "$gt", 50);
3738     bson_append_finish_object(&bsq1);
3739     bson_finish(&bsq1);
3740     CU_ASSERT_FALSE_FATAL(bsq1.err);
3741
3742     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3743     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3744     uint32_t count = 0;
3745     TCXSTR *log = tcxstrnew();
3746     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3747     //fprintf(stderr, "%s", TCXSTRPTR(log));
3748     CU_ASSERT_EQUAL(count, 1);
3749     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3750         CU_ASSERT_TRUE(!bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
3751     }
3752     bson_destroy(&bsq1);
3753     tclistdel(q1res);
3754     tcxstrdel(log);
3755     ejdbquerydel(q1);
3756 }
3757
3758 void testAddToSet(void) {
3759     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
3760     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
3761     bson bsq1;
3762     bson_init_as_query(&bsq1);
3763     bson_append_string(&bsq1, "name", "Антонов");
3764     bson_append_start_object(&bsq1, "$addToSet");
3765     bson_append_string(&bsq1, "personal.tags", "tag1");
3766     bson_append_string(&bsq1, "labels", "green");
3767     bson_append_finish_object(&bsq1);
3768     bson_finish(&bsq1);
3769     CU_ASSERT_FALSE_FATAL(bsq1.err);
3770
3771     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3772     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3773     uint32_t count = 0;
3774     TCXSTR *log = tcxstrnew();
3775     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
3776     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: YES"));
3777     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
3778     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 0"));
3779     //fprintf(stderr, "%s", TCXSTRPTR(log));
3780     bson_destroy(&bsq1);
3781     tcxstrdel(log);
3782     ejdbquerydel(q1);
3783
3784     //check updated  data
3785     bson_init_as_query(&bsq1);
3786     bson_append_string(&bsq1, "name", "Антонов");
3787     bson_finish(&bsq1);
3788     CU_ASSERT_FALSE_FATAL(bsq1.err);
3789
3790     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3791     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3792     log = tcxstrnew();
3793     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3794     \
3795     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
3796     //fprintf(stderr, "\n\n%s", TCXSTRPTR(log));
3797
3798     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3799         CU_ASSERT_FALSE(bson_compare_string("tag1", TCLISTVALPTR(q1res, i), "personal.tags.0"));
3800         CU_ASSERT_FALSE(bson_compare_string("green", TCLISTVALPTR(q1res, i), "labels.0"));
3801     }
3802
3803     bson_destroy(&bsq1);
3804     tclistdel(q1res);
3805     tcxstrdel(log);
3806     ejdbquerydel(q1);
3807
3808     //Uppend more vals
3809     bson_init_as_query(&bsq1);
3810     bson_append_string(&bsq1, "name", "Антонов");
3811     bson_append_start_object(&bsq1, "$addToSet");
3812     bson_append_string(&bsq1, "personal.tags", "tag2");
3813     bson_append_string(&bsq1, "labels", "green");
3814     //bson_append_int(&bsq1, "scores", 1);
3815     bson_append_finish_object(&bsq1);
3816     bson_finish(&bsq1);
3817     CU_ASSERT_FALSE_FATAL(bsq1.err);
3818
3819     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3820     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3821     count = 0;
3822     log = tcxstrnew();
3823     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
3824     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: YES"));
3825     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
3826     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 0"));
3827     //fprintf(stderr, "%s", TCXSTRPTR(log));
3828     bson_destroy(&bsq1);
3829     tcxstrdel(log);
3830     ejdbquerydel(q1);
3831
3832
3833     //check updated  data
3834     bson_init_as_query(&bsq1);
3835     bson_append_string(&bsq1, "name", "Антонов");
3836     bson_finish(&bsq1);
3837     CU_ASSERT_FALSE_FATAL(bsq1.err);
3838
3839     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3840     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3841     log = tcxstrnew();
3842     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3843     \
3844     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
3845     //fprintf(stderr, "\n\n%s", TCXSTRPTR(log));
3846
3847     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3848         //bson_print_raw(TCLISTVALPTR(q1res, i), 0);
3849         CU_ASSERT_FALSE(bson_compare_string("tag1", TCLISTVALPTR(q1res, i), "personal.tags.0"));
3850         CU_ASSERT_FALSE(bson_compare_string("tag2", TCLISTVALPTR(q1res, i), "personal.tags.1"));
3851         CU_ASSERT_FALSE(bson_compare_string("green", TCLISTVALPTR(q1res, i), "labels.0"));
3852         CU_ASSERT_FALSE(!bson_compare_string("green", TCLISTVALPTR(q1res, i), "labels.1"));
3853     }
3854
3855     bson_destroy(&bsq1);
3856     tclistdel(q1res);
3857     tcxstrdel(log);
3858     ejdbquerydel(q1);
3859
3860     //Uppend more vals
3861     bson_init_as_query(&bsq1);
3862     bson_append_string(&bsq1, "name", "Антонов");
3863     bson_append_start_object(&bsq1, "$inc");
3864     bson_append_int(&bsq1, "age", -1);
3865     bson_append_finish_object(&bsq1);
3866     bson_append_start_object(&bsq1, "$addToSet");
3867     bson_append_string(&bsq1, "personal.tags", "tag3");
3868     bson_append_finish_object(&bsq1); //EOF $addToSet
3869     bson_append_start_object(&bsq1, "$addToSetAll");
3870     bson_append_start_array(&bsq1, "labels");
3871     bson_append_string(&bsq1, "0", "red");
3872     bson_append_string(&bsq1, "1", "black");
3873     bson_append_string(&bsq1, "2", "green");
3874     bson_append_finish_array(&bsq1);
3875     bson_append_finish_object(&bsq1); //EOF $addToSetAll
3876     bson_finish(&bsq1);
3877     CU_ASSERT_FALSE_FATAL(bsq1.err);
3878
3879     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3880     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3881     count = 0;
3882     log = tcxstrnew();
3883     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
3884     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: YES"));
3885     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
3886     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 0"));
3887     bson_destroy(&bsq1);
3888     tcxstrdel(log);
3889     ejdbquerydel(q1);
3890
3891     bson_init_as_query(&bsq1);
3892     bson_append_string(&bsq1, "name", "Антонов");
3893     bson_finish(&bsq1);
3894     CU_ASSERT_FALSE_FATAL(bsq1.err);
3895
3896     //check again
3897     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3898     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3899     log = tcxstrnew();
3900     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3901     \
3902     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
3903     //fprintf(stderr, "\n\n%s", TCXSTRPTR(log));
3904
3905     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3906         //bson_print_raw(TCLISTVALPTR(q1res, i), 0);
3907         CU_ASSERT_FALSE(bson_compare_string("tag1", TCLISTVALPTR(q1res, i), "personal.tags.0"));
3908         CU_ASSERT_FALSE(bson_compare_string("tag2", TCLISTVALPTR(q1res, i), "personal.tags.1"));
3909         CU_ASSERT_FALSE(bson_compare_string("tag3", TCLISTVALPTR(q1res, i), "personal.tags.2"));
3910         CU_ASSERT_FALSE(bson_compare_string("green", TCLISTVALPTR(q1res, i), "labels.0"));
3911         CU_ASSERT_FALSE(bson_compare_string("red", TCLISTVALPTR(q1res, i), "labels.1"));
3912         CU_ASSERT_FALSE(bson_compare_string("black", TCLISTVALPTR(q1res, i), "labels.2"));
3913         CU_ASSERT_TRUE(bson_compare_string("green", TCLISTVALPTR(q1res, i), "labels.3"));
3914     }
3915
3916     bson_destroy(&bsq1);
3917     tclistdel(q1res);
3918     tcxstrdel(log);
3919     ejdbquerydel(q1);
3920 }
3921
3922 void testTicket123(void) {
3923     EJCOLL *coll = ejdbcreatecoll(jb, "ticket123", NULL);
3924     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
3925
3926     bson bs1;
3927     bson_oid_t oid1;
3928     bson_init(&bs1);
3929     bson_append_start_object(&bs1, "abc");
3930     bson_append_start_array(&bs1, "de");
3931     bson_append_string(&bs1, "0", "g");
3932     bson_append_finish_array(&bs1);
3933     bson_append_start_array(&bs1, "fg");
3934     bson_append_finish_array(&bs1);
3935     bson_append_finish_object(&bs1);
3936     bson_finish(&bs1);
3937
3938     CU_ASSERT_TRUE_FATAL(ejdbsavebson(coll, &bs1, &oid1));
3939
3940     bson bsq1;
3941     bson_init_as_query(&bsq1);
3942     bson_append_start_object(&bsq1, "$addToSet");
3943     bson_append_string(&bsq1, "abc.g", "f");
3944     bson_append_finish_object(&bsq1);
3945     bson_finish(&bsq1);
3946     CU_ASSERT_FALSE_FATAL(bsq1.err);
3947
3948     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3949     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3950     uint32_t count = 0;
3951     TCXSTR *log = tcxstrnew();
3952     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
3953     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: YES"));
3954     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
3955     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 0"));
3956     //fprintf(stderr, "%s", TCXSTRPTR(log));
3957     bson_destroy(&bsq1);
3958     tcxstrdel(log);
3959     ejdbquerydel(q1);
3960
3961     //check updated  data
3962     bson_init_as_query(&bsq1);
3963     bson_finish(&bsq1);
3964     CU_ASSERT_FALSE_FATAL(bsq1.err);
3965
3966     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
3967     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
3968     log = tcxstrnew();
3969     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
3970
3971     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
3972     //fprintf(stderr, "\n\n%s", TCXSTRPTR(log));
3973
3974     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
3975         CU_ASSERT_FALSE(bson_compare_string("g", TCLISTVALPTR(q1res, i), "abc.de.0"));
3976         CU_ASSERT_FALSE(bson_compare_string("f", TCLISTVALPTR(q1res, i), "abc.g.0"));
3977     }
3978
3979     bson_destroy(&bs1);
3980     bson_destroy(&bsq1);
3981     tclistdel(q1res);
3982     tcxstrdel(log);
3983     ejdbquerydel(q1);
3984 }
3985
3986
3987 void testPull(void) {
3988     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
3989     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
3990     bson bsq1;
3991     bson_init_as_query(&bsq1);
3992     bson_append_string(&bsq1, "name", "Антонов");
3993     bson_append_start_object(&bsq1, "$pull");
3994     bson_append_string(&bsq1, "personal.tags", "tag2");
3995     bson_append_string(&bsq1, "labels", "green");
3996     bson_append_finish_object(&bsq1);
3997     bson_finish(&bsq1);
3998     CU_ASSERT_FALSE_FATAL(bsq1.err);
3999
4000     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4001     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4002     uint32_t count = 0;
4003     TCXSTR *log = tcxstrnew();
4004     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
4005     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: YES"));
4006     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
4007     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 0"));
4008     //fprintf(stderr, "%s", TCXSTRPTR(log));
4009     bson_destroy(&bsq1);
4010     tcxstrdel(log);
4011     ejdbquerydel(q1);
4012
4013     //check
4014     bson_init_as_query(&bsq1);
4015     bson_append_string(&bsq1, "name", "Антонов");
4016     bson_finish(&bsq1);
4017     CU_ASSERT_FALSE_FATAL(bsq1.err);
4018     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4019     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4020     log = tcxstrnew();
4021     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4022     \
4023     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
4024     //fprintf(stderr, "\n\n%s", TCXSTRPTR(log));
4025
4026     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
4027         //bson_print_raw(TCLISTVALPTR(q1res, i), 0);
4028         CU_ASSERT_FALSE(bson_compare_string("tag1", TCLISTVALPTR(q1res, i), "personal.tags.0"));
4029         CU_ASSERT_FALSE(bson_compare_string("tag3", TCLISTVALPTR(q1res, i), "personal.tags.1"));
4030         CU_ASSERT_FALSE(bson_compare_string("red", TCLISTVALPTR(q1res, i), "labels.0"));
4031     }
4032
4033     bson_destroy(&bsq1);
4034     tclistdel(q1res);
4035     tcxstrdel(log);
4036     ejdbquerydel(q1);
4037 }
4038
4039 void testFindInComplexArray(void) {
4040     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
4041     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4042     bson bsq1;
4043     bson_init_as_query(&bsq1);
4044     bson_append_string(&bsq1, "complexarr.key", "title");
4045     bson_append_string(&bsq1, "complexarr.value", "some title");
4046     bson_finish(&bsq1);
4047     CU_ASSERT_FALSE_FATAL(bsq1.err);
4048
4049     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4050     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4051     uint32_t count = 0;
4052     TCXSTR *log = tcxstrnew();
4053     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4054     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4055     //fprintf(stderr, "%s", TCXSTRPTR(log));
4056     CU_ASSERT_EQUAL_FATAL(count, 2);
4057
4058     // 0
4059     CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name"));
4060
4061     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key"));
4062     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value"));
4063
4064     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key"));
4065     CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value"));
4066
4067     // 1
4068     CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, 1), "name"));
4069     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 1), "complexarr.0.key"));
4070     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 1), "complexarr.0.value"));
4071
4072     bson_destroy(&bsq1);
4073     tclistdel(q1res);
4074     tcxstrdel(log);
4075     ejdbquerydel(q1);
4076
4077     //Check matching positional element
4078     bson_init_as_query(&bsq1);
4079     bson_append_string(&bsq1, "complexarr.0.key", "title");
4080     bson_finish(&bsq1);
4081     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4082     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4083     log = tcxstrnew();
4084     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4085     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4086     //fprintf(stderr, "\n%s", TCXSTRPTR(log));
4087     CU_ASSERT_EQUAL_FATAL(count, 2);
4088
4089     // 0
4090     CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name"));
4091
4092     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key"));
4093     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value"));
4094
4095     // 1
4096     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key"));
4097     CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value"));
4098
4099     CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, 1), "name"));
4100     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 1), "complexarr.0.key"));
4101     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 1), "complexarr.0.value"));
4102
4103     bson_destroy(&bsq1);
4104     tclistdel(q1res);
4105     tcxstrdel(log);
4106     ejdbquerydel(q1);
4107
4108     //Check simple el
4109     bson_init_as_query(&bsq1);
4110     bson_append_int(&bsq1, "complexarr.2", 333);
4111     bson_finish(&bsq1);
4112     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4113     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4114     log = tcxstrnew();
4115     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4116     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4117     //fprintf(stderr, "\n%s", TCXSTRPTR(log));
4118     CU_ASSERT_EQUAL_FATAL(count, 1);
4119
4120     // 0
4121     CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name"));
4122
4123     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key"));
4124     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value"));
4125
4126     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key"));
4127     CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value"));
4128
4129     CU_ASSERT_FALSE(bson_compare_long(333, TCLISTVALPTR(q1res, 0), "complexarr.2"));
4130
4131     bson_destroy(&bsq1);
4132     tclistdel(q1res);
4133     tcxstrdel(log);
4134     ejdbquerydel(q1);
4135
4136     //Check simple el2
4137     bson_init_as_query(&bsq1);
4138     bson_append_int(&bsq1, "complexarr", 333);
4139     bson_finish(&bsq1);
4140     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4141     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4142     log = tcxstrnew();
4143     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4144     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4145     //fprintf(stderr, "\n%s", TCXSTRPTR(log));
4146     CU_ASSERT_EQUAL_FATAL(count, 1);
4147
4148     // 0
4149     CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name"));
4150
4151     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key"));
4152     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value"));
4153
4154     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key"));
4155     CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value"));
4156
4157     CU_ASSERT_FALSE(bson_compare_long(333, TCLISTVALPTR(q1res, 0), "complexarr.2"));
4158
4159     bson_destroy(&bsq1);
4160     tclistdel(q1res);
4161     tcxstrdel(log);
4162     ejdbquerydel(q1);
4163
4164
4165     //$exists
4166     bson_init_as_query(&bsq1);
4167     bson_append_start_object(&bsq1, "complexarr.key");
4168     bson_append_bool(&bsq1, "$exists", true);
4169     bson_append_finish_object(&bsq1);
4170     bson_finish(&bsq1);
4171     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4172     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4173     log = tcxstrnew();
4174     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4175     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4176     CU_ASSERT_EQUAL(count, 2);
4177     bson_destroy(&bsq1);
4178     tclistdel(q1res);
4179     tcxstrdel(log);
4180     ejdbquerydel(q1);
4181
4182
4183     //$exists 2
4184     bson_init_as_query(&bsq1);
4185     bson_append_start_object(&bsq1, "complexarr.2");
4186     bson_append_bool(&bsq1, "$exists", true);
4187     bson_append_finish_object(&bsq1);
4188     bson_finish(&bsq1);
4189     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4190     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4191     log = tcxstrnew();
4192     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4193     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4194     CU_ASSERT_EQUAL(count, 1);
4195     bson_destroy(&bsq1);
4196     tclistdel(q1res);
4197     tcxstrdel(log);
4198     ejdbquerydel(q1);
4199
4200
4201     //$exists 3
4202     bson_init_as_query(&bsq1);
4203     bson_append_start_object(&bsq1, "complexarr.4");
4204     bson_append_bool(&bsq1, "$exists", true);
4205     bson_append_finish_object(&bsq1);
4206     bson_finish(&bsq1);
4207     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4208     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4209     log = tcxstrnew();
4210     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4211     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4212     CU_ASSERT_EQUAL(count, 0);
4213     bson_destroy(&bsq1);
4214     tclistdel(q1res);
4215     tcxstrdel(log);
4216     ejdbquerydel(q1);
4217 }
4218
4219 void testElemMatch(void) {
4220     // { complexarr: { $elemMatch: { key: 'title', value: 'some title' } } }
4221     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
4222     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4223     bson bsq1;
4224     bson_init_as_query(&bsq1);
4225     bson_append_start_object(&bsq1, "complexarr");
4226     bson_append_start_object(&bsq1, "$elemMatch");
4227     bson_append_string(&bsq1, "key", "title");
4228     bson_append_string(&bsq1, "value", "some title");
4229     bson_append_finish_object(&bsq1);
4230     bson_append_finish_object(&bsq1);
4231     bson_finish(&bsq1);
4232     CU_ASSERT_FALSE_FATAL(bsq1.err);
4233
4234     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4235     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4236     uint32_t count = 0;
4237     TCXSTR *log = tcxstrnew();
4238     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4239     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4240     CU_ASSERT_EQUAL_FATAL(count, 2);
4241 //    fprintf(stderr, "%s", TCXSTRPTR(log));
4242
4243     // 0
4244     CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name"));
4245
4246     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key"));
4247     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value"));
4248
4249     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key"));
4250     CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value"));
4251
4252     // 1
4253     CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, 1), "name"));
4254
4255     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 1), "complexarr.0.key"));
4256     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 1), "complexarr.0.value"));
4257
4258     CU_ASSERT_FALSE(bson_compare_string("comment", TCLISTVALPTR(q1res, 1), "complexarr.1.key"));
4259     CU_ASSERT_FALSE(bson_compare_string("some comment", TCLISTVALPTR(q1res, 1), "complexarr.1.value"));
4260
4261     bson_destroy(&bsq1);
4262     tclistdel(q1res);
4263     tcxstrdel(log);
4264     ejdbquerydel(q1);
4265
4266     bson_init_as_query(&bsq1);
4267     bson_append_start_object(&bsq1, "complexarr");
4268     bson_append_start_object(&bsq1, "$elemMatch");
4269     bson_append_string(&bsq1, "key", "title");
4270     bson_append_string(&bsq1, "value", "some other title");
4271     bson_append_finish_object(&bsq1);
4272     bson_append_finish_object(&bsq1);
4273     bson_finish(&bsq1);
4274     CU_ASSERT_FALSE_FATAL(bsq1.err);
4275     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4276     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4277     log = tcxstrnew();
4278     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4279     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4280     //fprintf(stderr, "%s", TCXSTRPTR(log));
4281     CU_ASSERT_EQUAL_FATAL(count, 1);
4282
4283     // 0
4284     CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name"));
4285
4286     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key"));
4287     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value"));
4288
4289     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key"));
4290     CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value"));
4291
4292     bson_destroy(&bsq1);
4293     tclistdel(q1res);
4294     tcxstrdel(log);
4295     ejdbquerydel(q1);
4296
4297     bson_init_as_query(&bsq1);
4298     bson_append_start_object(&bsq1, "complexarr");
4299     bson_append_start_object(&bsq1, "$elemMatch");
4300     bson_append_string(&bsq1, "key", "title");
4301     bson_append_start_object(&bsq1, "value");
4302     bson_append_string(&bsq1, "$not", "some title");
4303     bson_append_finish_object(&bsq1);
4304     bson_append_finish_object(&bsq1);
4305     bson_append_finish_object(&bsq1);
4306     bson_finish(&bsq1);
4307     CU_ASSERT_FALSE_FATAL(bsq1.err);
4308     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4309     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4310     log = tcxstrnew();
4311     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4312     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4313 //    fprintf(stderr, "%s", TCXSTRPTR(log));
4314     CU_ASSERT_EQUAL_FATAL(count, 1);
4315
4316     // 0
4317     CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name"));
4318
4319     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key"));
4320     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value"));
4321
4322     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key"));
4323     CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value"));
4324
4325     bson_destroy(&bsq1);
4326     tclistdel(q1res);
4327     tcxstrdel(log);
4328     ejdbquerydel(q1);
4329
4330     bson_init_as_query(&bsq1);
4331     bson_append_string(&bsq1, "complexarr.key", "title");
4332     bson_append_string(&bsq1, "complexarr.value", "some other title");
4333     bson_finish(&bsq1);
4334     CU_ASSERT_FALSE_FATAL(bsq1.err);
4335     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4336     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4337     log = tcxstrnew();
4338     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4339     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4340     //fprintf(stderr, "%s", TCXSTRPTR(log));
4341     CU_ASSERT_EQUAL_FATAL(count, 1);
4342
4343     // 0
4344     CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name"));
4345
4346     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key"));
4347     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value"));
4348
4349     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key"));
4350     CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value"));
4351
4352     bson_destroy(&bsq1);
4353     tclistdel(q1res);
4354     tcxstrdel(log);
4355     ejdbquerydel(q1);
4356 }
4357
4358 void testNotElemMatch(void) {
4359     // { complexarr: { $not: { $elemMatch: { key: 'title', value: 'some title' } } } }
4360     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
4361     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4362     bson bsq1;
4363     bson_init_as_query(&bsq1);
4364     bson_append_start_object(&bsq1, "complexarr");
4365     bson_append_start_object(&bsq1, "$not");
4366     bson_append_start_object(&bsq1, "$elemMatch");
4367     bson_append_string(&bsq1, "key", "title");
4368     bson_append_string(&bsq1, "value", "some title");
4369     bson_append_finish_object(&bsq1);//$elemMatch
4370     bson_append_finish_object(&bsq1);//$not
4371     //include $exists to exclude documents without complexarr
4372     bson_append_bool(&bsq1, "$exists", true);
4373     bson_append_finish_object(&bsq1);//complexarr
4374     bson_finish(&bsq1);
4375     CU_ASSERT_FALSE_FATAL(bsq1.err);
4376
4377     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4378     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4379     uint32_t count = 0;
4380     TCXSTR *log = tcxstrnew();
4381     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4382     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4383     //fprintf(stderr, "%s", TCXSTRPTR(log));
4384     CU_ASSERT_EQUAL_FATAL(count, 0);
4385
4386     bson_destroy(&bsq1);
4387     tclistdel(q1res);
4388     tcxstrdel(log);
4389     ejdbquerydel(q1);
4390
4391     bson_init_as_query(&bsq1);
4392     bson_append_start_object(&bsq1, "complexarr");
4393     bson_append_start_object(&bsq1, "$not");
4394     bson_append_start_object(&bsq1, "$elemMatch");
4395     bson_append_string(&bsq1, "key", "title");
4396     bson_append_string(&bsq1, "value", "some other title");
4397     bson_append_finish_object(&bsq1);//$elemMatch
4398     bson_append_finish_object(&bsq1);//$not
4399     bson_append_bool(&bsq1, "$exists", true);
4400     bson_append_finish_object(&bsq1);
4401     bson_finish(&bsq1);
4402     CU_ASSERT_FALSE_FATAL(bsq1.err);
4403     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4404     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4405     log = tcxstrnew();
4406     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4407     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4408     //fprintf(stderr, "%s", TCXSTRPTR(log));
4409     CU_ASSERT_EQUAL_FATAL(count, 1);
4410
4411     // 0
4412     CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, 0), "name"));
4413
4414     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key"));
4415     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value"));
4416
4417     CU_ASSERT_FALSE(bson_compare_string("comment", TCLISTVALPTR(q1res, 0), "complexarr.1.key"));
4418     CU_ASSERT_FALSE(bson_compare_string("some comment", TCLISTVALPTR(q1res, 0), "complexarr.1.value"));
4419
4420     bson_destroy(&bsq1);
4421     tclistdel(q1res);
4422     tcxstrdel(log);
4423     ejdbquerydel(q1);
4424
4425     bson_init_as_query(&bsq1);
4426     bson_append_start_object(&bsq1, "complexarr");
4427     bson_append_start_object(&bsq1, "$not");
4428     bson_append_start_object(&bsq1, "$elemMatch");
4429     bson_append_string(&bsq1, "key", "comment");
4430     bson_append_finish_object(&bsq1);//$elemMatch
4431     bson_append_finish_object(&bsq1);//$not
4432     bson_append_bool(&bsq1, "$exists", true);
4433     bson_append_finish_object(&bsq1);
4434     bson_finish(&bsq1);
4435     CU_ASSERT_FALSE_FATAL(bsq1.err);
4436     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4437     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4438     log = tcxstrnew();
4439     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4440     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4441     //fprintf(stderr, "%s", TCXSTRPTR(log));
4442     CU_ASSERT_EQUAL_FATAL(count, 1);
4443
4444     // 0
4445     CU_ASSERT_FALSE(bson_compare_string("Адаманский", TCLISTVALPTR(q1res, 0), "name"));
4446
4447     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key"));
4448     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value"));
4449
4450     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.1.key"));
4451     CU_ASSERT_FALSE(bson_compare_string("some other title", TCLISTVALPTR(q1res, 0), "complexarr.1.value"));
4452
4453     bson_destroy(&bsq1);
4454     tclistdel(q1res);
4455     tcxstrdel(log);
4456     ejdbquerydel(q1);
4457
4458     //ensure correct behaviour of double negative
4459     bson_init_as_query(&bsq1);
4460     bson_append_start_object(&bsq1, "complexarr");
4461     bson_append_start_object(&bsq1, "$not");
4462     bson_append_start_object(&bsq1, "$elemMatch");
4463     bson_append_string(&bsq1, "key", "title");
4464     bson_append_start_object(&bsq1, "value");
4465     bson_append_string(&bsq1, "$not", "some title");
4466     bson_append_finish_object(&bsq1);
4467     bson_append_finish_object(&bsq1);
4468     bson_append_finish_object(&bsq1);
4469     bson_append_finish_object(&bsq1);
4470     bson_finish(&bsq1);
4471     CU_ASSERT_FALSE_FATAL(bsq1.err);
4472     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4473     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4474     log = tcxstrnew();
4475     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4476     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4477     //fprintf(stderr, "%s", TCXSTRPTR(log));
4478     CU_ASSERT_EQUAL_FATAL(count, 1);
4479
4480     // 0
4481     CU_ASSERT_FALSE(bson_compare_string("Антонов", TCLISTVALPTR(q1res, 0), "name"));
4482
4483     CU_ASSERT_FALSE(bson_compare_string("title", TCLISTVALPTR(q1res, 0), "complexarr.0.key"));
4484     CU_ASSERT_FALSE(bson_compare_string("some title", TCLISTVALPTR(q1res, 0), "complexarr.0.value"));
4485
4486     CU_ASSERT_FALSE(bson_compare_string("comment", TCLISTVALPTR(q1res, 0), "complexarr.1.key"));
4487     CU_ASSERT_FALSE(bson_compare_string("some comment", TCLISTVALPTR(q1res, 0), "complexarr.1.value"));
4488
4489     bson_destroy(&bsq1);
4490     tclistdel(q1res);
4491     tcxstrdel(log);
4492     ejdbquerydel(q1);
4493 }
4494
4495 void testTicket16(void) {
4496     EJCOLL *coll = ejdbcreatecoll(jb, "abcd", NULL);
4497     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4498     CU_ASSERT_EQUAL(coll->tdb->inum, 0);
4499     CU_ASSERT_TRUE(ejdbsetindex(coll, "abcd", JBIDXISTR));
4500     CU_ASSERT_TRUE(ejdbsetindex(coll, "abcd", JBIDXNUM));
4501     CU_ASSERT_EQUAL(coll->tdb->inum, 2);
4502     CU_ASSERT_TRUE(ejdbsetindex(coll, "abcd", JBIDXDROPALL));
4503     CU_ASSERT_EQUAL(coll->tdb->inum, 0);
4504 }
4505
4506 void testUpsert(void) {
4507     EJCOLL *coll = ejdbcreatecoll(jb, "abcd", NULL);
4508     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4509     bson bsq1;
4510     bson_init_as_query(&bsq1);
4511     bson_append_string(&bsq1, "cde", "fgh"); //sel condition
4512     bson_append_start_object(&bsq1, "$upsert");
4513     bson_append_string(&bsq1, "cde", "fgh");
4514     bson_append_string(&bsq1, "ijk", "lmnp");
4515     bson_append_finish_object(&bsq1);
4516     bson_finish(&bsq1);
4517     CU_ASSERT_FALSE_FATAL(bsq1.err);
4518
4519     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4520     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4521     uint32_t count = 0;
4522     TCXSTR *log = tcxstrnew();
4523     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4524     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4525     CU_ASSERT_EQUAL(count, 1);
4526
4527     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
4528         bson_iterator it;
4529         CU_ASSERT_TRUE(bson_find_from_buffer(&it, TCLISTVALPTR(q1res, i), "_id") == BSON_OID);
4530         CU_ASSERT_FALSE(bson_compare_string("fgh", TCLISTVALPTR(q1res, i), "cde"));
4531         CU_ASSERT_FALSE(bson_compare_string("lmnp", TCLISTVALPTR(q1res, i), "ijk"));
4532     }
4533
4534     bson_destroy(&bsq1);
4535     tclistdel(q1res);
4536     tcxstrdel(log);
4537     ejdbquerydel(q1);
4538
4539     bson_init_as_query(&bsq1);
4540     bson_append_string(&bsq1, "cde", "fgh"); //sel condition
4541     bson_append_start_object(&bsq1, "$upsert");
4542     bson_append_string(&bsq1, "cde", "fgh");
4543     bson_append_string(&bsq1, "ijk", "lmnp+");
4544     bson_append_finish_object(&bsq1);
4545     bson_finish(&bsq1);
4546     CU_ASSERT_FALSE_FATAL(bsq1.err);
4547
4548     log = tcxstrnew();
4549     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4550     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4551     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4552     //fprintf(stderr, "%s", TCXSTRPTR(log));
4553     CU_ASSERT_EQUAL(count, 1);
4554
4555     bson_destroy(&bsq1);
4556     tclistdel(q1res);
4557     tcxstrdel(log);
4558     ejdbquerydel(q1);
4559
4560     bson_init_as_query(&bsq1);
4561     bson_append_string(&bsq1, "cde", "fgh");
4562     bson_finish(&bsq1);
4563     CU_ASSERT_FALSE_FATAL(bsq1.err);
4564
4565     log = tcxstrnew();
4566     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4567     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4568     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4569     //fprintf(stderr, "%s", TCXSTRPTR(log));
4570     CU_ASSERT_EQUAL(count, 1);
4571
4572     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
4573         CU_ASSERT_FALSE(bson_compare_string("fgh", TCLISTVALPTR(q1res, i), "cde"));
4574         CU_ASSERT_FALSE(bson_compare_string("lmnp+", TCLISTVALPTR(q1res, i), "ijk"));
4575     }
4576
4577     bson_destroy(&bsq1);
4578     tclistdel(q1res);
4579     tcxstrdel(log);
4580     ejdbquerydel(q1);
4581 }
4582
4583 void testPrimitiveCases1(void) {
4584     EJCOLL *coll = ejdbcreatecoll(jb, "abcd", NULL);
4585     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4586     bson bsq1;
4587     bson_init_as_query(&bsq1);
4588     bson_finish(&bsq1);
4589     CU_ASSERT_FALSE_FATAL(bsq1.err);
4590
4591     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4592     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4593     uint32_t count = 0;
4594     TCXSTR *log = tcxstrnew();
4595     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
4596     CU_ASSERT_EQUAL(count, 1);
4597     //fprintf(stderr, "%s", TCXSTRPTR(log));
4598     CU_ASSERT_EQUAL(count, 1);
4599     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "SIMPLE COUNT(*): 1"));
4600     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
4601     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 0"));
4602
4603     bson_destroy(&bsq1);
4604     tcxstrdel(log);
4605     ejdbquerydel(q1);
4606
4607     //$dropall on whole collection
4608     bson_init_as_query(&bsq1);
4609     bson_append_bool(&bsq1, "$dropall", true);
4610     bson_finish(&bsq1);
4611     CU_ASSERT_FALSE_FATAL(bsq1.err);
4612
4613     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4614     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4615     count = 0;
4616     log = tcxstrnew();
4617     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
4618     CU_ASSERT_EQUAL(count, 1);
4619     //fprintf(stderr, "%s", TCXSTRPTR(log));
4620     CU_ASSERT_EQUAL(count, 1);
4621     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "VANISH WHOLE COLLECTION ON $dropall"));
4622     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1"));
4623     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 0"));
4624
4625     bson_destroy(&bsq1);
4626     tcxstrdel(log);
4627     ejdbquerydel(q1);
4628 }
4629
4630 void testTicket29(void) {
4631     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
4632     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4633     CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXARR));
4634
4635     bson a1;
4636     bson_init(&a1);
4637     bson_append_string(&a1, "name", "Hello Мир");
4638     bson_append_long(&a1, "longscore", 77);
4639     bson_finish(&a1);
4640     CU_ASSERT_FALSE_FATAL(a1.err);
4641
4642     bson_oid_t oid;
4643     CU_ASSERT_TRUE(ejdbsavebson(coll, &a1, &oid));
4644     bson_destroy(&a1);
4645
4646     //{"name" : {$strand : ["Hello", "Мир"]}}
4647     bson bsq1;
4648     bson_init_as_query(&bsq1);
4649     bson_append_start_object(&bsq1, "name");
4650     bson_append_start_array(&bsq1, "$strand");
4651     bson_append_string(&bsq1, "0", "Hello");
4652     bson_append_string(&bsq1, "1", "Мир");
4653     bson_append_finish_array(&bsq1);
4654     bson_append_finish_object(&bsq1);
4655     bson_finish(&bsq1);
4656     CU_ASSERT_FALSE_FATAL(bsq1.err);
4657
4658     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4659     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4660     uint32_t count = 0;
4661     TCXSTR *log = tcxstrnew();
4662     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4663     //fprintf(stderr, "%s", TCXSTRPTR(log));
4664     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4665     CU_ASSERT_EQUAL(count, 1);
4666     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "token occurrence: \"Hello\" 1"));
4667
4668     bson_destroy(&bsq1);
4669     tclistdel(q1res);
4670     tcxstrdel(log);
4671     ejdbquerydel(q1);
4672 }
4673
4674 void testTicket28(void) {
4675     EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
4676     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4677     //{$some:2}
4678     bson bsq1;
4679     bson_init_as_query(&bsq1);
4680     bson_append_int(&bsq1, "$some", 2);
4681     bson_finish(&bsq1);
4682     CU_ASSERT_FALSE_FATAL(bsq1.err);
4683     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4684     CU_ASSERT_EQUAL(ejdbecode(jb), JBEQERROR);
4685     CU_ASSERT_PTR_NULL(q1);
4686     bson_destroy(&bsq1);
4687
4688     //Second step
4689     bson_init_as_query(&bsq1);
4690     bson_finish(&bsq1);
4691     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4692     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4693     uint32_t count = 0;
4694     TCXSTR *log = tcxstrnew();
4695     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4696     CU_ASSERT_EQUAL(ejdbecode(jb), TCESUCCESS);
4697     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4698
4699     bson_destroy(&bsq1);
4700     tcxstrdel(log);
4701     ejdbquerydel(q1);
4702     tclistdel(q1res);
4703 }
4704
4705 void testTicket38(void) {
4706     EJCOLL *coll = ejdbcreatecoll(jb, "ticket38", NULL);
4707     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4708
4709     //R: {a: [ 'b', 'c', 'ddd', 3 ]}
4710     bson r1;
4711     bson_init(&r1);
4712     bson_append_start_array(&r1, "a");
4713     bson_append_string(&r1, "0", "b");
4714     bson_append_string(&r1, "1", "c");
4715     bson_append_string(&r1, "2", "ddd");
4716     bson_append_int(&r1, "3", 3);
4717     bson_append_finish_array(&r1);
4718     bson_finish(&r1);
4719     CU_ASSERT_FALSE_FATAL(r1.err);
4720
4721     bson_oid_t oid;
4722     CU_ASSERT_TRUE(ejdbsavebson(coll, &r1, &oid));
4723     bson_destroy(&r1);
4724
4725     //Q: {$pullAll:{a:[3, 2, 'c']}
4726     bson bsq1;
4727     bson_init_as_query(&bsq1);
4728     bson_append_start_object(&bsq1, "$pullAll");
4729     bson_append_start_array(&bsq1, "a");
4730     bson_append_int(&bsq1, "0", 3);
4731     bson_append_int(&bsq1, "1", 2);
4732     bson_append_string(&bsq1, "2", "c");
4733     bson_append_finish_array(&bsq1);
4734     bson_append_finish_object(&bsq1);
4735     bson_finish(&bsq1);
4736     CU_ASSERT_FALSE_FATAL(bsq1.err);
4737
4738     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4739     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4740     uint32_t count = 0;
4741     TCXSTR *log = tcxstrnew();
4742     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
4743     //fprintf(stderr, "%s", TCXSTRPTR(log));
4744
4745     tcxstrdel(log);
4746     ejdbquerydel(q1);
4747     bson_destroy(&bsq1);
4748
4749     //Q: {}
4750     bson_init_as_query(&bsq1);
4751     bson_finish(&bsq1);
4752     CU_ASSERT_FALSE_FATAL(bsq1.err);
4753     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4754     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4755     log = tcxstrnew();
4756     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4757     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4758
4759     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
4760         void *bsdata = TCLISTVALPTR(q1res, i);
4761         bson_iterator it;
4762         bson_iterator_from_buffer(&it, bsdata);
4763         bson_type bt = bson_find_fieldpath_value("_id", &it);
4764         CU_ASSERT_EQUAL(bt, BSON_OID);
4765         CU_ASSERT_FALSE(bson_compare_string("b", TCLISTVALPTR(q1res, i), "a.0"));
4766         CU_ASSERT_FALSE(bson_compare_string("ddd", TCLISTVALPTR(q1res, i), "a.1"));
4767         bt = bson_find_fieldpath_value("a.2", &it);
4768         CU_ASSERT_EQUAL(bt, BSON_EOO);
4769         bt = bson_find_fieldpath_value("a.3", &it);
4770         CU_ASSERT_EQUAL(bt, BSON_EOO);
4771     }
4772
4773     tcxstrdel(log);
4774     ejdbquerydel(q1);
4775     bson_destroy(&bsq1);
4776     tclistdel(q1res);
4777 }
4778
4779 void testTicket43(void) {
4780
4781     EJCOLL *coll = ejdbcreatecoll(jb, "ticket43", NULL);
4782     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4783     EJCOLL *rcoll = ejdbcreatecoll(jb, "ticket43_refs", NULL);
4784     CU_ASSERT_PTR_NOT_NULL_FATAL(rcoll);
4785
4786     bson a1;
4787     bson_oid_t oid;
4788     bson_oid_t ref_oids[2];
4789     char xoid[25];
4790
4791     bson_init(&a1);
4792     bson_append_string(&a1, "name", "n1");
4793     bson_append_string(&a1, "name2", "n12");
4794     bson_finish(&a1);
4795     CU_ASSERT_FALSE_FATAL(a1.err);
4796     CU_ASSERT_TRUE_FATAL(ejdbsavebson(rcoll, &a1, &ref_oids[0]));
4797     bson_destroy(&a1);
4798
4799     bson_init(&a1);
4800     bson_append_string(&a1, "name", "n2");
4801     bson_append_string(&a1, "name2", "n22");
4802     bson_finish(&a1);
4803     CU_ASSERT_FALSE_FATAL(a1.err);
4804     CU_ASSERT_TRUE_FATAL(ejdbsavebson(rcoll, &a1, &ref_oids[1]));
4805     bson_destroy(&a1);
4806
4807     bson_init(&a1);
4808     bson_append_string(&a1, "name", "c1");
4809     bson_oid_to_string(&ref_oids[0], xoid);
4810     bson_append_string(&a1, "refs", xoid);
4811     bson_finish(&a1);
4812     CU_ASSERT_FALSE_FATAL(a1.err);
4813     CU_ASSERT_TRUE_FATAL(ejdbsavebson(coll, &a1, &oid));
4814     bson_destroy(&a1);
4815
4816     bson_init(&a1);
4817     bson_append_string(&a1, "name", "c2");
4818     bson_append_start_array(&a1, "arrefs");
4819     bson_oid_to_string(&ref_oids[0], xoid);
4820     bson_append_string(&a1, "0", xoid);
4821     bson_append_oid(&a1, "1", &ref_oids[1]);
4822     bson_append_finish_array(&a1);
4823     bson_finish(&a1);
4824     CU_ASSERT_FALSE_FATAL(a1.err);
4825     CU_ASSERT_TRUE_FATAL(ejdbsavebson(coll, &a1, &oid));
4826     bson_destroy(&a1);
4827
4828     /*
4829      Assuming fpath contains object id (or its string representation).
4830      In query results fpath values will be replaced by loaded bson
4831      objects with matching oids from collectionname
4832
4833      {..., $do : {fpath : {$join : 'collectionname'}} }
4834      $fields applied to the joined object:
4835      {..., $do : {fpath : {$join : 'collectionname'}} }, {$fields : {fpath.jonnedfpath : 1}}
4836      */
4837
4838     bson bsq1;
4839     bson_init_as_query(&bsq1);
4840     bson_append_string(&bsq1, "name", "c1");
4841     bson_append_start_object(&bsq1, "$do");
4842     bson_append_start_object(&bsq1, "refs");
4843     bson_append_string(&bsq1, "$join", "ticket43_refs");
4844     bson_append_finish_object(&bsq1);
4845     bson_append_finish_object(&bsq1);
4846     bson_finish(&bsq1);
4847     CU_ASSERT_FALSE_FATAL(bsq1.err);
4848
4849     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4850     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4851
4852     uint32_t count = 0;
4853     TCXSTR *log = tcxstrnew();
4854     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4855     //fprintf(stderr, "%s", TCXSTRPTR(log));
4856     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4857     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FIELD: refs HAS $do OPERATION"));
4858     CU_ASSERT_EQUAL(count, 1);
4859
4860     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
4861         CU_ASSERT_FALSE(bson_compare_string("n1", TCLISTVALPTR(q1res, i), "refs.name"));
4862     }
4863
4864     tclistdel(q1res);
4865     ejdbquerydel(q1);
4866     bson_destroy(&bsq1);
4867     tcxstrdel(log);
4868
4869     /////////////////////////////////////////////////////////////////////////////////////
4870
4871     bson_init_as_query(&bsq1);
4872     bson_append_string(&bsq1, "name", "c2");
4873     bson_append_start_object(&bsq1, "$do");
4874     bson_append_start_object(&bsq1, "arrefs");
4875     bson_append_string(&bsq1, "$join", "ticket43_refs");
4876     bson_append_finish_object(&bsq1);
4877     bson_append_finish_object(&bsq1);
4878     bson_finish(&bsq1);
4879     CU_ASSERT_FALSE_FATAL(bsq1.err);
4880
4881     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
4882     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4883
4884     count = 0;
4885     log = tcxstrnew();
4886     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4887
4888     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4889     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FIELD: arrefs HAS $do OPERATION"));
4890     CU_ASSERT_EQUAL(count, 1);
4891
4892     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
4893         CU_ASSERT_FALSE(bson_compare_string("c2", TCLISTVALPTR(q1res, i), "name"));
4894         CU_ASSERT_FALSE(bson_compare_string("n1", TCLISTVALPTR(q1res, i), "arrefs.0.name"));
4895         CU_ASSERT_FALSE(bson_compare_string("n2", TCLISTVALPTR(q1res, i), "arrefs.1.name"));
4896     }
4897
4898     tclistdel(q1res);
4899     ejdbquerydel(q1);
4900     bson_destroy(&bsq1);
4901     tcxstrdel(log);
4902
4903     /////////////////////////////////////////////////////////////////////////////////////////////////
4904
4905     bson_init_as_query(&bsq1);
4906     bson_append_string(&bsq1, "name", "c2");
4907     bson_append_start_object(&bsq1, "$do");
4908     bson_append_start_object(&bsq1, "arrefs");
4909     bson_append_string(&bsq1, "$join", "ticket43_refs");
4910     bson_append_finish_object(&bsq1);
4911     bson_append_finish_object(&bsq1);
4912     bson_finish(&bsq1);
4913     CU_ASSERT_FALSE_FATAL(bsq1.err);
4914
4915
4916     bson bshits1;
4917     bson_init_as_query(&bshits1);
4918     bson_append_start_object(&bshits1, "$fields");
4919     bson_append_int(&bshits1, "arrefs.0.name", 0);
4920     bson_append_finish_object(&bshits1);
4921     bson_finish(&bshits1);
4922     CU_ASSERT_FALSE_FATAL(bshits1.err);
4923
4924     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshits1);
4925     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
4926
4927     count = 0;
4928     log = tcxstrnew();
4929     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
4930     //fprintf(stderr, "%s", TCXSTRPTR(log));
4931     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
4932     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "FIELD: arrefs HAS $do OPERATION"));
4933     CU_ASSERT_EQUAL(count, 1);
4934
4935     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
4936         bson_type bt;
4937         bson_iterator it;
4938         bson_iterator_from_buffer(&it, TCLISTVALPTR(q1res, i));
4939         CU_ASSERT_FALSE(bson_compare_string("c2", TCLISTVALPTR(q1res, i), "name"));
4940         bt = bson_find_fieldpath_value("arrefs.0.name", &it);
4941         CU_ASSERT_TRUE(bt == BSON_EOO);
4942         CU_ASSERT_FALSE(bson_compare_string("n2", TCLISTVALPTR(q1res, i), "arrefs.1.name"));
4943     }
4944
4945     tclistdel(q1res);
4946     ejdbquerydel(q1);
4947     bson_destroy(&bsq1);
4948     bson_destroy(&bshits1);
4949     tcxstrdel(log);
4950 }
4951
4952 void testTicket54(void) {
4953     EJCOLL *coll = ejdbcreatecoll(jb, "ticket54", NULL);
4954     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4955     bson b;
4956     bson_oid_t oid;
4957     bson_init(&b);
4958     bson_append_long(&b, "value", -10000000L);
4959     bson_finish(&b);
4960     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
4961     bson_destroy(&b);
4962     CU_ASSERT_TRUE(ejdbsetindex(coll, "value", JBIDXNUM));
4963 }
4964
4965 void testMetaInfo(void) {
4966     bson *meta = ejdbmeta(jb);
4967     CU_ASSERT_PTR_NOT_NULL_FATAL(meta);
4968     const char *metabsdata = bson_data(meta);
4969     CU_ASSERT_FALSE(bson_compare_string("dbt2", metabsdata, "file"));
4970     CU_ASSERT_FALSE(bson_compare_string("contacts", metabsdata, "collections.1.name"));
4971     CU_ASSERT_FALSE(bson_compare_string("dbt2_contacts", metabsdata, "collections.1.file"));
4972     CU_ASSERT_FALSE(bson_compare_long(131071, metabsdata, "collections.1.options.buckets"));
4973     CU_ASSERT_FALSE(bson_compare_long(8, metabsdata, "collections.1.records"));
4974     bson_del(meta);
4975 }
4976
4977 void testTicket81(void) {
4978     EJCOLL *coll = ejdbcreatecoll(jb, "ticket81", NULL);
4979     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
4980
4981     bson b;
4982     bson_oid_t oid;
4983
4984     bson_init(&b); //true
4985     bson_append_int(&b, "z", 33);
4986     bson_append_int(&b, "a", 1);
4987     bson_append_int(&b, "b", 3);
4988     bson_append_int(&b, "c", 10);
4989     bson_append_int(&b, "d", 7);
4990     bson_finish(&b);
4991     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
4992     bson_destroy(&b);
4993
4994     bson_init(&b); //false
4995     bson_append_int(&b, "z", 33);
4996     bson_append_int(&b, "a", 11);
4997     bson_append_int(&b, "b", 22);
4998     bson_append_int(&b, "c", 5);
4999     bson_append_int(&b, "d", 7);
5000     bson_finish(&b);
5001     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5002     bson_destroy(&b);
5003
5004     bson_init(&b); //true
5005     bson_append_int(&b, "z", 33);
5006     bson_append_int(&b, "b", 2);
5007     bson_append_int(&b, "d", 7);
5008     bson_finish(&b);
5009     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5010     bson_destroy(&b);
5011
5012     bson_init(&b); //false
5013     bson_append_int(&b, "z", 22);
5014     bson_append_int(&b, "a", 1);
5015     bson_append_int(&b, "b", 3);
5016     bson_append_int(&b, "c", 10);
5017     bson_append_int(&b, "d", 7);
5018     bson_finish(&b);
5019     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5020     bson_destroy(&b);
5021
5022     //z=33 AND (a=1 OR b=2) AND (c=5 OR d=7)
5023     //{z : 33, $and : [ {$or : [{a : 1}, {b : 2}]}, {$or : [{c : 5}, {d : 7}]} ] }
5024     bson_init_as_query(&b);
5025     bson_append_int(&b, "z", 33);
5026     bson_append_start_array(&b, "$and");
5027
5028     //{$or : [{a : 1}, {b : 2}]}
5029     bson_append_start_object(&b, "0");
5030     bson_append_start_array(&b, "$or");
5031     //{a : 1}
5032     bson_append_start_object(&b, "0");
5033     bson_append_int(&b, "a", 1);
5034     bson_append_finish_object(&b);
5035     //{b : 2}
5036     bson_append_start_object(&b, "1");
5037     bson_append_int(&b, "b", 2);
5038     bson_append_finish_object(&b);
5039     bson_append_finish_array(&b);
5040     bson_append_finish_object(&b); //eof {$or : [{a : 1}, {b : 2}]}
5041
5042     //{$or : [{c : 5}, {d : 7}]}
5043     bson_append_start_object(&b, "1");
5044     bson_append_start_array(&b, "$or");
5045     //{c : 5}
5046     bson_append_start_object(&b, "0");
5047     bson_append_int(&b, "c", 5);
5048     bson_append_finish_object(&b);
5049     //{d : 7}
5050     bson_append_start_object(&b, "1");
5051     bson_append_int(&b, "d", 7);
5052     bson_append_finish_object(&b);
5053     bson_append_finish_array(&b);
5054     bson_append_finish_object(&b); //eof {$or : [{c : 5}, {d : 7}]}
5055     bson_append_finish_array(&b); //eof $and
5056     bson_finish(&b);
5057
5058     TCXSTR *log = tcxstrnew();
5059     uint32_t count = 0;
5060     EJQ *q1 = ejdbcreatequery(jb, &b, NULL, 0, NULL);
5061     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5062     bson_destroy(&b);
5063
5064     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
5065     //fprintf(stderr, "%s", TCXSTRPTR(log));
5066     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
5067     CU_ASSERT_EQUAL(count, 2);
5068     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "ACTIVE CONDITIONS: 1"));
5069     CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "$AND QUERIES: 2"));
5070
5071     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
5072         //z=33 AND (a=1 OR b=2) AND (c=5 OR d=7)
5073         CU_ASSERT_FALSE(bson_compare_long(33, TCLISTVALPTR(q1res, i), "z"));
5074         CU_ASSERT_TRUE(!bson_compare_long(1, TCLISTVALPTR(q1res, i), "a") || !bson_compare_long(2, TCLISTVALPTR(q1res, i), "b"));
5075         CU_ASSERT_TRUE(!bson_compare_long(5, TCLISTVALPTR(q1res, i), "c") || !bson_compare_long(7, TCLISTVALPTR(q1res, i), "d"));
5076     }
5077     tclistdel(q1res);
5078     ejdbquerydel(q1);
5079     bson_destroy(&b);
5080     tcxstrdel(log);
5081 }
5082
5083 // $(projection)
5084 // https://github.com/Softmotions/ejdb/issues/15
5085 // http://docs.mongodb.org/manual/reference/projection/positional/#proj._S_
5086
5087 void testDQprojection(void) {
5088     EJCOLL *coll = ejdbcreatecoll(jb, "f_projection", NULL);
5089     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
5090
5091     bson b;
5092     bson_oid_t oid;
5093
5094     bson_init(&b);
5095     bson_append_int(&b, "z", 33);
5096     bson_append_start_array(&b, "arr");
5097     bson_append_int(&b, "0", 0);
5098     bson_append_int(&b, "1", 1);
5099     bson_append_int(&b, "2", 2);
5100     bson_append_int(&b, "3", 3);
5101     bson_append_finish_array(&b);
5102     bson_finish(&b);
5103     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5104     bson_destroy(&b);
5105
5106     bson_init(&b);
5107     bson_append_int(&b, "z", 33);
5108     bson_append_start_array(&b, "arr");
5109     bson_append_int(&b, "0", 3);
5110     bson_append_int(&b, "1", 2);
5111     bson_append_int(&b, "2", 1);
5112     bson_append_int(&b, "3", 0);
5113     bson_append_finish_array(&b);
5114     bson_finish(&b);
5115     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5116     bson_destroy(&b);
5117
5118     bson_init(&b);
5119     bson_append_int(&b, "z", 44);
5120     bson_append_start_array(&b, "arr");
5121     bson_append_start_object(&b, "0");
5122     bson_append_int(&b, "h", 1);
5123     bson_append_finish_object(&b);
5124     bson_append_start_object(&b, "1");
5125     bson_append_int(&b, "h", 2);
5126     bson_append_finish_object(&b);
5127     bson_append_finish_array(&b);
5128     bson_finish(&b);
5129     //bson_print_raw(bson_data(&b), 0);
5130     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5131     bson_destroy(&b);
5132
5133 //////// Q1
5134     bson bshints;
5135     bson_init_as_query(&bshints);
5136     bson_append_start_object(&bshints, "$fields");
5137     bson_append_int(&bshints, "arr.$", 1);
5138     bson_append_finish_object(&bshints);
5139     bson_finish(&bshints);
5140     CU_ASSERT_FALSE_FATAL(bshints.err);
5141
5142     bson bsq1;
5143     bson_init_as_query(&bsq1);
5144     bson_append_int(&bsq1, "z", 33);
5145     bson_append_start_object(&bsq1, "arr");
5146     bson_append_int(&bsq1, "$gte", 2);
5147     bson_append_finish_object(&bsq1);
5148     bson_finish(&bsq1);
5149
5150     TCXSTR *log = tcxstrnew();
5151     uint32_t count;
5152     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
5153     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5154     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
5155     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 2);
5156     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
5157         CU_ASSERT_TRUE(!bson_compare_long(2, TCLISTVALPTR(q1res, i), "arr.0") || !bson_compare_long(3, TCLISTVALPTR(q1res, i), "arr.0"));
5158     }
5159
5160     tclistdel(q1res);
5161     ejdbquerydel(q1);
5162     tcxstrdel(log);
5163     bson_destroy(&bshints);
5164     bson_destroy(&bsq1);
5165
5166     /////// Q2
5167     bson_init_as_query(&bshints);
5168     bson_append_start_object(&bshints, "$fields");
5169     bson_append_int(&bshints, "arr.$.h", 1);
5170     bson_append_finish_object(&bshints);
5171     bson_finish(&bshints);
5172     CU_ASSERT_FALSE_FATAL(bshints.err);
5173
5174     bson_init_as_query(&bsq1);
5175     bson_append_int(&bsq1, "z", 44);
5176     bson_append_int(&bsq1, "arr.h", 2);
5177     bson_finish(&bsq1);
5178
5179     log = tcxstrnew();
5180     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
5181     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5182     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
5183     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
5184     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
5185         CU_ASSERT_FALSE(bson_compare_long(2, TCLISTVALPTR(q1res, i), "arr.0.h"));
5186     }
5187     tclistdel(q1res);
5188     ejdbquerydel(q1);
5189     tcxstrdel(log);
5190     bson_destroy(&bshints);
5191     bson_destroy(&bsq1);
5192
5193
5194     /////// Q3
5195     bson_init_as_query(&bshints);
5196     bson_append_start_object(&bshints, "$fields");
5197     bson_append_int(&bshints, "arr.$.h", 1);
5198     bson_append_finish_object(&bshints);
5199     bson_finish(&bshints);
5200     CU_ASSERT_FALSE_FATAL(bshints.err);
5201
5202     //{z: 44, arr: {$elemMatch: {h: 2}} }
5203     bson_init_as_query(&bsq1);
5204     bson_append_int(&bsq1, "z", 44);
5205     bson_append_start_object(&bsq1, "arr");
5206     bson_append_start_object(&bsq1, "$elemMatch");
5207     bson_append_int(&bsq1, "h", 2);
5208     bson_append_finish_object(&bsq1);
5209     bson_append_finish_object(&bsq1);
5210     bson_finish(&bsq1);
5211
5212     log = tcxstrnew();
5213     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, &bshints);
5214     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5215     q1res = ejdbqryexecute(coll, q1, &count, 0, log);
5216     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
5217     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
5218         CU_ASSERT_FALSE(bson_compare_long(2, TCLISTVALPTR(q1res, i), "arr.0.h"));
5219     }
5220     tclistdel(q1res);
5221     ejdbquerydel(q1);
5222     tcxstrdel(log);
5223     bson_destroy(&bshints);
5224     bson_destroy(&bsq1);
5225 }
5226
5227 void testTicket96(void) {
5228     EJCOLL *coll = ejdbgetcoll(jb, "f_projection");
5229     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
5230
5231     //{ $and : [ {arr : {$elemMatch : {h : 2}}} ]
5232     bson bsq1;
5233     bson_init_as_query(&bsq1);
5234     bson_append_start_array(&bsq1, "$and");
5235     bson_append_start_object(&bsq1, "0");
5236     bson_append_start_object(&bsq1, "arr");
5237     bson_append_start_object(&bsq1, "$elemMatch");
5238     bson_append_int(&bsq1, "h", 2);
5239     bson_append_finish_object(&bsq1);
5240     bson_append_finish_object(&bsq1);
5241     bson_append_finish_object(&bsq1);
5242     bson_append_finish_array(&bsq1);
5243     bson_finish(&bsq1);
5244
5245     CU_ASSERT_EQUAL(bsq1.err, 0);
5246
5247     TCXSTR *log = tcxstrnew();
5248     uint32_t count;
5249     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
5250     bson_destroy(&bsq1);
5251     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5252     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
5253     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
5254
5255     tclistdel(q1res);
5256     ejdbquerydel(q1);
5257     tcxstrdel(log);
5258 }
5259
5260
5261 // $(query)
5262 // https://github.com/Softmotions/ejdb/issues/15
5263 // http://docs.mongodb.org/manual/reference/projection/positional/#proj._S_
5264
5265 void testDQupdate(void) {
5266     EJCOLL *coll = ejdbcreatecoll(jb, "f_update", NULL);
5267     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
5268
5269     bson b;
5270     bson_oid_t oid;
5271
5272     bson_init(&b);
5273     bson_append_int(&b, "z", 33);
5274     bson_append_start_array(&b, "arr");
5275     bson_append_int(&b, "0", 0);
5276     bson_append_int(&b, "1", 1);
5277     bson_append_int(&b, "2", 2);
5278     bson_append_int(&b, "3", 3);
5279     bson_append_finish_array(&b);
5280     bson_finish(&b);
5281     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5282     bson_destroy(&b);
5283
5284     bson bsq1;
5285     bson_init_as_query(&bsq1);
5286     bson_append_int(&bsq1, "z", 33);
5287     bson_append_int(&bsq1, "arr", 1);
5288     bson_append_start_object(&bsq1, "$set");
5289     bson_append_int(&bsq1, "arr.$", 4);
5290     bson_append_finish_object(&bsq1);
5291     bson_finish(&bsq1);
5292
5293     TCXSTR *log = tcxstrnew();
5294     uint32_t count;
5295     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
5296     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5297     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
5298     CU_ASSERT_EQUAL(count, 1);
5299
5300     ejdbquerydel(q1);
5301     tcxstrdel(log);
5302     bson_destroy(&bsq1);
5303
5304     //Now check It
5305     bson_init_as_query(&bsq1);
5306     bson_append_int(&bsq1, "z", 33);
5307     bson_append_int(&bsq1, "arr", 4);
5308     bson_finish(&bsq1);
5309
5310     log = tcxstrnew();
5311     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
5312     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5313     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
5314     CU_ASSERT_EQUAL(count, 1);
5315
5316     ejdbquerydel(q1);
5317     tcxstrdel(log);
5318     bson_destroy(&bsq1);
5319
5320 }
5321
5322 void testDQupdate2(void) {
5323     EJCOLL *coll = ejdbcreatecoll(jb, "f_update", NULL);
5324     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
5325
5326     bson b;
5327     bson_oid_t oid;
5328
5329     bson_init(&b);
5330     bson_append_int(&b, "z", 44);
5331     bson_append_start_array(&b, "arr");
5332     bson_append_start_object(&b, "0");
5333     bson_append_int(&b, "h", 1);
5334     bson_append_finish_object(&b);
5335     bson_append_start_object(&b, "1");
5336     bson_append_int(&b, "h", 2);
5337     bson_append_finish_object(&b);
5338     bson_append_finish_array(&b);
5339     bson_finish(&b);
5340     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5341     bson_destroy(&b);
5342
5343     bson bsq1;
5344     bson_init_as_query(&bsq1);
5345     bson_append_int(&bsq1, "z", 44);
5346     bson_append_int(&bsq1, "arr.h", 2);
5347     bson_append_start_object(&bsq1, "$set");
5348     bson_append_int(&bsq1, "arr.$.h", 4);
5349     bson_append_int(&bsq1, "arr.$.z", 5);
5350     bson_append_int(&bsq1, "k", 55);
5351     bson_append_finish_object(&bsq1);
5352     bson_finish(&bsq1);
5353
5354     TCXSTR *log = tcxstrnew();
5355     uint32_t count;
5356     EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
5357     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5358     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
5359     CU_ASSERT_EQUAL(count, 1);
5360
5361     ejdbquerydel(q1);
5362     tcxstrdel(log);
5363     bson_destroy(&bsq1);
5364
5365     //Now check It
5366     bson_init_as_query(&bsq1);
5367     bson_append_int(&bsq1, "k", 55);
5368     bson_append_int(&bsq1, "arr.h", 4);
5369     bson_append_int(&bsq1, "arr.z", 5);
5370     bson_finish(&bsq1);
5371
5372     log = tcxstrnew();
5373     q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
5374     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5375     ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log);
5376     CU_ASSERT_EQUAL(count, 1);
5377
5378     ejdbquerydel(q1);
5379     tcxstrdel(log);
5380     bson_destroy(&bsq1);
5381 }
5382
5383 void testTicket99(void) {
5384     EJCOLL *coll = ejdbcreatecoll(jb, "ticket99", NULL);
5385     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
5386
5387     //create
5388     bson_oid_t oid;
5389     bson data;
5390     bson_init(&data);
5391     bson_append_start_array(&data, "arr");
5392     bson_append_start_object(&data, "0");
5393     bson_append_string(&data, "test0", "value");
5394     bson_append_finish_object(&data);
5395     bson_append_finish_array(&data);
5396     bson_append_finish_array(&data);
5397     bson_finish(&data);
5398     CU_ASSERT_TRUE(ejdbsavebson(coll, &data, &oid));
5399     bson_destroy(&data);
5400
5401     //set
5402     bson bsquery;
5403     bson_init_as_query(&bsquery);
5404     bson_append_oid(&bsquery, "_id", &oid);
5405     bson_append_start_object(&bsquery, "$set");
5406     bson_append_string(&bsquery, "arr.0.test0", "value0");
5407     bson_append_string(&bsquery, "arr.0.test1", "value1");
5408     bson_append_string(&bsquery, "arr.0.test2", "value2");
5409     bson_append_string(&bsquery, "arr.0.test3", "value3");
5410     bson_append_string(&bsquery, "arr.0.test4", "value4");
5411     bson_append_finish_object(&bsquery);
5412     bson_finish(&bsquery);
5413
5414     uint32_t count = ejdbupdate(coll, &bsquery, 0, 0, 0, 0);
5415     CU_ASSERT_EQUAL(count, 1);
5416     bson_destroy(&bsquery);
5417
5418     bson_init_as_query(&bsquery);
5419     bson_finish(&bsquery);
5420     EJQ *q1 = ejdbcreatequery(jb, &bsquery, NULL, 0, NULL);
5421     bson_destroy(&bsquery);
5422     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5423     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, NULL);
5424     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
5425
5426     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
5427         CU_ASSERT_FALSE(bson_compare_string("value0", TCLISTVALPTR(q1res, i), "arr.0.test0"));
5428         CU_ASSERT_FALSE(bson_compare_string("value1", TCLISTVALPTR(q1res, i), "arr.0.test1"));
5429         CU_ASSERT_FALSE(bson_compare_string("value2", TCLISTVALPTR(q1res, i), "arr.0.test2"));
5430         CU_ASSERT_FALSE(bson_compare_string("value3", TCLISTVALPTR(q1res, i), "arr.0.test3"));
5431         CU_ASSERT_FALSE(bson_compare_string("value4", TCLISTVALPTR(q1res, i), "arr.0.test4"));
5432     }
5433
5434     tclistdel(q1res);
5435     ejdbquerydel(q1);
5436 }
5437
5438
5439 void testTicket101(void) {
5440     EJCOLL *coll = ejdbcreatecoll(jb, "ticket101", NULL);
5441     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
5442
5443     bson b;
5444     bson_oid_t oid;
5445
5446     bson_init(&b);
5447     bson_append_int(&b, "z", 33);
5448     bson_append_start_object(&b, "obj");
5449     bson_append_string(&b, "name", "abc");
5450     bson_append_int(&b, "score", 12);
5451     bson_append_finish_object(&b); //eof obj
5452     bson_append_start_array(&b, "arr");
5453     bson_append_int(&b, "0", 0);
5454     bson_append_start_object(&b, "1");
5455     bson_append_string(&b, "name", "cde");
5456     bson_append_int(&b, "score", 13);
5457     bson_append_finish_object(&b);
5458     bson_append_int(&b, "2", 2);
5459     bson_append_int(&b, "3", 3);
5460     bson_append_finish_array(&b); //eof arr
5461     bson_finish(&b);
5462     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5463     bson_destroy(&b);
5464
5465     bson bsq;
5466     bson_init_as_query(&bsq);
5467     bson_append_start_object(&bsq, "$unset");
5468     bson_append_string(&bsq, "obj.name", "");
5469     bson_append_bool(&bsq, "arr.1.score", true);
5470     bson_append_bool(&bsq, "arr.2", true);
5471     bson_append_finish_object(&bsq);
5472     bson_finish(&bsq);
5473
5474     uint32_t count = ejdbupdate(coll, &bsq, 0, 0, 0, 0);
5475     bson_destroy(&bsq);
5476     CU_ASSERT_EQUAL(count, 1);
5477
5478
5479     bson_init_as_query(&bsq);
5480     bson_finish(&bsq);
5481     EJQ *q1 = ejdbcreatequery(jb, &bsq, NULL, 0, NULL);
5482     bson_destroy(&bsq);
5483     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5484     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, NULL);
5485     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
5486
5487     bson_type bt;
5488     bson_iterator it;
5489     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
5490         CU_ASSERT_FALSE(bson_compare_long(33,  TCLISTVALPTR(q1res, i), "z"));
5491         CU_ASSERT_FALSE(bson_compare_long(12,  TCLISTVALPTR(q1res, i), "obj.score"));
5492         bson_iterator_from_buffer(&it, TCLISTVALPTR(q1res, i));
5493         bt = bson_find_fieldpath_value("obj.name", &it);
5494         CU_ASSERT_TRUE(bt == BSON_EOO);
5495         bson_iterator_from_buffer(&it, TCLISTVALPTR(q1res, i));
5496         bt = bson_find_fieldpath_value("arr.2", &it);
5497         CU_ASSERT_TRUE(bt == BSON_UNDEFINED);
5498     }
5499
5500     tclistdel(q1res);
5501     ejdbquerydel(q1);
5502 }
5503
5504 void testTicket110(void) {
5505         EJCOLL *coll = ejdbcreatecoll(jb, "ticket110", NULL);
5506     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
5507         
5508         bson b;
5509     bson_oid_t oid;
5510
5511     bson_init(&b);
5512         bson_append_string(&b, "comment", "One");
5513         bson_append_string(&b, "status", "New");
5514         bson_append_int(&b, "xversion", 0);
5515         bson_append_int(&b, "value",  9855);
5516         bson_append_string(&b, "title", "Lead 0");
5517     bson_finish(&b);
5518     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5519     bson_destroy(&b);
5520         
5521         bson_init(&b);
5522         bson_append_string(&b, "comment", "Two");
5523         bson_append_string(&b, "status", "New");
5524         bson_append_int(&b, "xversion", 0);
5525         bson_append_string(&b, "value",  "18973");
5526         bson_append_string(&b, "title", "Lead 1");
5527     bson_finish(&b);
5528     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5529     bson_destroy(&b);
5530
5531         bson_init(&b);
5532         bson_append_string(&b, "comment", "Three");
5533         bson_append_string(&b, "status", "New");
5534         bson_append_int(&b, "xversion", 0);
5535         bson_append_string(&b, "value",  "25504");
5536         bson_append_string(&b, "title", "Lead 2");
5537     bson_finish(&b);
5538     CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid));
5539     bson_destroy(&b);
5540
5541         
5542         //   
5543         bson bsq;
5544     bson_init_as_query(&bsq);
5545         bson_finish(&bsq);
5546         CU_ASSERT_FALSE_FATAL(bsq.err);
5547
5548         //
5549         bson bshints;
5550     bson_init_as_query(&bshints);
5551     bson_append_start_object(&bshints, "$orderby");
5552     bson_append_int(&bshints, "value", -1);
5553     bson_append_finish_object(&bshints);
5554     bson_finish(&bshints);
5555     CU_ASSERT_FALSE_FATAL(bshints.err);
5556         
5557         EJQ *q1 = ejdbcreatequery(jb, &bsq, NULL, 0, &bshints);
5558     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5559         
5560         uint32_t count = 0;
5561     TCXSTR *log = tcxstrnew();
5562     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
5563         
5564         bson_destroy(&bsq);
5565         bson_destroy(&bshints);
5566         
5567         tclistdel(q1res);
5568         tcxstrdel(log);
5569         ejdbquerydel(q1);
5570 }
5571
5572 // Ticket #14
5573 void testSlice(void) {
5574         EJCOLL *coll = ejdbgetcoll(jb, "f_projection");
5575     CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
5576         
5577         bson_iterator it;
5578         
5579 // { z : 44, $do : { arr : {$slice : 1} } }
5580         bson bsq;
5581     bson_init_as_query(&bsq);
5582     bson_append_int(&bsq, "z", 44);
5583     bson_append_start_object(&bsq, "$do");
5584     bson_append_start_object(&bsq, "arr");
5585     bson_append_int(&bsq, "$slice", 1);
5586     bson_append_finish_object(&bsq);
5587     bson_append_finish_object(&bsq);
5588     bson_finish(&bsq);
5589     CU_ASSERT_FALSE_FATAL(bsq.err);
5590         
5591         EJQ *q1 = ejdbcreatequery(jb, &bsq, NULL, 0, NULL);
5592     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5593         
5594         uint32_t count = 0;
5595     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, NULL);
5596         //fprintf(stderr, "\n%s", TCXSTRPTR(log));
5597         CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
5598     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
5599                 void *bsdata = TCLISTVALPTR(q1res, i);
5600         CU_ASSERT_PTR_NOT_NULL_FATAL(bsdata);
5601         CU_ASSERT_FALSE(bson_compare_long(1, bsdata, "arr.0.h"));
5602                 bson_iterator_from_buffer(&it, bsdata);
5603                 CU_ASSERT_TRUE(bson_find_fieldpath_value("arr.1.h", &it) == BSON_EOO);
5604     }
5605         tclistdel(q1res);
5606         bson_destroy(&bsq);
5607         ejdbquerydel(q1);
5608         
5609         // { z : 44, $do : { arr : {$slice : 2} } }
5610         bson_init_as_query(&bsq);
5611     bson_append_int(&bsq, "z", 44);
5612     bson_append_start_object(&bsq, "$do");
5613     bson_append_start_object(&bsq, "arr");
5614     bson_append_int(&bsq, "$slice", 2);
5615     bson_append_finish_object(&bsq);
5616     bson_append_finish_object(&bsq);
5617     bson_finish(&bsq);
5618     CU_ASSERT_FALSE_FATAL(bsq.err);
5619         
5620         q1 = ejdbcreatequery(jb, &bsq, NULL, 0, NULL);
5621     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5622         
5623         count = 0;
5624     q1res = ejdbqryexecute(coll, q1, &count, 0, NULL);
5625         CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
5626         CU_ASSERT_EQUAL(count, 1);
5627     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
5628                 void *bsdata = TCLISTVALPTR(q1res, i);
5629         CU_ASSERT_PTR_NOT_NULL_FATAL(bsdata);
5630         CU_ASSERT_FALSE(bson_compare_long(1, bsdata, "arr.0.h"));
5631         CU_ASSERT_FALSE(bson_compare_long(2, bsdata, "arr.1.h"));
5632                 bson_iterator_from_buffer(&it, bsdata);
5633                 CU_ASSERT_TRUE(bson_find_fieldpath_value("arr.2.h", &it) == BSON_EOO);
5634     }
5635         tclistdel(q1res);
5636         bson_destroy(&bsq);
5637         ejdbquerydel(q1);
5638         
5639         // { $do : { arr : {$slice : [1, 2]} } }
5640         bson_init_as_query(&bsq);
5641     bson_append_start_object(&bsq, "$do");
5642     bson_append_start_object(&bsq, "arr");
5643     bson_append_start_array(&bsq, "$slice");
5644         bson_append_int(&bsq, "0", 1);
5645         bson_append_int(&bsq, "1", 2);
5646         bson_append_finish_array(&bsq);
5647     bson_append_finish_object(&bsq);
5648     bson_append_finish_object(&bsq);
5649     bson_finish(&bsq);
5650     CU_ASSERT_FALSE_FATAL(bsq.err);
5651         
5652         q1 = ejdbcreatequery(jb, &bsq, NULL, 0, NULL);
5653     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5654         
5655         count = 0;
5656     q1res = ejdbqryexecute(coll, q1, &count, 0, NULL);
5657         CU_ASSERT_EQUAL(TCLISTNUM(q1res), 3);
5658         CU_ASSERT_EQUAL(count, 3);
5659     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
5660                 void *bsdata = TCLISTVALPTR(q1res, i);
5661         CU_ASSERT_PTR_NOT_NULL_FATAL(bsdata);
5662                 if (i == 0) {
5663                         CU_ASSERT_FALSE(bson_compare_long(1, bsdata, "arr.0"));
5664                         CU_ASSERT_FALSE(bson_compare_long(2, bsdata, "arr.1"));
5665                         bson_iterator_from_buffer(&it, bsdata);
5666                         CU_ASSERT_TRUE(bson_find_fieldpath_value("arr.2", &it) == BSON_EOO);
5667                 } else if (i == 1) {
5668                         CU_ASSERT_FALSE(bson_compare_long(2, bsdata, "arr.0"));
5669                         CU_ASSERT_FALSE(bson_compare_long(1, bsdata, "arr.1"));
5670                         bson_iterator_from_buffer(&it, bsdata);
5671                         CU_ASSERT_TRUE(bson_find_fieldpath_value("arr.2", &it) == BSON_EOO);
5672                 } else if (i == 2) {
5673                         CU_ASSERT_FALSE(bson_compare_long(2, bsdata, "arr.0.h"));
5674                         bson_iterator_from_buffer(&it, bsdata);
5675                         CU_ASSERT_TRUE(bson_find_fieldpath_value("arr.1", &it) == BSON_EOO);
5676                 }
5677     }
5678         tclistdel(q1res);
5679         bson_destroy(&bsq);
5680         ejdbquerydel(q1);
5681         
5682         
5683         
5684 //{ _id: '54d7a2f07e671e140000001f',
5685 //  z: 33,
5686 //  arr: [ 0, 1, 2, 3 ] }
5687 //{ _id: '54d7a2f07e671e1400000020',
5688 //  z: 33,
5689 //  arr: [ 3, 2, 1, 0 ] }
5690 //{ _id: '54d7a2f07e671e1400000021',
5691 //  z: 44,
5692 //  arr: [ { h: 1 }, { h: 2 } ] } 
5693         
5694         // { $do : { arr : {$slice : [-3, 1]} } }
5695         bson_init_as_query(&bsq);
5696     bson_append_start_object(&bsq, "$do");
5697     bson_append_start_object(&bsq, "arr");
5698     bson_append_start_array(&bsq, "$slice");
5699         bson_append_int(&bsq, "0", -3);
5700         bson_append_int(&bsq, "1", 1);
5701         bson_append_finish_array(&bsq);
5702     bson_append_finish_object(&bsq);
5703     bson_append_finish_object(&bsq);
5704     bson_finish(&bsq);
5705     CU_ASSERT_FALSE_FATAL(bsq.err);
5706         
5707         q1 = ejdbcreatequery(jb, &bsq, NULL, 0, NULL);
5708     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5709         
5710         count = 0;
5711     q1res = ejdbqryexecute(coll, q1, &count, 0, NULL);
5712         CU_ASSERT_EQUAL(TCLISTNUM(q1res), 3);
5713         CU_ASSERT_EQUAL(count, 3);
5714     for (int i = 0; i < TCLISTNUM(q1res); ++i) {
5715                 void *bsdata = TCLISTVALPTR(q1res, i);
5716         CU_ASSERT_PTR_NOT_NULL_FATAL(bsdata);
5717                 if (i == 0) {
5718                         CU_ASSERT_FALSE(bson_compare_long(1, bsdata, "arr.0"));
5719                         bson_iterator_from_buffer(&it, bsdata);
5720                         CU_ASSERT_TRUE(bson_find_fieldpath_value("arr.1", &it) == BSON_EOO);
5721                 } else if (i == 1) {
5722                         CU_ASSERT_FALSE(bson_compare_long(2, bsdata, "arr.0"));
5723                         bson_iterator_from_buffer(&it, bsdata);
5724                         CU_ASSERT_TRUE(bson_find_fieldpath_value("arr.1", &it) == BSON_EOO);
5725                 } else if (i == 2) {
5726                         CU_ASSERT_FALSE(bson_compare_long(2, bsdata, "arr.0.h"));
5727                         bson_iterator_from_buffer(&it, bsdata);
5728                         CU_ASSERT_TRUE(bson_find_fieldpath_value("arr.1", &it) == BSON_EOO);
5729                 }
5730     }
5731         tclistdel(q1res);
5732         bson_destroy(&bsq);
5733         ejdbquerydel(q1);
5734 }
5735
5736
5737 void testDistinct(void) {
5738     EJCOLL *contacts = ejdbcreatecoll(jb, "contacts", NULL);
5739     CU_ASSERT_PTR_NOT_NULL_FATAL(contacts);
5740
5741     uint32_t count;
5742     TCXSTR *log;
5743     bson *q1res; 
5744
5745     log = tcxstrnew();
5746     q1res = ejdbqrydistinct(contacts, "address", NULL, NULL, 0, &count, log);
5747
5748     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
5749     CU_ASSERT_EQUAL(count, 4);
5750     
5751     bson_del(q1res);
5752     
5753     bson bsq1;
5754     bson_init_as_query(&bsq1);
5755     bson_append_string(&bsq1, "address.street", "Pirogova");
5756     bson_finish(&bsq1);
5757     CU_ASSERT_FALSE_FATAL(bsq1.err);
5758
5759     q1res = ejdbqrydistinct(contacts, "address.room", &bsq1, NULL, 0, &count, log);
5760     
5761     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
5762     CU_ASSERT_EQUAL(count, 1);
5763     
5764     bson_del(q1res);
5765
5766     q1res = ejdbqrydistinct(contacts, "nonexisted", NULL, NULL, 0, &count, log);
5767     
5768     CU_ASSERT_PTR_NOT_NULL_FATAL(q1res);
5769     CU_ASSERT_EQUAL(count, 0);
5770     
5771     bson_del(q1res);
5772
5773     bson_destroy(&bsq1);
5774     tcxstrdel(log);
5775 }
5776
5777
5778 void testTicket117(void) {
5779         EJCOLL *coll = ejdbcreatecoll(jb, "ticket117", NULL);
5780         CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
5781         
5782         bson_oid_t oid;
5783         bson brec;
5784         
5785         bson_init(&brec);
5786     bson_append_string(&brec, "color", "Red");
5787     bson_finish(&brec);
5788     CU_ASSERT_FALSE_FATAL(brec.err);
5789     CU_ASSERT_TRUE_FATAL(ejdbsavebson(coll, &brec, &oid));
5790     bson_destroy(&brec);
5791         
5792         bson_init(&brec);
5793     bson_append_string(&brec, "color", "Green");
5794     bson_finish(&brec);
5795     CU_ASSERT_FALSE_FATAL(brec.err);
5796     CU_ASSERT_TRUE_FATAL(ejdbsavebson(coll, &brec, &oid));
5797     bson_destroy(&brec);
5798         
5799         CU_ASSERT_TRUE_FATAL(ejdbsetindex(coll, "color", JBIDXSTR));
5800         
5801         bson_init(&brec);
5802     bson_append_string(&brec, "color", "Blue");
5803     bson_finish(&brec);
5804     CU_ASSERT_FALSE_FATAL(brec.err);
5805     CU_ASSERT_TRUE_FATAL(ejdbsavebson(coll, &brec, &oid));
5806     bson_destroy(&brec);
5807         
5808         bson bsq;
5809     bson_init_as_query(&bsq);
5810         bson_append_string(&bsq, "color", "Blue");
5811         bson_finish(&bsq);
5812         CU_ASSERT_FALSE_FATAL(bsq.err);
5813         
5814         TCXSTR *log = tcxstrnew();
5815         uint32_t count = 0;
5816         EJQ *q1 = ejdbcreatequery(jb, &bsq, NULL, 0, NULL);
5817     bson_destroy(&bsq);
5818     CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
5819     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
5820         CU_ASSERT_PTR_NOT_NULL(q1res);
5821     CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1);
5822         
5823         for (int i = 0; i < TCLISTNUM(q1res); ++i) {
5824                 void *bsdata = TCLISTVALPTR(q1res, i);
5825         bson_print_raw(bsdata, 0);
5826     }
5827     //fprintf(stderr, "%s", TCXSTRPTR(log));
5828         CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "MAIN IDX: 'scolor'"));
5829         
5830         ejdbquerydel(q1);
5831         tclistdel(q1res);
5832         tcxstrdel(log);
5833 }
5834
5835
5836 int main() {
5837     setlocale(LC_ALL, "en_US.UTF-8");
5838     CU_pSuite pSuite = NULL;
5839
5840     /* Initialize the CUnit test registry */
5841     if (CUE_SUCCESS != CU_initialize_registry())
5842         return CU_get_error();
5843
5844     /* Add a suite to the registry */
5845     pSuite = CU_add_suite("ejdbtest2", init_suite, clean_suite);
5846     if (NULL == pSuite) {
5847         CU_cleanup_registry();
5848         return CU_get_error();
5849     }
5850
5851     /* Add the tests to the suite */
5852     if ((NULL == CU_add_test(pSuite, "testAddData", testAddData)) ||
5853             (NULL == CU_add_test(pSuite, "testInvalidQueries1", testInvalidQueries1)) ||
5854             (NULL == CU_add_test(pSuite, "testSetIndex1", testSetIndex1)) ||
5855             (NULL == CU_add_test(pSuite, "testQuery1", testQuery1)) ||
5856             (NULL == CU_add_test(pSuite, "testQuery2", testQuery2)) ||
5857             (NULL == CU_add_test(pSuite, "testQuery3", testQuery3)) ||
5858             (NULL == CU_add_test(pSuite, "testQuery4", testQuery4)) ||
5859             (NULL == CU_add_test(pSuite, "testQuery5", testQuery5)) ||
5860             (NULL == CU_add_test(pSuite, "testQuery6", testQuery6)) ||
5861             (NULL == CU_add_test(pSuite, "testQuery7", testQuery7)) ||
5862             (NULL == CU_add_test(pSuite, "testQuery8", testQuery8)) ||
5863             (NULL == CU_add_test(pSuite, "testQuery9", testQuery9)) ||
5864             (NULL == CU_add_test(pSuite, "testQuery10", testQuery10)) ||
5865             (NULL == CU_add_test(pSuite, "testQuery11", testQuery11)) ||
5866             (NULL == CU_add_test(pSuite, "testQuery12", testQuery12)) ||
5867             (NULL == CU_add_test(pSuite, "testQuery13", testQuery13)) ||
5868             (NULL == CU_add_test(pSuite, "testQuery14", testQuery14)) ||
5869             (NULL == CU_add_test(pSuite, "testQuery15", testQuery15)) ||
5870             (NULL == CU_add_test(pSuite, "testQuery16", testQuery16)) ||
5871             (NULL == CU_add_test(pSuite, "testQuery17", testQuery17)) ||
5872             (NULL == CU_add_test(pSuite, "testQuery18", testQuery18)) ||
5873             (NULL == CU_add_test(pSuite, "testQuery19", testQuery19)) ||
5874             (NULL == CU_add_test(pSuite, "testQuery20", testQuery20)) ||
5875             (NULL == CU_add_test(pSuite, "testQuery21", testQuery21)) ||
5876             (NULL == CU_add_test(pSuite, "testQuery22", testQuery22)) ||
5877             (NULL == CU_add_test(pSuite, "testQuery23", testQuery23)) ||
5878             (NULL == CU_add_test(pSuite, "testQuery24", testQuery24)) ||
5879             (NULL == CU_add_test(pSuite, "testQuery25", testQuery25)) ||
5880             (NULL == CU_add_test(pSuite, "testQuery25_2", testQuery25_2)) ||
5881             (NULL == CU_add_test(pSuite, "testQuery26", testQuery26)) ||
5882             (NULL == CU_add_test(pSuite, "testQuery27", testQuery27)) ||
5883                         (NULL == CU_add_test(pSuite, "testQuery28", testQuery28)) ||
5884                         (NULL == CU_add_test(pSuite, "testQuery29", testQuery29)) ||
5885                         (NULL == CU_add_test(pSuite, "testQuery30", testQuery30)) ||
5886                         (NULL == CU_add_test(pSuite, "testQuery31", testQuery31)) ||
5887             (NULL == CU_add_test(pSuite, "testOIDSMatching", testOIDSMatching)) ||
5888             (NULL == CU_add_test(pSuite, "testEmptyFieldIndex", testEmptyFieldIndex)) ||
5889             (NULL == CU_add_test(pSuite, "testICaseIndex", testICaseIndex)) ||
5890             (NULL == CU_add_test(pSuite, "testTicket7", testTicket7)) ||
5891             (NULL == CU_add_test(pSuite, "testTicket8", testTicket8)) ||
5892             (NULL == CU_add_test(pSuite, "testUpdate1", testUpdate1)) ||
5893             (NULL == CU_add_test(pSuite, "testUpdate2", testUpdate2)) ||
5894             (NULL == CU_add_test(pSuite, "testUpdate3", testUpdate3)) ||
5895             (NULL == CU_add_test(pSuite, "testQueryBool", testQueryBool)) ||
5896             (NULL == CU_add_test(pSuite, "testDropAll", testDropAll)) ||
5897             (NULL == CU_add_test(pSuite, "testTokensBegin", testTokensBegin)) ||
5898             (NULL == CU_add_test(pSuite, "testOneFieldManyConditions", testOneFieldManyConditions)) ||
5899             (NULL == CU_add_test(pSuite, "testAddToSet", testAddToSet)) ||
5900             (NULL == CU_add_test(pSuite, "testTicket123", testTicket123)) ||
5901             (NULL == CU_add_test(pSuite, "testPull", testPull)) ||
5902             (NULL == CU_add_test(pSuite, "testFindInComplexArray", testFindInComplexArray)) ||
5903             (NULL == CU_add_test(pSuite, "testElemMatch", testElemMatch)) ||
5904             (NULL == CU_add_test(pSuite, "testNotElemMatch", testNotElemMatch)) ||
5905             (NULL == CU_add_test(pSuite, "testTicket16", testTicket16)) ||
5906             (NULL == CU_add_test(pSuite, "testUpsert", testUpsert)) ||
5907             (NULL == CU_add_test(pSuite, "testPrimitiveCases1", testPrimitiveCases1)) ||
5908             (NULL == CU_add_test(pSuite, "testTicket29", testTicket29)) ||
5909             (NULL == CU_add_test(pSuite, "testTicket28", testTicket28)) ||
5910             (NULL == CU_add_test(pSuite, "testTicket38", testTicket38)) ||
5911             (NULL == CU_add_test(pSuite, "testTicket43", testTicket43)) ||
5912             (NULL == CU_add_test(pSuite, "testTicket54", testTicket54)) ||
5913             (NULL == CU_add_test(pSuite, "testTicket88", testTicket88)) ||
5914             (NULL == CU_add_test(pSuite, "testTicket89", testTicket89)) ||
5915             (NULL == CU_add_test(pSuite, "testTicket81", testTicket81)) ||
5916             (NULL == CU_add_test(pSuite, "test$projection", testDQprojection)) ||
5917             (NULL == CU_add_test(pSuite, "test$update", testDQupdate)) ||
5918             (NULL == CU_add_test(pSuite, "test$update2", testDQupdate2)) ||
5919             (NULL == CU_add_test(pSuite, "testTicket96", testTicket96)) ||
5920             (NULL == CU_add_test(pSuite, "testTicket99", testTicket99)) ||
5921             (NULL == CU_add_test(pSuite, "testTicket101", testTicket101)) || 
5922             (NULL == CU_add_test(pSuite, "testTicket110", testTicket110)) ||
5923             (NULL == CU_add_test(pSuite, "testDistinct", testDistinct)) ||
5924                         (NULL == CU_add_test(pSuite, "testSlice", testSlice)) ||
5925                         (NULL == CU_add_test(pSuite, "testTicket117", testTicket117)) ||
5926             (NULL == CU_add_test(pSuite, "testMetaInfo", testMetaInfo))
5927     ) {
5928         CU_cleanup_registry();
5929         return CU_get_error();
5930     }
5931     /* Run all tests using the CUnit Basic interface */
5932     CU_basic_set_mode(CU_BRM_VERBOSE);
5933     CU_basic_run_tests();
5934     int ret = CU_get_error() || CU_get_number_of_failures();
5935     CU_cleanup_registry();
5936     return ret;
5937 }