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