summaryrefslogtreecommitdiff
path: root/tcejdb/ejdb.h
blob: 02394070e57ba8d92eeff938f21896262b89d359 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/*
 * File:   ejdb.h
 * Author: adam
 *
 * Created on September 8, 2012, 10:09 PM
 */

#ifndef EJDB_H
#define        EJDB_H

#include "myconf.h"
#include "bson.h"
#include "tcutil.h"

EJDB_EXTERN_C_START

struct EJDB; /**< EJDB database object. */
typedef struct EJDB EJDB;

struct EJCOLL; /*< EJDB collection handle. */
typedef struct EJCOLL EJCOLL;

struct EJQ; /**< EJDB query. */
typedef struct EJQ EJQ;

typedef struct { /**< EJDB collection tuning options. */
    bool large; /**< Large collection. It can be larger than 2GB. Default false */
    bool compressed; /**< Collection records will be compressed with DEFLATE compression. Default: false */
    int64_t records; /**< Expected records number in the collection. Default: 128K */
    int cachedrecords; /**< Maximum number of cached records. Default: 0 */
} EJCOLLOPTS;


#define JBMAXCOLNAMELEN 128

enum { /** Error codes */
    JBEINVALIDCOLNAME = 9000, /**< Invalid collection name. */
    JBEINVALIDBSON = 9001, /**< Invalid bson object. */
    JBEQINVALIDQCONTROL = 9002, /**< Invalid query control field starting with '$'. */
    JBEQINOPNOTARRAY = 9003, /**< $strand, $stror, $in, $nin, $bt keys requires not empty array value. */
    JBEMETANVALID = 9004, /**< Inconsistent database metadata. */
    JBEFPATHINVALID = 9005, /**< Invalid field path value. */
    JBEQINVALIDQRX = 9006, /**< Invalid query regexp value. */
    JBEQRSSORTING = 9007, /**< Result set sorting error. */
    JBEQERROR = 9008 /**< Query generic error. */
};

enum { /** Database open modes */
    JBOREADER = 1 << 0, /**< Open as a reader. */
    JBOWRITER = 1 << 1, /**< Open as a writer. */
    JBOCREAT = 1 << 2, /**< Create if db file not exists. */
    JBOTRUNC = 1 << 3, /**< Truncate db on open. */
    JBONOLCK = 1 << 4, /**< Open without locking. */
    JBOLCKNB = 1 << 5, /**< Lock without blocking. */
    JBOTSYNC = 1 << 6 /**< Synchronize every transaction. */
};

enum { /** Index modes, index types. */
    JBIDXDROP = 1 << 0, /**< Drop index. */
    JBIDXDROPALL = 1 << 1, /**< Drop index for all types. */
    JBIDXOP = 1 << 2, /**< Optimize index. */
    JBIDXREBLD = 1 << 3, /**< Rebuild index. */
    JBIDXNUM = 1 << 4, /**< Number index. */
    JBIDXSTR = 1 << 5, /**< String index.*/
    JBIDXARR = 1 << 6, /**< Array token index. */
    JBIDXISTR = 1 << 7 /**< Case insensitive string index */
};

enum { /*< Query search mode flags in ejdbqrysearch() */
    JBQRYCOUNT = 1 /*< Query only count(*) */
};

/**
 * Get the message string corresponding to an error code.
 * @param ecode `ecode' specifies the error code.
 * @return The return value is the message string of the error code.
 */
EJDB_EXPORT const char *ejdberrmsg(int ecode);

/**
 * Get the last happened error code of a EJDB database object.
 * @param jb
 * @return The return value is the last happened error code.
 */
EJDB_EXPORT int ejdbecode(EJDB *jb);

/**
 * Create a EJDB database object. On error returns NULL.
 * Created pointer must be freed by ejdbdel()
 * @return The return value is the new EJDB database object or NULL if error.
 */
EJDB_EXPORT EJDB* ejdbnew(void);

/**
 * Delete database object. If the database is not closed, it is closed implicitly.
 * Note that the deleted object and its derivatives can not be used anymore
 * @param jb
 */
EJDB_EXPORT void ejdbdel(EJDB *jb);

/**
 * Close a table database object. If a writer opens a database but does not close it appropriately,
 * the database will be broken.
 * @param jb EJDB handle.
 * @return If successful return true, otherwise return false.
 */
EJDB_EXPORT bool ejdbclose(EJDB *jb);

