• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "ejdb_test.h"
2 #include <CUnit/Basic.h>
3 
init_suite()4 int init_suite() {
5   int rc = ejdb_init();
6   return rc;
7 }
8 
clean_suite()9 int clean_suite() {
10   return 0;
11 }
12 
ejdb_test3_1()13 static void ejdb_test3_1() {
14   EJDB_OPTS opts = {
15     .kv       = {
16       .path   = "ejdb_test3_1.db",
17       .oflags = IWKV_TRUNC
18     },
19     .no_wal   = true
20   };
21 
22   EJDB db;
23   char dbuf[1024];
24   EJDB_LIST list = 0;
25   IWXSTR *log = iwxstr_new();
26   CU_ASSERT_PTR_NOT_NULL_FATAL(log);
27   IWXSTR *xstr = iwxstr_new();
28   CU_ASSERT_PTR_NOT_NULL_FATAL(xstr);
29 
30   iwrc rc = ejdb_open(&opts, &db);
31   CU_ASSERT_EQUAL_FATAL(rc, 0);
32 
33   rc = ejdb_ensure_index(db, "c1", "/f/b", EJDB_IDX_UNIQUE | EJDB_IDX_I64);
34   CU_ASSERT_EQUAL_FATAL(rc, 0);
35 
36   for (int i = 1; i <= 10; ++i) {
37     snprintf(dbuf, sizeof(dbuf), "{\"f\":{\"b\":%d},\"n\":%d}", i, i);
38     rc = put_json(db, "c1", dbuf);
39     CU_ASSERT_EQUAL_FATAL(rc, 0);
40     if (i == 1) { // Check unique index constraint violation
41       rc = put_json(db, "c1", dbuf);
42       CU_ASSERT_EQUAL(rc, EJDB_ERROR_UNIQUE_INDEX_CONSTRAINT_VIOLATED);
43     }
44     rc = put_json(db, "c2", dbuf);
45     CU_ASSERT_EQUAL_FATAL(rc, 0);
46   }
47 
48   rc = ejdb_ensure_index(db, "c2", "/f/b", EJDB_IDX_UNIQUE | EJDB_IDX_I64);
49   CU_ASSERT_EQUAL_FATAL(rc, 0);
50 
51   rc = ejdb_list3(db, "c1", "/f/[b = 1]", 0, log, &list);
52   CU_ASSERT_EQUAL_FATAL(rc, 0);
53 
54   CU_ASSERT_PTR_NOT_NULL_FATAL(strstr(iwxstr_ptr(log), "[INDEX] MATCHED  UNIQUE|I64|10 /f/b EXPR1: 'b = 1' "
55                                       "INIT: IWKV_CURSOR_EQ"));
56   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[INDEX] SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b = 1' "
57                                 "INIT: IWKV_CURSOR_EQ"));
58   int i = 0;
59   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
60     iwxstr_clear(xstr);
61     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
62     CU_ASSERT_EQUAL_FATAL(rc, 0);
63     CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":1},\"n\":1}");
64   }
65   ejdb_list_destroy(&list);
66   iwxstr_clear(log);
67 
68   // Q: /f/[b > 1]
69   rc = ejdb_list3(db, "c1", "/f/[b > 1]", 0, log, &list);
70   //if (rc) iwlog_ecode_error3(rc);
71   CU_ASSERT_EQUAL_FATAL(rc, 0);
72   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "MATCHED  UNIQUE|I64|10 /f/b EXPR1: 'b > 1' "
73                                 "INIT: IWKV_CURSOR_GE"));
74   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b > 1' "
75                                 "INIT: IWKV_CURSOR_GE"));
76 
77   i = 0;
78   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
79     iwxstr_clear(xstr);
80     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
81     CU_ASSERT_EQUAL_FATAL(rc, 0);
82     if (i == 0) {
83       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":2},\"n\":2}");
84     } else if (i == 8) {
85       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":10},\"n\":10}");
86     }
87   }
88   CU_ASSERT_EQUAL(i, 9);
89   ejdb_list_destroy(&list);
90   iwxstr_clear(log);
91 
92   // Q: /f/[b >= 2]
93   rc = ejdb_list3(db, "c1", "/f/[b >= 3]", 0, log, &list);
94   CU_ASSERT_EQUAL_FATAL(rc, 0);
95   i = 0;
96   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
97     iwxstr_clear(xstr);
98     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
99     CU_ASSERT_EQUAL_FATAL(rc, 0);
100     if (i == 0) {
101       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":3},\"n\":3}");
102     } else if (i == 8) {
103       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":10},\"n\":10}");
104     }
105   }
106   CU_ASSERT_EQUAL(i, 8);
107   ejdb_list_destroy(&list);
108   iwxstr_clear(log);
109 
110   // Q: /f/[b < 9]
111   rc = ejdb_list3(db, "c1", "/f/[b < 9]", 0, log, &list);
112   CU_ASSERT_EQUAL_FATAL(rc, 0);
113   i = 0;
114   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
115     iwxstr_clear(xstr);
116     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
117     CU_ASSERT_EQUAL_FATAL(rc, 0);
118     if (i == 0) {
119       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":8},\"n\":8}");
120     } else if (i == 7) {
121       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":1},\"n\":1}");
122     }
123   }
124   CU_ASSERT_EQUAL(i, 8);
125   ejdb_list_destroy(&list);
126 
127   // Q: /f/[b < 11]
128   rc = ejdb_list3(db, "c1", "/f/[b < 11]", 0, log, &list);
129   CU_ASSERT_EQUAL_FATAL(rc, 0);
130   i = 0;
131   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
132     iwxstr_clear(xstr);
133     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
134     CU_ASSERT_EQUAL_FATAL(rc, 0);
135     if (i == 0) {
136       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":10},\"n\":10}");
137     } else if (i == 9) {
138       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":1},\"n\":1}");
139     }
140   }
141   ejdb_list_destroy(&list);
142   iwxstr_clear(log);
143 
144   // Q: /f/[b < 11 and b >= 4]
145   rc = ejdb_list3(db, "c1", "/f/[b < 11 and b >= 4]", 0, log, &list);
146   CU_ASSERT_EQUAL_FATAL(rc, 0);
147   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[INDEX] SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b >= 4' EXPR2: 'b < 11' "
148                                 "INIT: IWKV_CURSOR_GE"));
149   i = 0;
150   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
151     iwxstr_clear(xstr);
152     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
153     CU_ASSERT_EQUAL_FATAL(rc, 0);
154     if (i == 0) {
155       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":4},\"n\":4}");
156     } else if (i == 6) {
157       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":10},\"n\":10}");
158     }
159   }
160   ejdb_list_destroy(&list);
161   iwxstr_clear(log);
162 
163   // Q: /f/[b < 11 and b > 0 or b = 0]
164   rc = ejdb_list3(db, "c1", "/f/[b < 11 and b > 0 or b = 0]", 0, log, &list);
165   CU_ASSERT_EQUAL_FATAL(rc, 0);
166   ejdb_list_destroy(&list);
167   iwxstr_clear(log);
168 
169   // Q: /f/[b > 1 and b < 2 and b = 2 and b < 3]
170   rc = ejdb_list3(db, "c1", "/f/[b > 1 and b < 2 and b = 2 and b < 3]", 0, log, &list);
171   CU_ASSERT_EQUAL_FATAL(rc, 0);
172   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
173                                 "[INDEX] SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b = 2' "
174                                 "INIT: IWKV_CURSOR_EQ"));
175   ejdb_list_destroy(&list);
176   iwxstr_clear(log);
177 
178   // Q: /f/[b > 1 and b < 3 and b <= 4]
179   rc = ejdb_list3(db, "c1", "/f/[b > 1 and b < 3 and b <= 4]", 0, log, &list);
180   CU_ASSERT_EQUAL_FATAL(rc, 0);
181   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
182                                 "[INDEX] SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b > 1' EXPR2: 'b < 3' "
183                                 "INIT: IWKV_CURSOR_GE"));
184   i = 0;
185   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
186     iwxstr_clear(xstr);
187     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
188     CU_ASSERT_EQUAL_FATAL(rc, 0);
189     CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":2},\"n\":2}");
190   }
191   CU_ASSERT_EQUAL(i, 1);
192   ejdb_list_destroy(&list);
193   iwxstr_clear(log);
194 
195   // Q: /f/[b > 1] and /f/[b < 3]
196   rc = ejdb_list3(db, "c1", "/f/[b > 1] and /f/[b < 3]", 0, log, &list);
197   CU_ASSERT_EQUAL_FATAL(rc, 0);
198   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
199                                 "[INDEX] MATCHED  UNIQUE|I64|10 /f/b EXPR1: 'b > 1' INIT: IWKV_CURSOR_GE"));
200   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
201                                 "[INDEX] MATCHED  UNIQUE|I64|10 /f/b EXPR1: 'b < 3' INIT: IWKV_CURSOR_GE"));
202   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
203                                 "[INDEX] SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b > 1' INIT: IWKV_CURSOR_GE"));
204   ejdb_list_destroy(&list);
205   iwxstr_clear(log);
206 
207   // Q: /f/[b > 1 or b != 1] and /f/[b < 3]
208   rc = ejdb_list3(db, "c1", "/f/[b > 1 or b != 1] and /f/[b < 3]", 0, log, &list);
209   CU_ASSERT_EQUAL_FATAL(rc, 0);
210   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
211                                 "[INDEX] SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b < 3' "
212                                 "INIT: IWKV_CURSOR_GE"));
213   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[COLLECTOR] PLAIN"));
214   i = 0;
215   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
216     iwxstr_clear(xstr);
217     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
218     CU_ASSERT_EQUAL_FATAL(rc, 0);
219     CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":2},\"n\":2}");
220   }
221   ejdb_list_destroy(&list);
222   iwxstr_clear(log);
223 
224   // Q: /f/[b in [2,1112,4,6]]
225   rc = ejdb_list3(db, "c1", "/f/[b in [2,1112,4,6]]", 0, log, &list);
226   CU_ASSERT_EQUAL_FATAL(rc, 0);
227   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
228                                 "[INDEX] SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b in [2,1112,4,6]' "
229                                 "INIT: IWKV_CURSOR_EQ"));
230   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[COLLECTOR] PLAIN"));
231   i = 0;
232   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
233     iwxstr_clear(xstr);
234     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
235     CU_ASSERT_EQUAL_FATAL(rc, 0);
236     if (i == 0) {
237       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":2},\"n\":2}");
238     } else if (i == 1) {
239       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":4},\"n\":4}");
240     } else if (i == 2) {
241       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":6},\"n\":6}");
242     }
243   }
244   CU_ASSERT_EQUAL(i, 3);
245   ejdb_list_destroy(&list);
246   iwxstr_clear(log);
247 
248   // Q: /f/[b > 1] | asc /f/b
249   rc = ejdb_list3(db, "c1", "/f/[b > 1] | asc /f/b", 0, log, &list);
250   CU_ASSERT_EQUAL_FATAL(rc, 0);
251   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
252                                 "[INDEX] SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b > 1' "
253                                 "INIT: IWKV_CURSOR_GE STEP: IWKV_CURSOR_PREV ORDERBY"));
254   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[COLLECTOR] PLAIN"));
255   i = 0;
256   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
257     iwxstr_clear(xstr);
258     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
259     CU_ASSERT_EQUAL_FATAL(rc, 0);
260     if (i == 0) {
261       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":2},\"n\":2}");
262     } else if (i == 8) {
263       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":10},\"n\":10}");
264     }
265   }
266   CU_ASSERT_EQUAL(i, 9);
267   ejdb_list_destroy(&list);
268   iwxstr_clear(log);
269 
270   // Q: /f/[b > 1] | desc /f/b
271   rc = ejdb_list3(db, "c1", "/f/[b > 1] | desc /f/b", 0, log, &list);
272   CU_ASSERT_EQUAL_FATAL(rc, 0);
273   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
274                                 "[INDEX] SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b > 1' "
275                                 "INIT: IWKV_CURSOR_GE"));
276   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[COLLECTOR] SORTER"));
277   i = 0;
278   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
279     iwxstr_clear(xstr);
280     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
281     CU_ASSERT_EQUAL_FATAL(rc, 0);
282     if (i == 0) {
283       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":10},\"n\":10}");
284     } else if (i == 8) {
285       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":2},\"n\":2}");
286     }
287   }
288   CU_ASSERT_EQUAL(i, 9);
289   ejdb_list_destroy(&list);
290   iwxstr_clear(log);
291 
292   // Q: /f/[b > 2 and b < 10] | asc /f/b
293   rc = ejdb_list3(db, "c1", "/f/[b > 2 and b < 10] | asc /f/b", 0, log, &list);
294   CU_ASSERT_EQUAL_FATAL(rc, 0);
295   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
296                                 "[INDEX] SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b > 2' EXPR2: 'b < 10' "
297                                 "INIT: IWKV_CURSOR_GE STEP: IWKV_CURSOR_PREV ORDERBY"));
298   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[COLLECTOR] PLAIN"));
299   i = 0;
300   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
301     iwxstr_clear(xstr);
302     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
303     CU_ASSERT_EQUAL_FATAL(rc, 0);
304     if (i == 0) {
305       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":3},\"n\":3}");
306     } else if (i == 6) {
307       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":9},\"n\":9}");
308     }
309   }
310   CU_ASSERT_EQUAL(i, 7);
311   ejdb_list_destroy(&list);
312   iwxstr_clear(log);
313 
314   // Q: /f/[b > 2 and b < 10] | desc /f/b
315   rc = ejdb_list3(db, "c1", "/f/[b > 2 and b < 10] | desc /f/b", 0, log, &list);
316   CU_ASSERT_EQUAL_FATAL(rc, 0);
317   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[INDEX] SELECTED UNIQUE|I64|10 /f/b EXPR1: 'b < 10' EXPR2: 'b > 2' "
318                                 "INIT: IWKV_CURSOR_GE STEP: IWKV_CURSOR_NEXT ORDERBY"));
319   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[COLLECTOR] PLAIN"));
320   i = 0;
321   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
322     iwxstr_clear(xstr);
323     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
324     CU_ASSERT_EQUAL_FATAL(rc, 0);
325     if (i == 0) {
326       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":9},\"n\":9}");
327     } else if (i == 6) {
328       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":3},\"n\":3}");
329     }
330   }
331   CU_ASSERT_EQUAL(i, 7);
332   ejdb_list_destroy(&list);
333   iwxstr_clear(log);
334 
335   rc = ejdb_close(&db);
336   CU_ASSERT_EQUAL_FATAL(rc, 0);
337   iwxstr_destroy(log);
338   iwxstr_destroy(xstr);
339 }
340 
ejdb_test3_2()341 static void ejdb_test3_2() {
342   EJDB_OPTS opts = {
343     .kv       = {
344       .path   = "ejdb_test3_2.db",
345       .oflags = IWKV_TRUNC
346     },
347     .no_wal   = true
348   };
349 
350   EJDB db;
351   char dbuf[1024];
352   EJDB_LIST list = 0;
353   int i = 0;
354   IWXSTR *log = iwxstr_new();
355   CU_ASSERT_PTR_NOT_NULL_FATAL(log);
356   IWXSTR *xstr = iwxstr_new();
357   CU_ASSERT_PTR_NOT_NULL_FATAL(xstr);
358 
359   iwrc rc = ejdb_open(&opts, &db);
360   CU_ASSERT_EQUAL_FATAL(rc, 0);
361 
362   rc = ejdb_ensure_index(db, "a1", "/f/b", EJDB_IDX_I64);
363   CU_ASSERT_EQUAL_FATAL(rc, 0);
364 
365   // Data:
366   //
367   //  {"f":{"b":16777215},"n":9}
368   //  {"f":{"b":16777215},"n":7}
369   //  {"f":{"b":16777215},"n":5}
370   //  {"f":{"b":16777215},"n":3}
371   //  {"f":{"b":16777215},"n":1}
372   //  {"f":{"b":127},"n":10}
373   //  {"f":{"b":127},"n":8}
374   //  {"f":{"b":127},"n":6}
375   //  {"f":{"b":127},"n":4}
376   //  {"f":{"b":127},"n":2}
377   //  {"f":{"b":126},"n":12}
378   //  {"f":{"b":126},"n":11}
379   //
380 
381   for (i = 1; i <= 10; ++i) {
382     int v = (i % 2) ? 0xffffff : 127;
383     //fprintf(stderr, "\n{\"f\":{\"b\":%d},\"n\":%d}", v, i);
384     snprintf(dbuf, sizeof(dbuf), "{\"f\":{\"b\":%d},\"n\":%d}", v, i);
385     rc = put_json(db, "a1", dbuf);
386     CU_ASSERT_EQUAL_FATAL(rc, 0);
387   }
388   snprintf(dbuf, sizeof(dbuf), "{\"f\":{\"b\":%d},\"n\":%d}", 126, 11);
389   rc = put_json(db, "a1", dbuf);
390   CU_ASSERT_EQUAL_FATAL(rc, 0);
391   snprintf(dbuf, sizeof(dbuf), "{\"f\":{\"b\":%d},\"n\":%d}", 126, 12);
392   rc = put_json(db, "a1", dbuf);
393   CU_ASSERT_EQUAL_FATAL(rc, 0);
394 
395   // GT
396   rc = ejdb_list3(db, "a1", "/f/[b > 127]", 0, log, &list);
397   CU_ASSERT_EQUAL_FATAL(rc, 0);
398 
399   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[INDEX] SELECTED I64|12 /f/b EXPR1: 'b > 127' "
400                                 "INIT: IWKV_CURSOR_GE STEP: IWKV_CURSOR_PREV"));
401 
402   i = 1;
403   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
404     iwxstr_clear(xstr);
405     if (i == 1) {
406       rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
407       CU_ASSERT_EQUAL_FATAL(rc, 0);
408       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":16777215},\"n\":1}");
409     } else if (i == 9) {
410       rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
411       CU_ASSERT_EQUAL_FATAL(rc, 0);
412       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":16777215},\"n\":9}");
413     }
414   }
415   CU_ASSERT_EQUAL(i, 6);
416   ejdb_list_destroy(&list);
417   iwxstr_clear(log);
418 
419   // LT
420   rc = ejdb_list3(db, "a1", "/f/[b < 127]", 0, log, &list);
421   CU_ASSERT_EQUAL_FATAL(rc, 0);
422   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "SELECTED I64|12 /f/b EXPR1: 'b < 127' "
423                                 "INIT: IWKV_CURSOR_GE STEP: IWKV_CURSOR_NEXT"));
424 
425   i = 1;
426   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
427     iwxstr_clear(xstr);
428     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
429     CU_ASSERT_EQUAL_FATAL(rc, 0);
430     if (i == 1) {
431       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":126},\"n\":12}");
432     } else if (i == 2) {
433       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":126},\"n\":11}");
434     }
435   }
436   CU_ASSERT_EQUAL(i, 3);
437   ejdb_list_destroy(&list);
438   iwxstr_clear(log);
439 
440   // LT2
441   rc = ejdb_list3(db, "a1", "/f/[b < 16777216]", 0, log, &list);
442   CU_ASSERT_EQUAL_FATAL(rc, 0);
443   i = 1;
444   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
445     iwxstr_clear(xstr);
446     if (i == 1) {
447       rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
448       CU_ASSERT_EQUAL_FATAL(rc, 0);
449       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":16777215},\"n\":9}");
450     } else if (i == 12) {
451       rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
452       CU_ASSERT_EQUAL_FATAL(rc, 0);
453       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":126},\"n\":11}");
454     }
455   }
456   CU_ASSERT_EQUAL(i, 13);
457   ejdb_list_destroy(&list);
458   iwxstr_clear(log);
459 
460   // EQ
461   rc = ejdb_list3(db, "a1", "/f/[b = 127]", 0, log, &list);
462   CU_ASSERT_EQUAL_FATAL(rc, 0);
463   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "SELECTED I64|12 /f/b EXPR1: 'b = 127' "
464                                 "INIT: IWKV_CURSOR_EQ"));
465 
466   i = 1;
467   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
468     iwxstr_clear(xstr);
469     if (i == 1) {
470       rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
471       CU_ASSERT_EQUAL_FATAL(rc, 0);
472       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":127},\"n\":2}");
473     } else if (i == 5) {
474       rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
475       CU_ASSERT_EQUAL_FATAL(rc, 0);
476       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":127},\"n\":10}");
477     }
478   }
479   CU_ASSERT_EQUAL(i, 6);
480   ejdb_list_destroy(&list);
481   iwxstr_clear(log);
482 
483   // IN
484   rc = ejdb_list3(db, "a1", "/f/[b in [333, 16777215, 127, 16777216]]", 0, log, &list);
485   CU_ASSERT_EQUAL_FATAL(rc, 0);
486   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[INDEX] SELECTED I64|12 /f/b "
487                                 "EXPR1: 'b in [333,16777215,127,16777216]' "
488                                 "INIT: IWKV_CURSOR_EQ"));
489   i = 1;
490   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
491     iwxstr_clear(xstr);
492     if (i == 1) {
493       rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
494       CU_ASSERT_EQUAL_FATAL(rc, 0);
495       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":127},\"n\":2}");
496     } else if (i == 5) {
497       rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
498       CU_ASSERT_EQUAL_FATAL(rc, 0);
499       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":127},\"n\":10}");
500     } else if (i == 6) {
501       rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
502       CU_ASSERT_EQUAL_FATAL(rc, 0);
503       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":16777215},\"n\":1}");
504     } else if (i == 10) {
505       rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
506       CU_ASSERT_EQUAL_FATAL(rc, 0);
507       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":16777215},\"n\":9}");
508     }
509   }
510   CU_ASSERT_EQUAL(i, 11);
511 
512   ejdb_list_destroy(&list);
513   iwxstr_clear(log);
514 
515   rc = ejdb_close(&db);
516   CU_ASSERT_EQUAL_FATAL(rc, 0);
517   iwxstr_destroy(log);
518   iwxstr_destroy(xstr);
519 }
520 
ejdb_test3_3()521 static void ejdb_test3_3() {
522   EJDB_OPTS opts = {
523     .kv       = {
524       .path   = "ejdb_test3_3.db",
525       .oflags = IWKV_TRUNC
526     },
527     .no_wal   = true
528   };
529   EJDB db;
530   char dbuf[1024];
531 
532   int i = 0;
533   EJDB_LIST list = 0;
534   IWXSTR *log = iwxstr_new();
535   CU_ASSERT_PTR_NOT_NULL_FATAL(log);
536   IWXSTR *xstr = iwxstr_new();
537   CU_ASSERT_PTR_NOT_NULL_FATAL(xstr);
538 
539   iwrc rc = ejdb_open(&opts, &db);
540   CU_ASSERT_EQUAL_FATAL(rc, 0);
541 
542   rc = ejdb_ensure_index(db, "a2", "/f/b", EJDB_IDX_STR);
543   CU_ASSERT_EQUAL_FATAL(rc, 0);
544 
545   char *data[] = {
546 
547     // len: 200
548     "Ar4prlJssa2ckf0IpmDuRBZ2b0Q6PtPdTacjWFFuO23CiCjdyfHaliz9JaqK1HFEeaneiMO"
549     "7sNh87oDLVkvz7TnOV22v0njqmmd6b8DSfzaCwxFxcqrF7MinjUvJvct1Fr07MJWeG7C6SP"
550     "MlUjFQ4jNlds3kUQDP9yxQImH7BkmCqBCisIoh5zar8zSax1Pk7nZSpm1b",
551 
552     // len: 115
553     "BkMSITU2qJ56xeX3nftUd3g4PuZwo9LY2mTGFtYKrrqhilPiR0UTHrDobstoShELlMHvPx61"
554     "KF8qQRPAn4OOUttNtkPE95XsjZQ8PPZW9ruWo1R9UMx",
555 
556     // len: 64
557     "C1257xkZuJqXhQ5v5eWG8TlwKdCY77DQ0ScLyC3nGDTtC3A8DPDAiVC09EBFTUxp",
558 
559     // len: 800
560     "D9z1bYv2oEp8n8B0BtY1VI4ezy8adAnPvqno9rdxM7RsMZDcLQyCEJ3vDMFqoJaRNbCtdbHh09"
561     "L0UijAR6wmQ87P90eAGKaEvuhoRzhoDZYpa37o7HZrBctcCxGHSrQMR0o1NKOz2vmEvhX6k02M"
562     "QopatRrL6jIkr9XXKgekOh6xcVyvUcnr6ttD3tqF0v0QN3ZPnXRCcVYyx0Ot9T6EfZik7HO3QW"
563     "jyblg4f4qqohprmGWKO8UfIIsF1gRPPacPc8oJXEFrbJu5NR4LidKpn6ygmTpstGVCanpCq2Yi"
564     "pkWrQpC1LkdSh3h2hNMUZbgZDgsvGzocuBuGgnyDd6I91PJjBmbFTXmILkT9t0ApvCGJTrc9aB"
565     "Sw5I9CAZRFRqVnRFUr7fA0OfQhN2zCu4d5m1XQg3yh9We4GI1ffhWsbnH4g59HbuAkm9jmz4mp"
566     "B6IJUSewlgq6YDgfsPNQXHboBVWAuR9NONIpfpmnU4wjuwI3j3QJAbi81u23QXAWJETvVBRqqU"
567     "ZqtqUjwnOCoPvkRV3WhfEHezmN9HTuxxl75WowRXyz8nwUe3xOXadmQwkhyYbWSSrO835XziTj"
568     "58e00zGi6eLwXD7xrKC7YeEb7HE4L8eKeEFiM1xC00ySIDkBNoclMxmExPg6kBUpiUT7HAEfaN"
569     "AN2VbdWFZsumDQHu3Q5XwrGdiQ6ubLTMuQEIv1IPTZIRTV5TQ59aUdiM6POdLFv9xuDjEgnBYd"
570     "MxcP60sNDIakuW2IeabKScwF5yx9PAg7D9K5WVWhpSQuzDFiTSSJPwkQfoWo"
571   };
572 
573   snprintf(dbuf, sizeof(dbuf), "{\"f\":{\"b\":\"%s\"},\"n\":%d}", data[0], 1);
574   rc = put_json(db, "a2", dbuf);
575   CU_ASSERT_EQUAL_FATAL(rc, 0);
576 
577   snprintf(dbuf, sizeof(dbuf), "{\"f\":{\"b\":\"%s\"},\"n\":%d}", data[1], 2);
578   rc = put_json(db, "a2", dbuf);
579   CU_ASSERT_EQUAL_FATAL(rc, 0);
580 
581   snprintf(dbuf, sizeof(dbuf), "{\"f\":{\"b\":\"%s\"},\"n\":%" PRId64 "}", data[1], INT64_MAX - 1);
582   rc = put_json(db, "a2", dbuf);
583   CU_ASSERT_EQUAL_FATAL(rc, 0);
584 
585   snprintf(dbuf, sizeof(dbuf), "{\"f\":{\"b\":\"%s\"},\"n\":%d}", data[2], 3);
586   rc = put_json(db, "a2", dbuf);
587   CU_ASSERT_EQUAL_FATAL(rc, 0);
588 
589   snprintf(dbuf, sizeof(dbuf), "{\"f\":{\"b\":\"%s\"},\"n\":%d}", data[2], 4);
590   rc = put_json(db, "a2", dbuf);
591   CU_ASSERT_EQUAL_FATAL(rc, 0);
592 
593 
594   snprintf(dbuf, sizeof(dbuf), "{\"f\":{\"b\":\"%s\"},\"n\":%d}", data[3], 5);
595   rc = put_json(db, "a2", dbuf);
596   CU_ASSERT_EQUAL_FATAL(rc, 0);
597 
598   // Q: /f/[b >= data[0]]
599   JQL q;
600   rc = jql_create(&q, "a2", "/f/[b >= :?]");
601   CU_ASSERT_EQUAL_FATAL(rc, 0);
602 
603   rc = jql_set_str(q, 0, 0, data[0]);
604   CU_ASSERT_EQUAL_FATAL(rc, 0);
605 
606   rc = ejdb_list4(db, q, 0, log, &list);
607   CU_ASSERT_EQUAL_FATAL(rc, 0);
608   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[INDEX] SELECTED STR|6 /f/b EXPR1: 'b >= :?' "
609                                 "INIT: IWKV_CURSOR_GE STEP: IWKV_CURSOR_PREV"));
610   i = 1;
611   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
612     JBL jbl1, jbl2;
613     rc = jbl_at(doc->raw, "/f/b", &jbl1);
614     CU_ASSERT_EQUAL_FATAL(rc, 0);
615     rc = jbl_at(doc->raw, "/n", &jbl2);
616     CU_ASSERT_EQUAL_FATAL(rc, 0);
617     int64_t llv = jbl_get_i64(jbl2);
618     const char *str = jbl_get_str(jbl1);
619     switch (i) {
620       case 1:
621         CU_ASSERT_EQUAL(llv, 1);
622         CU_ASSERT_STRING_EQUAL(str, data[0]);
623         break;
624       case 2:
625         CU_ASSERT_EQUAL(llv, 2);
626         CU_ASSERT_STRING_EQUAL(str, data[1]);
627         break;
628       case 3:
629         CU_ASSERT_EQUAL(llv, INT64_MAX - 1);
630         CU_ASSERT_STRING_EQUAL(str, data[1]);
631         break;
632       case 4:
633         CU_ASSERT_EQUAL(llv, 3);
634         CU_ASSERT_STRING_EQUAL(str, data[2]);
635         break;
636       case 5:
637         CU_ASSERT_EQUAL(llv, 4);
638         CU_ASSERT_STRING_EQUAL(str, data[2]);
639         break;
640       case 6:
641         CU_ASSERT_EQUAL(llv, 5);
642         CU_ASSERT_STRING_EQUAL(str, data[3]);
643         break;
644     }
645     jbl_destroy(&jbl1);
646     jbl_destroy(&jbl2);
647   }
648   CU_ASSERT_EQUAL(i, 7);
649 
650   ejdb_list_destroy(&list);
651   iwxstr_clear(log);
652 
653   // Q: /f/[b >= data[3]]
654   rc = jql_set_str(q, 0, 0, data[3]);
655   CU_ASSERT_EQUAL_FATAL(rc, 0);
656 
657   rc = ejdb_list4(db, q, 0, log, &list);
658   CU_ASSERT_EQUAL_FATAL(rc, 0);
659   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[INDEX] SELECTED STR|6 /f/b EXPR1: 'b >= :?' "
660                                 "INIT: IWKV_CURSOR_GE STEP: IWKV_CURSOR_PREV"));
661 
662   i = 1;
663   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
664     JBL jbl1, jbl2;
665     rc = jbl_at(doc->raw, "/f/b", &jbl1);
666     CU_ASSERT_EQUAL_FATAL(rc, 0);
667     rc = jbl_at(doc->raw, "/n", &jbl2);
668     CU_ASSERT_EQUAL_FATAL(rc, 0);
669     int64_t llv = jbl_get_i64(jbl2);
670     const char *str = jbl_get_str(jbl1);
671     CU_ASSERT_EQUAL(llv, 5);
672     CU_ASSERT_STRING_EQUAL(str, data[3]);
673     jbl_destroy(&jbl1);
674     jbl_destroy(&jbl2);
675   }
676   CU_ASSERT_EQUAL(i, 2);
677 
678   // todo: record update
679   // todo: record removal
680 
681   ejdb_list_destroy(&list);
682   iwxstr_clear(log);
683   jql_destroy(&q);
684 
685   rc = ejdb_close(&db);
686   CU_ASSERT_EQUAL_FATAL(rc, 0);
687   iwxstr_destroy(log);
688   iwxstr_destroy(xstr);
689 }
690 
691 // Test array index
ejdb_test3_4()692 static void ejdb_test3_4() {
693   EJDB_OPTS opts = {
694     .kv       = {
695       .path   = "ejdb_test3_4.db",
696       .oflags = IWKV_TRUNC
697     },
698     .no_wal   = true
699   };
700   EJDB db;
701   char dbuf[1024];
702 
703   int i = 0;
704   EJDB_LIST list = 0;
705   int64_t docId = 0;
706 
707   IWPOOL *pool = iwpool_create(1024);
708   CU_ASSERT_PTR_NOT_NULL_FATAL(pool);
709   IWXSTR *log = iwxstr_new();
710   CU_ASSERT_PTR_NOT_NULL_FATAL(log);
711   IWXSTR *xstr = iwxstr_new();
712   CU_ASSERT_PTR_NOT_NULL_FATAL(xstr);
713 
714   iwrc rc = ejdb_open(&opts, &db);
715   CU_ASSERT_EQUAL_FATAL(rc, 0);
716 
717   rc = ejdb_ensure_index(db, "a3", "/tags", EJDB_IDX_STR);
718   CU_ASSERT_EQUAL_FATAL(rc, 0);
719 
720   snprintf(dbuf, sizeof(dbuf), "{\"tags\": [\"foo\", \"bar\", \"gaz\"],\"n\":%d}", 1);
721   rc = put_json(db, "a3", dbuf);
722   CU_ASSERT_EQUAL_FATAL(rc, 0);
723 
724   snprintf(dbuf, sizeof(dbuf), "{\"tags\": [\"gaz\", \"zaz\"],\"n\":%d}", 2);
725   rc = put_json2(db, "a3", dbuf, &docId);
726   CU_ASSERT_EQUAL_FATAL(rc, 0);
727 
728   JQL q;
729   rc = jql_create(&q, "a3", "/tags/[** in :tags]");
730   CU_ASSERT_EQUAL_FATAL(rc, 0);
731 
732   // Q:
733   JBL_NODE qtags;
734   rc = jbn_from_json("[\"zaz\",\"gaz\"]", &qtags, pool);
735   CU_ASSERT_EQUAL_FATAL(rc, 0);
736 
737   rc = jql_set_json(q, "tags", 0, qtags);
738   CU_ASSERT_EQUAL_FATAL(rc, 0);
739 
740   rc = ejdb_list4(db, q, 0, log, &list);
741   CU_ASSERT_EQUAL_FATAL(rc, 0);
742 
743   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
744                                 "[INDEX] SELECTED STR|5 /tags EXPR1: '** in :tags' "
745                                 "INIT: IWKV_CURSOR_EQ"));
746   i = 1;
747   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
748     iwxstr_clear(xstr);
749     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
750     CU_ASSERT_EQUAL_FATAL(rc, 0);
751     if (i == 1) {
752       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"tags\":[\"foo\",\"bar\",\"gaz\"],\"n\":1}");
753     } else if ((i == 2) || (i == 3)) {
754       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"tags\":[\"gaz\",\"zaz\"],\"n\":2}");
755     }
756   }
757   CU_ASSERT_EQUAL(i, 4);
758   ejdb_list_destroy(&list);
759   iwxstr_clear(log);
760 
761 
762   // Get
763   CU_ASSERT_TRUE(docId > 0);
764   JBL jbl;
765   rc = ejdb_get(db, "a3", docId, &jbl);
766   CU_ASSERT_EQUAL_FATAL(rc, 0);
767   iwxstr_clear(xstr);
768   rc = jbl_as_json(jbl, jbl_xstr_json_printer, xstr, 0);
769   CU_ASSERT_EQUAL_FATAL(rc, 0);
770   jbl_destroy(&jbl);
771   CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"tags\":[\"gaz\",\"zaz\"],\"n\":2}");
772   rc = put_json2(db, "a3", "{\"tags\": [\"gaz\",\"zaz\"],\"n\":2}", &docId);
773   CU_ASSERT_EQUAL_FATAL(rc, 0);
774 
775   // Update {"tags":["gaz","zaz", "boo"], "n":2}
776   rc = put_json2(db, "a3", "{\"tags\": [\"gaz\",\"zaz\",\"boo\"],\"n\":2}", &docId);
777   CU_ASSERT_EQUAL_FATAL(rc, 0);
778 
779   // Q:
780   rc = jbn_from_json("[\"zaz\",\"boo\"]", &qtags, pool);
781   CU_ASSERT_EQUAL_FATAL(rc, 0);
782   rc = jql_set_json(q, "tags", 0, qtags);
783   CU_ASSERT_EQUAL_FATAL(rc, 0);
784 
785   rc = ejdb_list4(db, q, 0, log, &list);
786   CU_ASSERT_EQUAL_FATAL(rc, 0);
787   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
788                                 "[INDEX] SELECTED STR|6 /tags EXPR1: '** in :tags' "
789                                 "INIT: IWKV_CURSOR_EQ"));
790   i = 1;
791   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
792     iwxstr_clear(xstr);
793     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
794     CU_ASSERT_EQUAL_FATAL(rc, 0);
795     CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"tags\":[\"gaz\",\"zaz\",\"boo\"],\"n\":2}");
796   }
797   CU_ASSERT_EQUAL(i, 3);
798   ejdb_list_destroy(&list);
799   iwxstr_clear(log);
800 
801   // Remove last
802   rc = ejdb_del(db, "a3", docId);
803   CU_ASSERT_EQUAL_FATAL(rc, 0);
804 
805   // G2
806   rc = jbn_from_json("[\"gaz\"]", &qtags, pool);
807   CU_ASSERT_EQUAL_FATAL(rc, 0);
808   rc = jql_set_json(q, "tags", 0, qtags);
809   CU_ASSERT_EQUAL_FATAL(rc, 0);
810 
811   rc = ejdb_list4(db, q, 0, log, &list);
812   CU_ASSERT_EQUAL_FATAL(rc, 0);
813   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log),
814                                 "[INDEX] SELECTED STR|3 /tags EXPR1: '** in :tags' "
815                                 "INIT: IWKV_CURSOR_EQ"));
816   i = 1;
817   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
818     iwxstr_clear(xstr);
819     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
820     CU_ASSERT_EQUAL_FATAL(rc, 0);
821     CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"tags\":[\"foo\",\"bar\",\"gaz\"],\"n\":1}");
822   }
823   CU_ASSERT_EQUAL(i, 2);
824 
825   ejdb_list_destroy(&list);
826   iwxstr_clear(log);
827 
828 
829   jql_destroy(&q);
830 
831   rc = ejdb_close(&db);
832   CU_ASSERT_EQUAL_FATAL(rc, 0);
833   iwxstr_destroy(log);
834   iwxstr_destroy(xstr);
835   iwpool_destroy(pool);
836 }
837 
ejdb_test3_5()838 void ejdb_test3_5() {
839   EJDB_OPTS opts = {
840     .kv       = {
841       .path   = "ejdb_test3_5.db",
842       .oflags = IWKV_TRUNC
843     },
844     .no_wal   = true
845   };
846   EJDB db;
847   EJDB_LIST list = 0;
848   char dbuf[1024];
849   IWXSTR *xstr = iwxstr_new();
850   CU_ASSERT_PTR_NOT_NULL_FATAL(xstr);
851 
852   iwrc rc = ejdb_open(&opts, &db);
853   CU_ASSERT_EQUAL_FATAL(rc, 0);
854 
855   for (int i = 1; i <= 10; ++i) {
856     snprintf(dbuf, sizeof(dbuf), "{\"f\":{\"b\":%d},\"n\":%d}", i, i);
857     rc = put_json(db, "c1", dbuf);
858     CU_ASSERT_EQUAL_FATAL(rc, 0);
859   }
860 
861   rc = ejdb_list3(db, "c1", "/f/[b = 2] | del", 0, 0, &list);
862   CU_ASSERT_EQUAL_FATAL(rc, 0);
863   int i = 0;
864   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
865     iwxstr_clear(xstr);
866     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
867     CU_ASSERT_EQUAL_FATAL(rc, 0);
868     CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":2},\"n\":2}");
869   }
870   CU_ASSERT_EQUAL_FATAL(i, 1);
871   ejdb_list_destroy(&list);
872 
873   // Check if /f/[b = 2] has been deleted
874   rc = ejdb_list3(db, "c1", "/f/[b = 2]", 0, 0, &list);
875   CU_ASSERT_EQUAL_FATAL(rc, 0);
876   CU_ASSERT_PTR_NULL(list->first);
877   ejdb_list_destroy(&list);
878 
879   // Ensure index on /f/b
880   rc = ejdb_ensure_index(db, "c2", "/f/b", EJDB_IDX_UNIQUE | EJDB_IDX_I64);
881   CU_ASSERT_EQUAL_FATAL(rc, 0);
882 
883   rc = ejdb_list3(db, "c1", "/f/[b = 3] | del", 0, 0, &list);
884   CU_ASSERT_EQUAL_FATAL(rc, 0);
885   ejdb_list_destroy(&list);
886 
887   // Check if /f/[b = 3] has been deleted
888   rc = ejdb_list3(db, "c1", "/f/[b = 3]", 0, 0, &list);
889   CU_ASSERT_EQUAL_FATAL(rc, 0);
890   CU_ASSERT_PTR_NULL(list->first);
891   ejdb_list_destroy(&list);
892 
893   rc = ejdb_list3(db, "c1", "/* | asc /f/b", 0, 0, &list);
894   CU_ASSERT_EQUAL_FATAL(rc, 0);
895   i = 0;
896   for (EJDB_DOC doc = list->first; doc; doc = doc->next, ++i) {
897     iwxstr_clear(xstr);
898     rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
899     CU_ASSERT_EQUAL_FATAL(rc, 0);
900     if (i == 0) {
901       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":1},\"n\":1}");
902     } else if (i == 1) {
903       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":4},\"n\":4}");
904     } else if (i == 7) {
905       CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"f\":{\"b\":10},\"n\":10}");
906     }
907   }
908   ejdb_list_destroy(&list);
909   CU_ASSERT_EQUAL_FATAL(i, 8);
910 
911   // Remove rest of elements
912   rc = ejdb_list3(db, "c1", "/* | del | desc /f/b", 0, 0, &list);
913   CU_ASSERT_EQUAL_FATAL(rc, 0);
914   ejdb_list_destroy(&list);
915 
916   // Check coll is empty
917   rc = ejdb_list3(db, "c1", "/*", 0, 0, &list);
918   CU_ASSERT_EQUAL_FATAL(rc, 0);
919   CU_ASSERT_PTR_NULL(list->first);
920   ejdb_list_destroy(&list);
921 
922   rc = ejdb_close(&db);
923   CU_ASSERT_EQUAL_FATAL(rc, 0);
924   iwxstr_destroy(xstr);
925 }
926 
jql_free_str(void * ptr,void * op)927 static void jql_free_str(void *ptr, void *op) {
928   if (ptr) {
929     free(ptr);
930   }
931 }
932 
ejdb_test3_6()933 void ejdb_test3_6() {
934   EJDB_OPTS opts = {
935     .kv       = {
936       .path   = "ejdb_test3_6.db",
937       .oflags = IWKV_TRUNC
938     }
939   };
940 
941   JQL q;
942   EJDB db;
943   EJDB_LIST list = 0;
944   IWXSTR *xstr = iwxstr_new();
945   CU_ASSERT_PTR_NOT_NULL_FATAL(xstr);
946 
947   iwrc rc = ejdb_open(&opts, &db);
948   CU_ASSERT_EQUAL_FATAL(rc, 0);
949 
950   rc = ejdb_ensure_index(db, "mycoll", "/foo", EJDB_IDX_UNIQUE | EJDB_IDX_STR);
951   CU_ASSERT_EQUAL_FATAL(rc, 0);
952 
953 
954   rc = put_json(db, "mycoll", "{\"foo\":\"baz\",\"baz\":\"qux\"}");
955   CU_ASSERT_EQUAL_FATAL(rc, 0);
956 
957   rc = jql_create(&q, 0, "@mycoll/[foo re :?]");
958   CU_ASSERT_EQUAL_FATAL(rc, 0);
959 
960   rc = jql_set_regexp(q, 0, 0, ".*");
961   CU_ASSERT_EQUAL_FATAL(rc, 0);
962 
963   rc = ejdb_list4(db, q, 0, 0, &list);
964   CU_ASSERT_EQUAL_FATAL(rc, 0);
965   CU_ASSERT_PTR_NOT_NULL_FATAL(list->first);
966 
967   iwxstr_clear(xstr);
968   rc = jbl_as_json(list->first->raw, jbl_xstr_json_printer, xstr, 0);
969   CU_ASSERT_EQUAL_FATAL(rc, 0);
970   CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "{\"foo\":\"baz\",\"baz\":\"qux\"}");
971   ejdb_list_destroy(&list);
972 
973   // Now set regexp again
974   rc = jql_set_regexp2(q, 0, 0, strdup(".*"), jql_free_str, 0);
975   CU_ASSERT_EQUAL_FATAL(rc, 0);
976 
977   rc = ejdb_list4(db, q, 0, 0, &list);
978   CU_ASSERT_EQUAL_FATAL(rc, 0);
979   CU_ASSERT_PTR_NOT_NULL_FATAL(list->first);
980 
981   ejdb_list_destroy(&list);
982 
983   rc = ejdb_close(&db);
984   CU_ASSERT_EQUAL_FATAL(rc, 0);
985   iwxstr_destroy(xstr);
986   jql_destroy(&q);
987 }
988 
ejdb_test3_7()989 void ejdb_test3_7() {
990   EJDB_OPTS opts = {
991     .kv       = {
992       .path   = "ejdb_test3_7.db",
993       .oflags = IWKV_TRUNC
994     }
995   };
996   EJDB db;
997   iwrc rc = ejdb_open(&opts, &db);
998   CU_ASSERT_EQUAL_FATAL(rc, 0);
999 
1000   rc = put_json(db, "cc1", "{'foo':1}");
1001   CU_ASSERT_EQUAL_FATAL(rc, 0);
1002 
1003   rc = ejdb_rename_collection(db, "cc1", "cc2");
1004   CU_ASSERT_EQUAL_FATAL(rc, 0);
1005 
1006   JBL jbl;
1007   rc = ejdb_get(db, "cc2", 1, &jbl);
1008   CU_ASSERT_EQUAL_FATAL(rc, 0);
1009   jbl_destroy(&jbl);
1010 
1011   rc = ejdb_rename_collection(db, "cc1", "cc2");
1012   CU_ASSERT_EQUAL_FATAL(rc, EJDB_ERROR_COLLECTION_NOT_FOUND);
1013 
1014   rc = ejdb_rename_collection(db, "cc2", "cc2");
1015   CU_ASSERT_EQUAL_FATAL(rc, EJDB_ERROR_TARGET_COLLECTION_EXISTS);
1016 
1017   rc = ejdb_close(&db);
1018   CU_ASSERT_EQUAL_FATAL(rc, 0);
1019 
1020   opts.kv.oflags = 0;
1021 
1022   rc = ejdb_open(&opts, &db);
1023   CU_ASSERT_EQUAL_FATAL(rc, 0);
1024 
1025   rc = ejdb_get(db, "cc2", 1, &jbl);
1026   CU_ASSERT_EQUAL_FATAL(rc, 0);
1027   jbl_destroy(&jbl);
1028 
1029   rc = ejdb_close(&db);
1030   CU_ASSERT_EQUAL_FATAL(rc, 0);
1031 }
1032 
ejdb_test3_8(void)1033 void ejdb_test3_8(void) {
1034   EJDB_OPTS opts = {
1035     .kv       = {
1036       .path   = "ejdb_test3_8.db",
1037       .oflags = IWKV_TRUNC
1038     },
1039     .no_wal   = true
1040   };
1041 
1042   EJDB db;
1043   JQL q;
1044   char buf[64];
1045   JBL_NODE n;
1046 
1047   int64_t id1 = 0, id2 = 0;
1048   EJDB_LIST list = 0;
1049 
1050   IWPOOL *pool = iwpool_create(255);
1051   IWXSTR *log = iwxstr_new();
1052   CU_ASSERT_PTR_NOT_NULL_FATAL(log);
1053 
1054   iwrc rc = ejdb_open(&opts, &db);
1055   CU_ASSERT_EQUAL_FATAL(rc, 0);
1056 
1057   rc = put_json2(db, "users", "{'name':'Andy'}", &id1);
1058   CU_ASSERT_EQUAL_FATAL(rc, 0);
1059 
1060   rc = put_json2(db, "users", "{'name':'John'}", &id2);
1061   CU_ASSERT_EQUAL_FATAL(rc, 0);
1062 
1063   rc = jql_create(&q, "users", "/=:?");
1064   CU_ASSERT_EQUAL_FATAL(rc, 0);
1065   rc = jql_set_i64(q, 0, 0, id1);
1066   CU_ASSERT_EQUAL_FATAL(rc, 0);
1067 
1068   rc = ejdb_list4(db, q, 0, log, &list);
1069   CU_ASSERT_EQUAL_FATAL(rc, 0);
1070 
1071   CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(log), "[INDEX] PK [COLLECTOR] PLAIN"));
1072   CU_ASSERT_PTR_NOT_NULL(list->first);
1073   CU_ASSERT_PTR_NULL(list->first->next);
1074 
1075   jql_destroy(&q);
1076   ejdb_list_destroy(&list);
1077   iwxstr_clear(log);
1078 
1079   rc = jql_create(&q, 0, "@users/=:id");
1080   CU_ASSERT_EQUAL_FATAL(rc, 0);
1081   rc = jql_set_str(q, "id", 0, "1");
1082   CU_ASSERT_EQUAL_FATAL(rc, 0);
1083   rc = ejdb_list4(db, q, 0, log, &list);
1084   CU_ASSERT_EQUAL_FATAL(rc, 0);
1085   CU_ASSERT_PTR_NOT_NULL(list->first);
1086   CU_ASSERT_PTR_NULL(list->first->next);
1087   jql_destroy(&q);
1088   ejdb_list_destroy(&list);
1089 
1090   // matching against PK array
1091   snprintf(buf, sizeof(buf), "@users/=[%" PRId64 ",%" PRId64 "]", id1, id2);
1092   rc = jql_create(&q, 0, buf);
1093   CU_ASSERT_EQUAL_FATAL(rc, 0);
1094   rc = ejdb_list4(db, q, 0, log, &list);
1095   CU_ASSERT_EQUAL_FATAL(rc, 0);
1096   CU_ASSERT_PTR_NOT_NULL(list->first);
1097   CU_ASSERT_PTR_NOT_NULL(list->first->next);
1098   jql_destroy(&q);
1099   ejdb_list_destroy(&list);
1100 
1101   // matching against PK array as JSON query paramater
1102   snprintf(buf, sizeof(buf), "[%" PRId64 ",%" PRId64 "]", id1, id2);
1103   rc = jbn_from_json(buf, &n, pool);
1104   CU_ASSERT_EQUAL_FATAL(rc, 0);
1105   rc = jql_create(&q, 0, "@users/=:?");
1106   CU_ASSERT_EQUAL_FATAL(rc, 0);
1107   rc = jql_set_json(q, 0, 0, n);
1108   CU_ASSERT_EQUAL_FATAL(rc, 0);
1109   rc = ejdb_list4(db, q, 0, log, &list);
1110   CU_ASSERT_EQUAL_FATAL(rc, 0);
1111   CU_ASSERT_PTR_NOT_NULL(list->first);
1112   CU_ASSERT_PTR_NOT_NULL(list->first->next);
1113   jql_destroy(&q);
1114   ejdb_list_destroy(&list);
1115 
1116   rc = ejdb_close(&db);
1117   CU_ASSERT_EQUAL_FATAL(rc, 0);
1118   iwxstr_destroy(log);
1119   iwpool_destroy(pool);
1120 }
1121 
main()1122 int main() {
1123   CU_pSuite pSuite = NULL;
1124   if (CUE_SUCCESS != CU_initialize_registry()) {
1125     return CU_get_error();
1126   }
1127   pSuite = CU_add_suite("ejdb_test3", init_suite, clean_suite);
1128   if (NULL == pSuite) {
1129     CU_cleanup_registry();
1130     return CU_get_error();
1131   }
1132   if (  (NULL == CU_add_test(pSuite, "ejdb_test3_1", ejdb_test3_1))
1133      || (NULL == CU_add_test(pSuite, "ejdb_test3_2", ejdb_test3_2))
1134      || (NULL == CU_add_test(pSuite, "ejdb_test3_3", ejdb_test3_3))
1135      || (NULL == CU_add_test(pSuite, "ejdb_test3_4", ejdb_test3_4))
1136      || (NULL == CU_add_test(pSuite, "ejdb_test3_5", ejdb_test3_5))
1137      || (NULL == CU_add_test(pSuite, "ejdb_test3_6", ejdb_test3_6))
1138      || (NULL == CU_add_test(pSuite, "ejdb_test3_7", ejdb_test3_7))
1139      || (NULL == CU_add_test(pSuite, "ejdb_test3_8", ejdb_test3_8))) {
1140     CU_cleanup_registry();
1141     return CU_get_error();
1142   }
1143   CU_basic_set_mode(CU_BRM_VERBOSE);
1144   CU_basic_run_tests();
1145   int ret = CU_get_error() || CU_get_number_of_failures();
1146   CU_cleanup_registry();
1147   return ret;
1148 }
1149