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