/**
 * Opens EJDB database.
 * @param jb   Database object created with `ejdbnew'
 * @param path Path to the database file.
 * @param mode Open mode bitmask flags:
 * `JBOREADER` Open as a reader.
 * `JBOWRITER` Open as a writer.
 * `JBOCREAT` Create db if it not exists
 * `JBOTRUNC` Truncate db.
 * `JBONOLCK` Open without locking.
 * `JBOLCKNB` Lock without blocking.
 * `JBOTSYNC` Synchronize every transaction.
 * @return
 */
EJDB_EXPORT bool ejdbopen(EJDB *jb, const char *path, int mode);


/**
 * Return true if database is in open state
 * @param jb EJDB database hadle
 * @return True if database is in open state otherwise false
 */
EJDB_EXPORT bool ejdbisopen(EJDB *jb);

/**
 * Retrieve collection handle for collection specified `collname`.
 * If collection with specified name does't exists it will return NULL.
 * @param jb EJDB handle.
 * @param colname Name of collection.
 * @return If error NULL will be returned.
 */
EJDB_EXPORT EJCOLL* ejdbgetcoll(EJDB *jb, const char *colname);

/**
 * Same as ejdbgetcoll() but automatically creates new collection
 * if it does't exists.
 *
 * @param jb EJDB handle.
 * @param colname Name of collection.
 * @param opts Options applied only for newly created collection.
 *              For existing collections it takes no effect.
 *
 * @return Collection handle or NULL if error.
 */
EJDB_EXPORT EJCOLL* ejdbcreatecoll(EJDB *jb, const char *colname, EJCOLLOPTS *opts);

/**
 * Removes collections specified by `colname`
 * @param jb EJDB handle.
 * @param colname Name of collection.
 * @param unlink It true the collection db file and all of its index files will be removed.
 * @return If successful return true, otherwise return false.
 */
EJDB_EXPORT bool ejdbrmcoll(EJDB *jb, const char *colname, bool unlinkfile);

/**
 * Persist BSON object in the collection.
 * If saved bson does't have _id primary key then `oid` will be set to generated bson _id,
 * otherwise `oid` will be set to the current bson's _id field.
 *
 * @param coll JSON collection handle.
 * @param bson BSON object id pointer.
 * @return If successful return true, otherwise return false.
 */
EJDB_EXPORT bool ejdbsavebson(EJCOLL *coll, bson *bs, bson_oid_t *oid);

/**
 * Remove BSON object from collection.
 * The `oid` argument should points the primary key (_id)
 * of the bson record to be removed.
 * @param coll JSON collection ref.
 * @param oid BSON object id pointer.
 * @return
 */
EJDB_EXPORT bool ejdbrmbson(EJCOLL *coll, bson_oid_t *oid);

/**
 * Load BSON object with specified 'oid'.
 * If loaded bson is not NULL it must be freed by bson_del().
 * @param coll
 * @param oid
 * @return BSON object if exists otherwise return NULL.
 */
EJDB_EXPORT bson* ejdbloadbson(EJCOLL *coll, const bson_oid_t *oid);

/**
 * Create query object.
 * Sucessfully created queries must be destroyed with ejdbquerydel().
 *
 * EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy.
 *
 *  - Supported queries:
 *      - Simple matching of String OR Number OR Array value:
 *          -   {'json.field.path' : 'val', ...}
 *      - $not Negate operation.
 *          -   {'json.field.path' : {'$not' : val}} //Field not equal to val
 *          -   {'json.field.path' : {'$not' : {'$begin' : prefix}}} //Field not begins with val
 *      - $begin String starts with prefix
 *          -   {'json.field.path' : {'$begin' : prefix}}
 *      - $gt, $gte (>, >=) and $lt, $lte for number types:
 *          -   {'json.field.path' : {'$gt' : number}, ...}
 *      - $bt Between for number types:
 *          -   {'json.field.path' : {'$bt' : [num1, num2]}}
 *      - $in String OR Number OR Array val matches to value in specified array:
 *          -   {'json.field.path' : {'$in' : [val1, val2, val3]}}
 *      - $nin - Not IN
 *      - $strand String tokens OR String array val matches all tokens in specified array:
 *          -   {'json.field.path' : {'$strand' : [val1, val2, val3]}}
 *      - $stror String tokens OR String array val matches any token in specified array:
 *          -   {'json.field.path' : {'$stror' : [val1, val2, val3]}}
 *      - $exists Field existence matching:
 *          -   {'json.field.path' : {'$exists' : true|false}}
 *      - $icase Case insensitive string matching:
 *          -    {'json.field.path' : {'$icase' : 'val1'}} //icase matching
 *          -    {'name' : {'$icase' : {'$in' : ['théâtre - театр', 'hello world']}}} //icase matching with '$in' operation
 *          For case insensitive matching you can create special index of type: `JBIDXISTR`
 *
 *  NOTE: Negate operations: $not and $nin not using indexes
 *  so they can be slow in comparison to other matching operations.
 *
 *  NOTE: Only one index can be used in search query operation.
 *
 *  QUERY HINTS (specified by `hints` argument):
 *      - $max Maximum number in the result set
 *      - $skip Number of skipped results in the result set
 *      - $orderby Sorting order of query fields.
 *          Eg: ORDER BY field1 ASC, field2 DESC
 *          hints:    {
 *                      "$orderby" : {
 *                          "field1" : 1,
 *                          "field2" : -1
 *                      }
 *                    }
 *
 * Many query examples can be found in `testejdb/t2.c` test case.
 *
 * @param EJDB database handle.
 * @param qobj Main BSON query object.
 * @param orqobjs Array of additional OR query objects (joined with OR predicate).
 * @param orqobjsnum Number of OR query objects.
 * @param hints BSON object with query hints.
 * @return On success return query handle. On error returns NULL.
 */
