• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #pragma once
2 #ifndef EJDB2_H
3 #define EJDB2_H
4 
5 /**************************************************************************************************
6  * EJDB2
7  *
8  * MIT License
9  *
10  * Copyright (c) 2012-2021 Softmotions Ltd <info@softmotions.com>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy
13  * of this software and associated documentation files (the "Software"), to deal
14  * in the Software without restriction, including without limitation the rights
15  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16  *  copies of the Software, and to permit persons to whom the Software is
17  * furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in all
20  * copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28  * SOFTWARE.
29  *************************************************************************************************/
30 
31 #include <ejdb2/iowow/iwkv.h>
32 #include "jql.h"
33 #include "jbl.h"
34 
35 IW_EXTERN_C_START
36 
37 /**
38  * @brief ejdb2 initialization routine.
39  * @note Must be called before using any of ejdb API function.
40  */
41 IW_EXPORT WUR iwrc ejdb_init(void);
42 
43 /** Maximum length of EJDB collection name */
44 #define EJDB_COLLECTION_NAME_MAX_LEN 255
45 
46 /**
47  * @brief EJDB error codes.
48  */
49 typedef enum {
50   _EJDB_ERROR_START = (IW_ERROR_START + 15000UL),
51   EJDB_ERROR_INVALID_COLLECTION_NAME,             /**< Invalid collection name */
52   EJDB_ERROR_INVALID_COLLECTION_META,             /**< Invalid collection metadata */
53   EJDB_ERROR_INVALID_COLLECTION_INDEX_META,       /**< Invalid collection index metadata */
54   EJDB_ERROR_INVALID_INDEX_MODE,                  /**< Invalid index mode specified */
55   EJDB_ERROR_MISMATCHED_INDEX_UNIQUENESS_MODE,    /**< Index exists but mismatched uniqueness constraint */
56   EJDB_ERROR_UNIQUE_INDEX_CONSTRAINT_VIOLATED,    /**< Unique index constraint violated */
57   EJDB_ERROR_COLLECTION_NOT_FOUND,                /**< Collection not found */
58   EJDB_ERROR_TARGET_COLLECTION_EXISTS,            /**< Target collection exists */
59   EJDB_ERROR_PATCH_JSON_NOT_OBJECT,               /**< Patch JSON must be an object (map) */
60   _EJDB_ERROR_END,
61 } ejdb_ecode_t;
62 
63 /** Index creation mode */
64 typedef uint8_t ejdb_idx_mode_t;
65 
66 /** Marks index is unique, no duplicated values allowed. */
67 #define EJDB_IDX_UNIQUE ((ejdb_idx_mode_t) 0x01U)
68 
69 /** Index values have string type.
70  *  Type conversion will be performed on atempt to save value with other type */
71 #define EJDB_IDX_STR ((ejdb_idx_mode_t) 0x04U)
72 
73 /** Index values have signed integer 64 bit wide type.
74  *  Type conversion will be performed on atempt to save value with other type */
75 #define EJDB_IDX_I64 ((ejdb_idx_mode_t) 0x08U)
76 
77 /** Index value have floating point type.
78  *  @note Internally floating point numbers are converted to string
79  *        with precision of 6 digits after decimal point.
80  */
81 #define EJDB_IDX_F64 ((ejdb_idx_mode_t) 0x10U)
82 
83 /**
84  * @brief Database handler.
85  */
86 struct _EJDB;
87 typedef struct _EJDB*EJDB;
88 
89 /**
90  * @brief EJDB HTTP/Websocket Server options.
91  */
92 typedef struct _EJDB_HTTP {
93   bool enabled;                 /**< If HTTP/Websocket endpoint enabled. Default: false */
94   int  port;                    /**< Listen port number, required */
95   const char *bind;             /**< Listen IP/host. Default: `localhost` */
96   const char *access_token;     /**< Server access token passed in `X-Access-Token` header. Default: zero */
97   size_t      access_token_len; /**< Length of access token string. Default: zero */
98   bool blocking;                /**< Block `ejdb_open()` thread until http service finished.
99                                      Otherwise HTTP server will be started in background. */
100   bool   read_anon;             /**< Allow anonymous read-only database access */
101   size_t max_body_size;         /**< Maximum WS/HTTP API body size. Default: 64Mb, Min: 512K */
102   bool cors;                    /**< Allow CORS */
103 } EJDB_HTTP;
104 
105 /**
106  * @brief EJDB open options.
107  */
108 typedef struct _EJDB_OPTS {
109   IWKV_OPTS kv;                 /**< IWKV storage options. @see iwkv.h */
110   EJDB_HTTP http;               /**< HTTP/Websocket server options */
111   bool      no_wal;             /**< Do not use write-ahead-log. Default: false */
112   uint32_t  sort_buffer_sz;     /**< Max sorting buffer size. If exceeded an overflow temp file for sorted data will
113                                    created.
114                                      Default 16Mb, min: 1Mb */
115   uint32_t document_buffer_sz;  /**< Initial size of buffer in bytes used to process/store document during query
116                                    execution.
117                                      Default 64Kb, min: 16Kb */
118 } EJDB_OPTS;
119 
120 /**
121  * @brief Document representation as result of query execution.
122  * @see ejdb_exec()
123  */
124 typedef struct _EJDB_DOC {
125   int64_t id;                 /**< Document ID. Not zero. */
126   JBL     raw;                /**< JSON document in compact binary form.
127                                    Based on [Binn](https://github.com/liteserver/binn) format.
128                                    Not zero. */
129   JBL_NODE node;              /**< JSON document as in-memory tree. Not zero only if query has `apply` or `projection`
130                                  parts.
131 
132                                    @warning The lifespan of @ref EJDB_DOC.node will be valid only during the call of
133                                       @ref EJDB_EXEC_VISITOR
134                                             It is true in all cases EXCEPT:
135                                             - @ref EJDB_EXEC.pool is not set by `ejdb_exec()` caller
136                                             - One of `ejdb_list()` methods used */
137 
138   struct _EJDB_DOC *next;     /**< Reference to next document in result list or zero.
139                                    Makes sense only for `ejdb_list()` calls. */
140   struct _EJDB_DOC *prev;     /**< Reference to the previous document in result list or zero.
141                                    Makes sense only for `ejdb_list()` calls. */
142 } *EJDB_DOC;
143 
144 /**
145  * @brief Query result as list.
146  * Used as result of `ejdb_list()` query functions.
147  *
148  * @warning Getting result of query as list can be very memory consuming for large collections.
149  *          Consider use of `ejdb_exec()` with visitor or set `limit` for query.
150  */
151 typedef struct _EJDB_LIST {
152   EJDB     db;          /**< EJDB storage used for query execution. Not zero. */
153   JQL      q;           /**< Query executed. Not zero. */
154   EJDB_DOC first;       /**< First document in result list. Zero if result set is empty. */
155   IWPOOL  *pool;        /**< Memory pool used to store list of documents */
156 } *EJDB_LIST;
157 
158 struct _EJDB_EXEC;
159 
160 /**
161  * @brief Visitor for matched documents during query execution.
162  *
163  * @param ctx Visitor context.
164  * @param doc Data in `doc` is valid only during execution of this method, to keep a data for farther
165  *        processing you need to copy it.
166  * @param step [out] Move forward cursor to given number of steps, `1` by default.
167  */
168 typedef iwrc (*EJDB_EXEC_VISITOR)(struct _EJDB_EXEC *ctx, EJDB_DOC doc, int64_t *step);
169 
170 /**
171  * @brief Query execution context.
172  * Passed to `ejdb_exec()` to execute database query.
173  */
174 typedef struct _EJDB_EXEC {
175   EJDB db;                    /**< EJDB database object. Required. */
176   JQL  q;                     /**< Query object to be executed. Created by `jql_create()` Required. */
177   EJDB_EXEC_VISITOR visitor;  /**< Optional visitor to handle documents in result set. */
178   void   *opaque;             /**< Optional user data passed to visitor functions. */
179   int64_t skip;               /**< Number of records to skip. Takes precedence over `skip` encoded in query. */
180   int64_t limit;              /**< Result set size limitation. Zero means no limitations. Takes precedence over `limit`
181                                  encoded in query. */
182   int64_t cnt;                /**< Number of result documents processed by `visitor` */
183   IWXSTR *log;                /**< Optional query execution log buffer. If set major query execution/index selection
184                                  steps will be logged into */
185   IWPOOL *pool;               /**< Optional pool which can be used in query apply  */
186 } EJDB_EXEC;
187 
188 /**
189  * @brief Open storage file.
190  *
191  * Storage can be opened only by one single process at time.
192  *
193  * @param opts  Operating options. Can be stack allocated or disposed after `ejdb_open()` call.
194  * @param [out] ejdbp EJDB storage handle pointer as result.
195  */
196 IW_EXPORT WUR iwrc ejdb_open(const EJDB_OPTS *opts, EJDB *ejdbp);
197 
198 /**
199  * @brief Closes storage and frees up all resources.
200  * @param [in,out] ejdbp Pointer to storage handle, will set to zero oncompletion.
201  *
202  * @return `0` on success.
203  *          Any non zero error codes.
204  */
205 IW_EXPORT iwrc ejdb_close(EJDB *ejdbp);
206 
207 /**
208  * @brief Executes a query.
209  *
210  * The `ux` structure should be configured before this call,
211  * usually it is a stack allocated object.
212  *
213  * Query object should be created by `jql_create()`.
214  *
215  * Example:
216  *
217  * @code {.c}
218  *
219  *  JQL q;
220  *  iwrc rc = jql_create(&q, "mycollection", "/[firstName=?]");
221  *  RCRET(rc);
222  *
223  *  jql_set_str(q, 0, 0, "Andy"); // Set positional string query parameter
224  *
225  *  EJDB_EXEC ux = {
226  *    .db = db,
227  *    .q = q,
228  *    .visitor = my_query_results_visitor_func
229  *  };
230  *  rc = ejdb_exec(&ux);  // Execute query
231  *  jql_destroy(&q);      // Destroy query object
232  *
233  * @endcode
234  *
235  * Query object can be reused in many `ejdb_exec()` calls
236  * with different positional/named parameters.
237  *
238  * @param [in] ux Query execution params, object state may be changes during query execution.
239  *                Not zero.
240  *
241  * @return `0` on success.
242  *          Any non zero error codes.
243  */
244 IW_EXPORT WUR iwrc ejdb_exec(EJDB_EXEC *ux);
245 
246 /**
247  * @brief Executes a given query and builds a query result as linked list of documents.
248  *
249  * @warning Getting whole query result as linked list can be memory consuming for large collections.
250  *          Consider use of `ejdb_exec()` with visitor or set a positive `limit` value.
251  *
252  * @param db            Database handle. Not zero.
253  * @param q             Query object. Not zero.
254  * @param [out] first   First document in result set or zero if no matched documents found.
255  * @param limit         Maximum number of documents in result set. Takes precedence over `limit` encoded in query.
256  *                      Zero means a `limit` encoded in `q` will be used.
257  * @param pool          Memory pool will keep documents allocated in result set. Not zero.
258  *
259  * @return `0` on success.
260  *          Any non zero error codes.
261  */
262 IW_EXPORT WUR iwrc ejdb_list(EJDB db, JQL q, EJDB_DOC *first, int64_t limit, IWPOOL *pool);
263 
264 /**
265  * @brief Executes a given query `q` then returns `count` of matched documents.
266  *
267  * @param db           Database handle. Not zero.
268  * @param q            Query object. Not zero.
269  * @param [out] count  Placeholder for number of matched documents. Not zero.
270  * @param limit        Limit of matched rows. Makes sense for update queries.
271  *
272  */
273 IW_EXPORT WUR iwrc ejdb_count(EJDB db, JQL q, int64_t *count, int64_t limit);
274 
275 /**
276  * @brief Executes a given query `q` then returns `count` of matched documents.
277  *
278  * @param db           Database handle. Not zero.
279  * @param coll         Name of document collection.
280  *                     Can be zero, in what collection name should be encoded in query.
281  * @param q            Query text. Not zero.
282  * @param [out] count  Placeholder for number of matched documents. Not zero.
283  * @param limit        Limit of matched rows. Makes sense for update queries.
284  *
285  */
286 IW_EXPORT WUR iwrc ejdb_count2(EJDB db, const char *coll, const char *q, int64_t *count, int64_t limit);
287 
288 /**
289  * @brief Executes update query assuming that query object contains `apply` clause.
290  *        Similar to `ejdb_count`.
291  *
292  * @param db          Database handle. Not zero.
293  * @param q           Query object. Not zero.
294  */
295 IW_EXPORT WUR iwrc ejdb_update(EJDB db, JQL q);
296 
297 /**
298  * @brief Executes update query assuming that query object contains `apply` clause.
299  *        Similar to `ejdb_count`.
300  *
301  * @param db        Database handle. Not zero.
302  * @param coll         Name of document collection.
303  *                     Can be zero, in what collection name should be encoded in query.
304  * @param q         Query text. Not zero.
305  */
306 IW_EXPORT WUR iwrc ejdb_update2(EJDB db, const char *coll, const char *q);
307 
308 /**
309  * @brief Executes a given `query` and builds a result as linked list of documents.
310  *
311  * @note Returned `listp` must be disposed by `ejdb_list_destroy()`
312  * @warning Getting whole query result as linked list can be memory consuming for large collections.
313  *          Consider use of `ejdb_exec()` with visitor or set a positive `limit` value.
314  *
315  * @param db            Database handle. Not zero.
316  * @param coll          Collection name. If zero, collection name must be encoded in query.
317  * @param query         Query text. Not zero.
318  * @param limit         Maximum number of documents in result set. Takes precedence over `limit` encoded in query.
319  *                      Zero means a `limit` encoded in `query` will be used.
320  * @param [out] listp   Holder for query result, should be disposed by `ejdb_list_destroy()`.
321  *                      Not zero.
322  *
323  * @return `0` on success.
324  *          Any non zero error codes.
325  */
326 IW_EXPORT WUR iwrc ejdb_list2(EJDB db, const char *coll, const char *query, int64_t limit, EJDB_LIST *listp);
327 
328 /**
329  * @brief Executes a given `query` and builds a result as linked list of documents.
330  *
331  * @note Returned `listp` must be disposed by `ejdb_list_destroy()`
332  * @warning Getting whole query result as linked list can be memory consuming for large collections.
333  *          Consider use of `ejdb_exec()` with visitor or set a positive `limit` value.
334  *
335  * @param db            Database handle. Not zero.
336  * @param coll          Collection name. If zero, collection name must be encoded in query.
337  * @param query         Query text. Not zero.
338  * @param limit         Maximum number of documents in result set. Takes precedence over `limit` encoded in query.
339  * @param log           Optional buffer to collect query execution / index usage info.
340  * @param [out] listp   Holder for query result, should be disposed by `ejdb_list_destroy()`.
341  *                      Not zero.
342  *
343  * @return `0` on success.
344  *          Any non zero error codes.
345  */
346 IW_EXPORT WUR iwrc ejdb_list3(
347   EJDB db, const char *coll, const char *query, int64_t limit,
348   IWXSTR *log, EJDB_LIST *listp);
349 
350 /**
351  * @brief Executes a given query `q` and builds a result as linked list of documents (`listp`).
352  *
353  * @note Returned `listp` must be disposed by `ejdb_list_destroy()`
354  * @warning Getting whole query result as linked list can be memory consuming for large collections.
355  *          Consider use of `ejdb_exec()` with visitor  or set a positive `limit` value.
356  *
357  * @param db           Database handle. Not zero.
358  * @param q            Query object. Not zero.
359  * @param limit        Maximum number of documents in result set. Takes precedence over `limit` encoded in query.
360  * @param log          Optional buffer to collect query execution / index usage info.
361  * @param [out] listp  Holder for query result, should be disposed by `ejdb_list_destroy()`.
362  *                     Not zero.
363  *
364  * @return `0` on success.
365  *          Any non zero error codes.
366  */
367 IW_EXPORT WUR iwrc ejdb_list4(EJDB db, JQL q, int64_t limit, IWXSTR *log, EJDB_LIST *listp);
368 
369 /**
370  * @brief Destroy query result set and set `listp` to zero.
371  * @param [in,out] listp Can be zero.
372  */
373 IW_EXPORT void ejdb_list_destroy(EJDB_LIST *listp);
374 
375 /**
376  * @brief Apply rfc6902/rfc7396 JSON patch to the document identified by `id`.
377  *
378  * @param db          Database handle. Not zero.
379  * @param coll        Collection name. Not zero.
380  * @param patchjson   JSON patch conformed to rfc6902 or rfc7396 specification.
381  * @param id          Document id. Not zero.
382  *
383  * @return `0` on success.
384  *         `IWKV_ERROR_NOTFOUND` if document not found.
385  *          Any non zero error codes.
386  */
387 IW_EXPORT WUR iwrc ejdb_patch(EJDB db, const char *coll, const char *patchjson, int64_t id);
388 
389 /**
390  * @brief Apply rfc6902/rfc7396 JSON patch to the document identified by `id`.
391  *
392  * @param db          Database handle. Not zero.
393  * @param coll        Collection name. Not zero.
394  * @param patch       JSON patch conformed to rfc6902 or rfc7396 specification.
395  * @param id          Document id. Not zero.
396  *
397  * @return `0` on success.
398  *         `IWKV_ERROR_NOTFOUND` if document not found.
399  *          Any non zero error codes.
400  */
401 IW_EXPORT WUR iwrc ejdb_patch_jbn(EJDB db, const char *coll, JBL_NODE patch, int64_t id);
402 
403 
404 /**
405  * @brief Apply rfc6902/rfc7396 JSON patch to the document identified by `id`.
406  *
407  * @param db          Database handle. Not zero.
408  * @param coll        Collection name. Not zero.
409  * @param patch       JSON patch conformed to rfc6902 or rfc7396 specification.
410  * @param id          Document id. Not zero.
411  *
412  * @return `0` on success.
413  *         `IWKV_ERROR_NOTFOUND` if document not found.
414  *          Any non zero error codes.
415  */
416 IW_EXPORT WUR iwrc ejdb_patch_jbl(EJDB db, const char *coll, JBL patch, int64_t id);
417 
418 /**
419  * @brief Apply JSON merge patch (rfc7396) to the document identified by `id` or
420  *        insert new document under specified `id`.
421  * @note This is an atomic operation.
422  *
423  * @param db          Database handle. Not zero.
424  * @param coll        Collection name. Not zero.
425  * @param patchjson   JSON merge patch conformed to rfc7396 specification.
426  * @param id          Document id. Not zero.
427  *
428  */
429 IW_EXPORT WUR iwrc ejdb_merge_or_put(EJDB db, const char *coll, const char *patchjson, int64_t id);
430 
431 /**
432  * @brief Apply JSON merge patch (rfc7396) to the document identified by `id` or
433  *        insert new document under specified `id`.
434  * @note This is an atomic operation.
435  *
436  * @param db          Database handle. Not zero.
437  * @param coll        Collection name. Not zero.
438  * @param patch       JSON merge patch conformed to rfc7396 specification.
439  * @param id          Document id. Not zero.
440  *
441  */
442 IW_EXPORT WUR iwrc ejdb_merge_or_put_jbn(EJDB db, const char *coll, JBL_NODE patch, int64_t id);
443 
444 /**
445  * @brief Apply JSON merge patch (rfc7396) to the document identified by `id` or
446  *        insert new document under specified `id`.
447  * @note This is an atomic operation.
448  *
449  * @param db          Database handle. Not zero.
450  * @param coll        Collection name. Not zero.
451  * @param patch       JSON merge patch conformed to rfc7396 specification.
452  * @param id          Document id. Not zero.
453  *
454  */
455 IW_EXPORT WUR iwrc ejdb_merge_or_put_jbl(EJDB db, const char *coll, JBL patch, int64_t id);
456 
457 /**
458  * @brief Save a given `jbl` document under specified `id`.
459  *
460  * @param db        Database handle. Not zero.
461  * @param coll      Collection name. Not zero.
462  * @param jbl       JSON document. Not zero.
463  * @param id        Document identifier. Not zero.
464  *
465  * @return `0` on success.
466  *          Any non zero error codes.
467  */
468 IW_EXPORT WUR iwrc ejdb_put(EJDB db, const char *coll, JBL jbl, int64_t id);
469 
470 /**
471  * @brief Save a document into `coll` under new identifier.
472  *
473  * @param db          Database handle. Not zero.
474  * @param coll        Collection name. Not zero.
475  * @param jbl         JSON document. Not zero.
476  * @param [out] oid   Placeholder for new document id. Not zero.
477  *
478  * @return `0` on success.
479  *          Any non zero error codes.
480  */
481 IW_EXPORT WUR iwrc ejdb_put_new(EJDB db, const char *coll, JBL jbl, int64_t *oid);
482 
483 /**
484  * @brief Save a document into `coll` under new identifier.
485  *
486  * @param db          Database handle. Not zero.
487  * @param coll        Collection name. Not zero.
488  * @param jbn         JSON document. Not zero.
489  * @param [out] oid   Placeholder for new document id. Not zero.
490  *
491  * @return `0` on success.
492  *          Any non zero error codes.
493  */
494 IW_EXPORT iwrc ejdb_put_new_jbn(EJDB db, const char *coll, JBL_NODE jbn, int64_t *id);
495 
496 /**
497  * @brief Retrieve document identified by given `id` from collection `coll`.
498  *
499  * @param db          Database handle. Not zero.
500  * @param coll        Collection name. Not zero.
501  * @param id          Document id. Not zero.
502  * @param [out] jblp  Placeholder for document.
503  *                    Must be released by `jbl_destroy()`
504  *
505  * @return `0` on success.
506  *         `IWKV_ERROR_NOTFOUND` if document not found.
507  *         `IW_ERROR_NOT_EXISTS` if collection `coll` is not exists in db.
508  *          Any non zero error codes.
509  */
510 IW_EXPORT WUR iwrc ejdb_get(EJDB db, const char *coll, int64_t id, JBL *jblp);
511 
512 /**
513  * @brief  Remove document identified by given `id` from collection `coll`.
514  *
515  * @param db    Database handle. Not zero.
516  * @param coll  Collection name. Not zero.
517  * @param id    Document id. Not zero.
518  *
519  * @return `0` on success.
520  *         `IWKV_ERROR_NOTFOUND` if document not found.
521  *          Any non zero error codes.
522  */
523 IW_EXPORT iwrc ejdb_del(EJDB db, const char *coll, int64_t id);
524 
525 /**
526  * @brief Remove collection under the given name `coll`.
527  *
528  * @param db    Database handle. Not zero.
529  * @param coll  Collection name. Not zero.
530  *
531  * @return `0` on success.
532  *          Will return `0` if collection is not found.
533  *          Any non zero error codes.
534  */
535 IW_EXPORT iwrc ejdb_remove_collection(EJDB db, const char *coll);
536 
537 /**
538  * @brief Rename collection `coll` to `new_coll`.
539  *
540  * @param db    Database handle. Not zero.
541  * @param coll  Old collection name. Not zero.
542  * @param new_coll New collection name.
543  * @return `0` on success.
544  *          - `EJDB_ERROR_COLLECTION_NOT_FOUND` - if source `coll` is not found.
545  *          - `EJDB_ERROR_TARGET_COLLECTION_EXISTS` - if `new_coll` is exists already.
546  *          -  Any other non zero error codes.
547  */
548 IW_EXPORT iwrc ejdb_rename_collection(EJDB db, const char *coll, const char *new_coll);
549 
550 /**
551  * @brief Create collection with given name if it has not existed before
552  *
553  * @param db    Database handle. Not zero.
554  * @param coll  Collection name. Not zero.
555  *
556  * @return `0` on success.
557  *          Any non zero error codes.
558  */
559 IW_EXPORT iwrc ejdb_ensure_collection(EJDB db, const char *coll);
560 
561 /**
562  * @brief Create index with specified parameters if it has not existed before.
563  *
564  * @note Index `path` must be fully specified as rfc6901 JSON pointer
565  *       and must not countain unspecified `*`/`**` element in middle sections.
566  * @see ejdb_idx_mode_t.
567  *
568  * Example document:
569  *
570  * @code
571  * {
572  *   "address" : {
573  *      "street": "High Street"
574  *   }
575  * }
576  * @endcode
577  *
578  * Create unique index over all street names in nested address object:
579  *
580  * @code {.c}
581  * iwrc rc = ejdb_ensure_index(db, "mycoll", "/address/street", EJDB_IDX_UNIQUE | EJDB_IDX_STR);
582  * @endcode
583  *
584  * @param db    Database handle. Not zero.
585  * @param coll  Collection name. Not zero.
586  * @param path  rfc6901 JSON pointer to indexed field.
587  * @param mode  Index mode.
588  *
589  * @return `0` on success.
590  *         `EJDB_ERROR_INVALID_INDEX_MODE` Invalid `mode` specified
591  *         `EJDB_ERROR_MISMATCHED_INDEX_UNIQUENESS_MODE` trying to create non unique index over existing unique or vice
592  * versa.
593  *          Any non zero error codes.
594  *
595  */
596 IW_EXPORT iwrc ejdb_ensure_index(EJDB db, const char *coll, const char *path, ejdb_idx_mode_t mode);
597 
598 /**
599  * @brief Remove index if it has existed before.
600  *
601  * @param db    Database handle. Not zero.
602  * @param coll  Collection name. Not zero.
603  * @param path  rfc6901 JSON pointer to indexed field.
604  * @param mode  Index mode.
605  *
606  * @return `0` on success.
607  *          Will return `0` if collection is not found.
608  *          Any non zero error codes.
609  */
610 IW_EXPORT iwrc ejdb_remove_index(EJDB db, const char *coll, const char *path, ejdb_idx_mode_t mode);
611 
612 /**
613  * @brief Returns JSON document describind database structure.
614  * @note Returned `jblp` must be disposed by `jbl_destroy()`
615  *
616  * Example database metadata:
617  * @code {.json}
618  *
619  *   {
620  *    "version": "2.0.0", // EJDB engine version
621  *    "file": "db.jb",    // Path to storage file
622  *    "size": 16384,      // Storage file size in bytes
623  *    "collections": [    // List of collections
624  *     {
625  *      "name": "c1",     // Collection name
626  *      "dbid": 3,        // Collection database ID
627  *      "rnum": 2,        // Number of documents in collection
628  *      "indexes": [      // List of collections indexes
629  *       {
630  *        "ptr": "/n",    // rfc6901 JSON pointer to indexed field
631  *        "mode": 8,      // Index mode. Here is EJDB_IDX_I64
632  *        "idbf": 96,     // Index flags. See iwdb_flags_t
633  *        "dbid": 4,      // Index database ID
634  *        "rnum": 2       // Number records stored in index database
635  *       }
636  *      ]
637  *     }
638  *    ]
639  *   }
640  * @endcode
641  *
642  * @param db          Database handle. Not zero.
643  * @param [out] jblp  JSON object describing ejdb storage.
644  *                    Must be disposed by `jbl_destroy()`
645  */
646 IW_EXPORT iwrc ejdb_get_meta(EJDB db, JBL *jblp);
647 
648 /**
649  * Creates an online database backup image and copies it into the specified `target_file`.
650  * During online backup phase read/write database operations are allowed and not
651  * blocked for significant amount of time. Backup finish time is placed into `ts`
652  * as number of milliseconds since epoch.
653  *
654  * Online backup guaranties what all records before `ts` timestamp will
655  * be stored in backup image. Later, online backup image can be
656  * opened as ordinary database file.
657  *
658  * @note In order to avoid deadlocks: close all opened database cursors
659  * before calling this method or do call in separate thread.
660  *
661  * @param Database handle. Not zero.
662  * @param [out] ts Backup completion timestamp
663  * @param target_file backup file path
664  */
665 IW_EXPORT iwrc ejdb_online_backup(EJDB db, uint64_t *ts, const char *target_file);
666 
667 /**
668  * @brief Get access to underlying IWKV storage.
669  *        Use it with caution.
670  *
671  * @param db Database handle. Not zero.
672  * @param [out] kvp Placeholder for IWKV storage.
673  */
674 IW_EXPORT iwrc ejdb_get_iwkv(EJDB db, IWKV *kvp);
675 
676 /**
677  * @brief  Return `\0` terminated ejdb2 source GIT revision hash.
678  */
679 IW_EXPORT const char *ejdb_git_revision(void);
680 
681 /**
682  * @brief Return `\0` terminated EJDB version string.
683  */
684 IW_EXPORT const char *ejdb_version_full(void);
685 
686 /**
687  * @brief Return major library version.
688  */
689 IW_EXPORT unsigned int ejdb_version_major(void);
690 
691 /**
692  * @brief Return minor library version.
693  */
694 IW_EXPORT unsigned int ejdb_version_minor(void);
695 
696 /**
697  * @brief Return patch library version.
698  */
699 IW_EXPORT unsigned int ejdb_version_patch(void);
700 
701 IW_EXTERN_C_END
702 #endif
703