EJDB_EXPORT EJQ* ejdbcreatequery(EJDB *jb, bson *qobj, bson *orqobjs, int orqobjsnum, bson *hints);

/**
 * Destroy query object created with ejdbcreatequery().
 * @param q
 */
EJDB_EXPORT void ejdbquerydel(EJQ *q);

/**
 * Set index for JSON field in EJDB collection.
 *
 *  - Available index types:
 *      - `JBIDXSTR` String index for JSON string values.
 *      - `JBIDXISTR` Case insensitive string index for JSON string values.
 *      - `JBIDXNUM` Index for JSON number values.
 *      - `JBIDXARR` Token index for JSON arrays and string values.
 *
 *  - One JSON field can have several indexes for different types.
 *
 *  - Available index operations:
 *      - `JBIDXDROP` Drop index of specified type.
 *              - Eg: flag = JBIDXDROP | JBIDXNUM (Drop number index)
 *      - `JBIDXDROPALL` Drop index for all types.
 *      - `JBIDXREBLD` Rebuild index of specified type.
 *      - `JBIDXOP` Optimize index of specified type. (Optimize the B+ tree index file)
 *
 *  Examples:
 *      - Set index for JSON path `addressbook.number` for strings and numbers:
 *          `ejdbsetindex(ccoll, "album.number", JBIDXSTR | JBIDXNUM)`
 *      - Set index for array:
 *          `ejdbsetindex(ccoll, "album.tags", JBIDXARR)`
 *      - Rebuild previous index:
 *          `ejdbsetindex(ccoll, "album.tags", JBIDXARR | JBIDXREBLD)`
 *
 *   Many index examples can be found in `testejdb/t2.c` test case.
 *
 * @param coll Collection handle.
 * @param ipath BSON field path.
 * @param flags Index flags.
 * @return
 */
EJDB_EXPORT bool ejdbsetindex(EJCOLL *coll, const char *ipath, int flags);

/**
 * Execute query against EJDB collection.
 *
 * @param jcoll EJDB database
 * @param q Query handle created with ejdbcreatequery()
 * @param count Output count pointer. Result set size will be stored into it.
 * @param qflags Execution flag. If JBQRYCOUNT is set the only count of matching records will be computed
 *         without resultset, this operation is analog of count(*) in SQL and can be faster than operations with resultsets.
 * @param log Optional extended string to collect debug information during query execution, can be NULL.
 * @return TCLIST with matched bson records data.
 * If (qflags & JBQRYCOUNT) then NULL will be returned
 * and only count reported.
 */
EJDB_EXPORT TCLIST* ejdbqrysearch(EJCOLL *jcoll, const EJQ *q, uint32_t *count, int qflags, TCXSTR *log);

/**
 * Synchronize content of a EJDB collection database with the file on device.
 * @param jcoll EJDB collection.
 * @return On success return true.
 */
EJDB_EXPORT bool ejdbsyncoll(EJCOLL *jcoll);

/**
 * Synchronize entire EJDB database and
 * all its collections with storage.
 * @param jb Database hand
 */
EJDB_EXPORT bool ejdbsyncdb(EJDB *jb);

/** Begin transaction for EJDB collection. */
EJDB_EXPORT bool ejdbtranbegin(EJCOLL *coll);

/** Commit transaction for EJDB collection. */
EJDB_EXPORT bool ejdbtrancommit(EJCOLL *coll);

/** Abort transaction for EJDB collection. */
EJDB_EXPORT bool ejdbtranabort(EJCOLL *coll);

EJDB_EXTERN_C_END

#endif        /* EJDB_H */