mdbxmou 0.1.34 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +5 -0
- package/README.md +60 -146
- package/package.json +4 -5
- package/src/async/envmou_keys.cpp +14 -7
- package/src/async/envmou_query.cpp +21 -10
- package/src/dbi.cpp +66 -0
- package/src/dbi.hpp +45 -0
- package/src/dbimou.cpp +192 -134
- package/src/dbimou.hpp +39 -24
- package/src/env_arg0.hpp +11 -5
- package/src/envmou.cpp +12 -2
- package/src/modulemou.cpp +25 -25
- package/src/querymou.cpp +3 -3
- package/src/txnmou.cpp +10 -2
- package/src/txnmou.hpp +2 -0
- package/src/valuemou.hpp +1 -1
package/CMakeLists.txt
CHANGED
|
@@ -7,6 +7,10 @@ add_definitions(-DNAPI_CPP_EXCEPTIONS)
|
|
|
7
7
|
set(CMAKE_CXX_STANDARD 17)
|
|
8
8
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
9
9
|
|
|
10
|
+
if (MSVC)
|
|
11
|
+
add_compile_options(/Zc:__cplusplus)
|
|
12
|
+
endif()
|
|
13
|
+
|
|
10
14
|
add_subdirectory("deps/libmdbx")
|
|
11
15
|
|
|
12
16
|
add_library(${PROJECT_NAME} SHARED
|
|
@@ -19,6 +23,7 @@ add_library(${PROJECT_NAME} SHARED
|
|
|
19
23
|
"src/querymou.cpp"
|
|
20
24
|
"src/envmou.cpp"
|
|
21
25
|
"src/txnmou.cpp"
|
|
26
|
+
"src/dbi.cpp"
|
|
22
27
|
"src/dbimou.cpp")
|
|
23
28
|
|
|
24
29
|
# Gives our library file a .node extension without any "lib" prefix
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ High-performance Node.js binding for libmdbx — a fast, lightweight, embedded k
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Synchronous API** — Direct MDBX operations in main thread
|
|
8
|
-
- **Asynchronous API** — Background operations
|
|
8
|
+
- **Asynchronous API** — Background operations with async/await
|
|
9
9
|
- **Transactions** — ACID transactions with read/write modes
|
|
10
10
|
- **Multiple key/value types** — String, binary, ordinal (integer) keys
|
|
11
11
|
- **Batch operations** — Efficient multi-key read/write
|
|
@@ -33,14 +33,14 @@ await env.open({
|
|
|
33
33
|
// Write data
|
|
34
34
|
const txn = env.startWrite();
|
|
35
35
|
const dbi = txn.createMap(MDBX_Param.keyMode.ordinal);
|
|
36
|
-
dbi.put(1, "hello");
|
|
37
|
-
dbi.put(2, "world");
|
|
36
|
+
dbi.put(txn, 1, "hello");
|
|
37
|
+
dbi.put(txn, 2, "world");
|
|
38
38
|
txn.commit();
|
|
39
39
|
|
|
40
40
|
// Read data
|
|
41
41
|
const readTxn = env.startRead();
|
|
42
42
|
const readDbi = readTxn.openMap(BigInt(MDBX_Param.keyMode.ordinal));
|
|
43
|
-
const value = readDbi.get(1);
|
|
43
|
+
const value = readDbi.get(readTxn, 1);
|
|
44
44
|
console.log(value); // "hello"
|
|
45
45
|
readTxn.commit();
|
|
46
46
|
|
|
@@ -180,32 +180,37 @@ txn.abort();
|
|
|
180
180
|
|
|
181
181
|
#### Methods
|
|
182
182
|
|
|
183
|
-
**put(key, value
|
|
183
|
+
**put(txn, key, value)**
|
|
184
184
|
```javascript
|
|
185
|
-
dbi.put(123, "value");
|
|
186
|
-
dbi.put("key", Buffer.from("binary data"));
|
|
185
|
+
dbi.put(txn, 123, "value");
|
|
186
|
+
dbi.put(txn, "key", Buffer.from("binary data"));
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
-
**get(key) → value**
|
|
189
|
+
**get(txn, key) → value**
|
|
190
190
|
```javascript
|
|
191
|
-
const value = dbi.get(123);
|
|
192
|
-
const binary = dbi.get("key");
|
|
191
|
+
const value = dbi.get(txn, 123);
|
|
192
|
+
const binary = dbi.get(txn, "key");
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
-
**del(key) → boolean**
|
|
195
|
+
**del(txn, key) → boolean**
|
|
196
196
|
```javascript
|
|
197
|
-
const deleted = dbi.del(123);
|
|
197
|
+
const deleted = dbi.del(txn, 123);
|
|
198
198
|
```
|
|
199
199
|
|
|
200
|
-
**
|
|
200
|
+
**has(txn, key) → boolean**
|
|
201
201
|
```javascript
|
|
202
|
-
const
|
|
202
|
+
const exists = dbi.has(txn, 123);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**stat(txn) → Object**
|
|
206
|
+
```javascript
|
|
207
|
+
const stats = dbi.stat(txn);
|
|
203
208
|
// { pageSize: 4096, depth: 1, entries: 10, ... }
|
|
204
209
|
```
|
|
205
210
|
|
|
206
|
-
**forEach(callback)**
|
|
211
|
+
**forEach(txn, callback)**
|
|
207
212
|
```javascript
|
|
208
|
-
dbi.forEach((key, value, index) => {
|
|
213
|
+
dbi.forEach(txn, (key, value, index) => {
|
|
209
214
|
console.log(`${key}: ${value}`);
|
|
210
215
|
return false; // continue iteration (or undefined)
|
|
211
216
|
// return true; // stop iteration
|
|
@@ -214,34 +219,37 @@ dbi.forEach((key, value, index) => {
|
|
|
214
219
|
|
|
215
220
|
> **Note**: forEach continues scanning while callback returns `undefined` or `false`, and stops when callback returns `true`.
|
|
216
221
|
|
|
217
|
-
**keys() → Array**
|
|
222
|
+
**keys(txn) → Array**
|
|
218
223
|
```javascript
|
|
219
224
|
// Get all keys
|
|
220
|
-
const allKeys = dbi.keys();
|
|
225
|
+
const allKeys = dbi.keys(txn);
|
|
221
226
|
```
|
|
222
227
|
|
|
223
|
-
**keysFrom(startKey, [limit], [cursorMode]) → Array**
|
|
228
|
+
**keysFrom(txn, startKey, [limit], [cursorMode]) → Array**
|
|
224
229
|
```javascript
|
|
225
230
|
// Get keys starting from specific key
|
|
226
|
-
const keys = dbi.keysFrom(42, 50); // 50 keys starting from 42
|
|
231
|
+
const keys = dbi.keysFrom(txn, 42, 50); // 50 keys starting from 42
|
|
227
232
|
|
|
228
233
|
// With cursor mode
|
|
229
|
-
const keys = dbi.keysFrom(42, 50, 'keyGreaterOrEqual');
|
|
234
|
+
const keys = dbi.keysFrom(txn, 42, 50, 'keyGreaterOrEqual');
|
|
230
235
|
|
|
231
236
|
// BigInt keys
|
|
232
|
-
const bigIntKeys = dbi.keysFrom(42n, 50);
|
|
237
|
+
const bigIntKeys = dbi.keysFrom(txn, 42n, 50);
|
|
233
238
|
|
|
234
239
|
// Key equal mode (for multi-value databases)
|
|
235
|
-
const equalKeys = dbi.keysFrom(5, 10, 'keyEqual');
|
|
240
|
+
const equalKeys = dbi.keysFrom(txn, 5, 10, 'keyEqual');
|
|
236
241
|
```
|
|
237
242
|
|
|
238
|
-
**
|
|
243
|
+
**drop(txn, [delete_db]) → void**
|
|
239
244
|
```javascript
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
+
// Clear database contents (keep structure)
|
|
246
|
+
dbi.drop(txn, false);
|
|
247
|
+
|
|
248
|
+
// Delete database completely
|
|
249
|
+
dbi.drop(txn, true);
|
|
250
|
+
|
|
251
|
+
// Default behavior (clear contents)
|
|
252
|
+
dbi.drop(txn);
|
|
245
253
|
```
|
|
246
254
|
|
|
247
255
|
## Key and Value Types
|
|
@@ -280,7 +288,7 @@ function syncExample() {
|
|
|
280
288
|
const dbi = writeTxn.createMap(MDBX_Param.keyMode.ordinal);
|
|
281
289
|
|
|
282
290
|
for (let i = 0; i < 1000; i++) {
|
|
283
|
-
dbi.put(i, `value_${i}`);
|
|
291
|
+
dbi.put(writeTxn, i, `value_${i}`);
|
|
284
292
|
}
|
|
285
293
|
writeTxn.commit();
|
|
286
294
|
|
|
@@ -288,17 +296,17 @@ function syncExample() {
|
|
|
288
296
|
const readTxn = env.startRead();
|
|
289
297
|
const readDbi = readTxn.openMap(MDBX_Param.keyMode.ordinal); // keys as numbers
|
|
290
298
|
|
|
291
|
-
const value = readDbi.get(42);
|
|
299
|
+
const value = readDbi.get(readTxn, 42);
|
|
292
300
|
console.log(value); // "value_42"
|
|
293
301
|
|
|
294
302
|
// Iterate with cursor
|
|
295
|
-
readDbi.forEach((key, value, index) => {
|
|
303
|
+
readDbi.forEach(readTxn, (key, value, index) => {
|
|
296
304
|
console.log(`Key ${key} (type: ${typeof key}): ${value}`); // key is number
|
|
297
305
|
return index >= 9; // stop after 10 items (indices 0-9)
|
|
298
306
|
});
|
|
299
307
|
|
|
300
308
|
// Get specific keys
|
|
301
|
-
const someKeys = readDbi.keysFrom(100,
|
|
309
|
+
const someKeys = readDbi.keysFrom(readTxn, 100, 50);
|
|
302
310
|
console.log(`Keys 100-149:`, someKeys); // array of numbers
|
|
303
311
|
|
|
304
312
|
readTxn.commit();
|
|
@@ -316,7 +324,7 @@ async function asyncExample() {
|
|
|
316
324
|
const dbi = writeTxn.createMap(MDBX_Param.keyMode.ordinal);
|
|
317
325
|
|
|
318
326
|
for (let i = 0; i < 1000; i++) {
|
|
319
|
-
dbi.put(i, `value_${i}`);
|
|
327
|
+
dbi.put(writeTxn, i, `value_${i}`);
|
|
320
328
|
}
|
|
321
329
|
writeTxn.commit();
|
|
322
330
|
|
|
@@ -324,17 +332,17 @@ async function asyncExample() {
|
|
|
324
332
|
const readTxn = env.startRead();
|
|
325
333
|
const readDbi = readTxn.openMap(BigInt(MDBX_Param.keyMode.ordinal)); // keys as BigInts
|
|
326
334
|
|
|
327
|
-
const value = readDbi.get(42);
|
|
335
|
+
const value = readDbi.get(readTxn, 42);
|
|
328
336
|
console.log(value); // "value_42"
|
|
329
337
|
|
|
330
338
|
// Iterate with BigInt keys
|
|
331
|
-
readDbi.forEach((key, value, index) => {
|
|
339
|
+
readDbi.forEach(readTxn, (key, value, index) => {
|
|
332
340
|
console.log(`Key ${key} (type: ${typeof key}): ${value}`); // key is bigint
|
|
333
341
|
return index >= 9; // stop after 10 items (indices 0-9)
|
|
334
342
|
});
|
|
335
343
|
|
|
336
344
|
// Get BigInt keys
|
|
337
|
-
const bigIntKeys = readDbi.keysFrom(100n,
|
|
345
|
+
const bigIntKeys = readDbi.keysFrom(readTxn, 100n, 50);
|
|
338
346
|
console.log(`Keys 100n-149n:`, bigIntKeys); // array of BigInts
|
|
339
347
|
|
|
340
348
|
readTxn.commit();
|
|
@@ -355,16 +363,16 @@ function keyTypesExample() {
|
|
|
355
363
|
const dbi = txn.createMap(MDBX_Param.keyMode.ordinal);
|
|
356
364
|
|
|
357
365
|
// Store some data
|
|
358
|
-
dbi.put(1, "one");
|
|
359
|
-
dbi.put(2, "two");
|
|
360
|
-
dbi.put(3, "three");
|
|
366
|
+
dbi.put(txn, 1, "one");
|
|
367
|
+
dbi.put(txn, 2, "two");
|
|
368
|
+
dbi.put(txn, 3, "three");
|
|
361
369
|
txn.commit();
|
|
362
370
|
|
|
363
371
|
// Read with number keyMode
|
|
364
372
|
const readTxn1 = env.startRead();
|
|
365
373
|
const numberDbi = readTxn1.openMap(MDBX_Param.keyMode.ordinal);
|
|
366
374
|
|
|
367
|
-
numberDbi.forEach((key, value) => {
|
|
375
|
+
numberDbi.forEach(readTxn1, (key, value) => {
|
|
368
376
|
console.log(`Number key: ${key} (${typeof key})`); // number
|
|
369
377
|
// return undefined; // continue iteration (default)
|
|
370
378
|
});
|
|
@@ -374,7 +382,7 @@ function keyTypesExample() {
|
|
|
374
382
|
const readTxn2 = env.startRead();
|
|
375
383
|
const bigintDbi = readTxn2.openMap(BigInt(MDBX_Param.keyMode.ordinal));
|
|
376
384
|
|
|
377
|
-
bigintDbi.forEach((key, value) => {
|
|
385
|
+
bigintDbi.forEach(readTxn2, (key, value) => {
|
|
378
386
|
console.log(`BigInt key: ${key} (${typeof key})`); // bigint
|
|
379
387
|
// return false; // continue iteration
|
|
380
388
|
});
|
|
@@ -398,7 +406,7 @@ function cursorExample() {
|
|
|
398
406
|
|
|
399
407
|
// Store test data
|
|
400
408
|
for (let i = 0; i < 100; i++) {
|
|
401
|
-
dbi.put(i, `value_${i}`);
|
|
409
|
+
dbi.put(txn, i, `value_${i}`);
|
|
402
410
|
}
|
|
403
411
|
txn.commit();
|
|
404
412
|
|
|
@@ -406,25 +414,25 @@ function cursorExample() {
|
|
|
406
414
|
const readDbi = readTxn.openMap(MDBX_Param.keyMode.ordinal);
|
|
407
415
|
|
|
408
416
|
// Get all keys
|
|
409
|
-
const allKeys = readDbi.keys();
|
|
417
|
+
const allKeys = readDbi.keys(readTxn);
|
|
410
418
|
console.log(`Total keys: ${allKeys.length}`);
|
|
411
419
|
|
|
412
420
|
// Get limited keys - use keysFrom with limit
|
|
413
|
-
const firstTen = readDbi.keysFrom(0, 10);
|
|
421
|
+
const firstTen = readDbi.keysFrom(readTxn, 0, 10);
|
|
414
422
|
console.log(`First 10 keys:`, firstTen);
|
|
415
423
|
|
|
416
424
|
// Get keys from specific position
|
|
417
|
-
const fromFifty = readDbi.keysFrom(50, 20);
|
|
425
|
+
const fromFifty = readDbi.keysFrom(readTxn, 50, 20);
|
|
418
426
|
console.log(`Keys 50-69:`, fromFifty);
|
|
419
427
|
|
|
420
428
|
// Reverse iteration - need manual logic or forEach
|
|
421
|
-
const allKeysForReverse = readDbi.keys();
|
|
429
|
+
const allKeysForReverse = readDbi.keys(readTxn);
|
|
422
430
|
const lastTen = allKeysForReverse.slice(-10).reverse();
|
|
423
431
|
console.log(`Last 10 keys:`, lastTen);
|
|
424
432
|
|
|
425
433
|
// Manual iteration with forEach
|
|
426
434
|
let count = 0;
|
|
427
|
-
readDbi.forEach((key, value, index) => {
|
|
435
|
+
readDbi.forEach(readTxn, (key, value, index) => {
|
|
428
436
|
if (key >= 80) {
|
|
429
437
|
console.log(`Key ${key}: ${value}`);
|
|
430
438
|
count++;
|
|
@@ -437,52 +445,6 @@ function cursorExample() {
|
|
|
437
445
|
}
|
|
438
446
|
```
|
|
439
447
|
|
|
440
|
-
### Batch Operations (Asynchronous)
|
|
441
|
-
|
|
442
|
-
```javascript
|
|
443
|
-
const { MDBX_Async_Env } = require('mdbxmou/lib/mdbx_evn_async');
|
|
444
|
-
const { MDBX_Param } = require('mdbxmou');
|
|
445
|
-
|
|
446
|
-
async function batchExample() {
|
|
447
|
-
const env = new MDBX_Async_Env();
|
|
448
|
-
await env.open({ path: './async-data' });
|
|
449
|
-
|
|
450
|
-
// Write transaction in worker thread
|
|
451
|
-
const writeTxn = await env.startWrite();
|
|
452
|
-
const dbi = await writeTxn.openMap({
|
|
453
|
-
keyMode: MDBX_Param.keyMode.ordinal,
|
|
454
|
-
create: true
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
// Batch write
|
|
458
|
-
await dbi.putBatch([
|
|
459
|
-
{ key: 1n, value: "one" },
|
|
460
|
-
{ key: 2n, value: "two" },
|
|
461
|
-
{ key: 3n, value: "three" }
|
|
462
|
-
]);
|
|
463
|
-
|
|
464
|
-
await writeTxn.commit();
|
|
465
|
-
|
|
466
|
-
// Read transaction in worker thread
|
|
467
|
-
const readTxn = await env.startRead();
|
|
468
|
-
const readDbi = await readTxn.openMap({
|
|
469
|
-
keyMode: MDBX_Param.keyMode.ordinal
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
// Batch read
|
|
473
|
-
const results = await readDbi.getBatch([1n, 2n, 3n]);
|
|
474
|
-
results.forEach((result, i) => {
|
|
475
|
-
if (result.found) {
|
|
476
|
-
console.log(`Key ${result.key}: ${result.value}`);
|
|
477
|
-
}
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
await readTxn.commit();
|
|
481
|
-
await env.close();
|
|
482
|
-
await env.terminate();
|
|
483
|
-
}
|
|
484
|
-
```
|
|
485
|
-
|
|
486
448
|
### Query API (Advanced Async)
|
|
487
449
|
|
|
488
450
|
```javascript
|
|
@@ -519,54 +481,6 @@ async function queryExample() {
|
|
|
519
481
|
}
|
|
520
482
|
```
|
|
521
483
|
|
|
522
|
-
### Worker Thread Example
|
|
523
|
-
|
|
524
|
-
```javascript
|
|
525
|
-
const { MDBX_Async_Env } = require('mdbxmou/lib/mdbx_evn_async');
|
|
526
|
-
|
|
527
|
-
async function workerExample() {
|
|
528
|
-
// Single worker thread for all async operations
|
|
529
|
-
const env = new MDBX_Async_Env();
|
|
530
|
-
await env.open({ path: './worker-data' });
|
|
531
|
-
|
|
532
|
-
// Each transaction runs in the same worker thread
|
|
533
|
-
const txn1 = await env.startWrite();
|
|
534
|
-
const dbi1 = await txn1.openMap({
|
|
535
|
-
keyMode: MDBX_Param.keyMode.ordinal,
|
|
536
|
-
create: true
|
|
537
|
-
});
|
|
538
|
-
await dbi1.put(1n, "worker-value-1");
|
|
539
|
-
await txn1.commit();
|
|
540
|
-
|
|
541
|
-
// Another transaction in the same worker
|
|
542
|
-
const txn2 = await env.startWrite();
|
|
543
|
-
const dbi2 = await txn2.openMap({
|
|
544
|
-
keyMode: MDBX_Param.keyMode.ordinal,
|
|
545
|
-
create: true
|
|
546
|
-
});
|
|
547
|
-
await dbi2.put(2n, "worker-value-2");
|
|
548
|
-
await txn2.commit();
|
|
549
|
-
|
|
550
|
-
// Read transaction
|
|
551
|
-
const readTxn = await env.startRead();
|
|
552
|
-
const readDbi = await readTxn.openMap({
|
|
553
|
-
keyMode: MDBX_Param.keyMode.ordinal
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
const results = await readDbi.getBatch([1n, 2n]);
|
|
557
|
-
results.forEach(r => {
|
|
558
|
-
if (r.found) {
|
|
559
|
-
console.log(`Key ${r.key}: ${r.value}`);
|
|
560
|
-
}
|
|
561
|
-
});
|
|
562
|
-
|
|
563
|
-
await readTxn.commit();
|
|
564
|
-
|
|
565
|
-
await env.close();
|
|
566
|
-
await env.terminate(); // Terminate the worker thread
|
|
567
|
-
}
|
|
568
|
-
```
|
|
569
|
-
|
|
570
484
|
## Error Handling
|
|
571
485
|
|
|
572
486
|
```javascript
|
|
@@ -578,7 +492,7 @@ try {
|
|
|
578
492
|
const dbi = txn.createMap(MDBX_Param.keyMode.ordinal);
|
|
579
493
|
|
|
580
494
|
// This might throw if key already exists with MDBX_NOOVERWRITE
|
|
581
|
-
dbi.put(123, "value", MDBX_Param.putFlag.nooverwrite);
|
|
495
|
+
dbi.put(txn, 123, "value", MDBX_Param.putFlag.nooverwrite);
|
|
582
496
|
|
|
583
497
|
txn.commit();
|
|
584
498
|
} catch (error) {
|
|
@@ -624,10 +538,10 @@ Note: For ordinal (integer) keys, use keyFlag.number or keyFlag.bigint to specif
|
|
|
624
538
|
## Performance Tips
|
|
625
539
|
|
|
626
540
|
1. **Use ordinal keys** for integer data - much faster than string keys
|
|
627
|
-
2. **Batch operations** - Use query API
|
|
541
|
+
2. **Batch operations** - Use query API for bulk operations
|
|
628
542
|
3. **Reuse transactions** - Keep read transactions open for multiple operations
|
|
629
|
-
4. **
|
|
630
|
-
5. **
|
|
543
|
+
4. **Memory mapping** - MDBX uses memory-mapped files for zero-copy access
|
|
544
|
+
5. **Transaction scope** - Always pass transaction object to DBI methods
|
|
631
545
|
|
|
632
546
|
## License
|
|
633
547
|
|
package/package.json
CHANGED
|
@@ -16,17 +16,16 @@
|
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
18
|
"e3": "node ./test/e3.js",
|
|
19
|
+
"e33": "node ./test/e33.js",
|
|
19
20
|
"e4": "node ./test/e4.js",
|
|
20
21
|
"e5": "node ./test/e5.js",
|
|
21
|
-
"test": "node ./test/e3.js && node ./test/e4.js && node ./test/e5.js",
|
|
22
22
|
"build": "node build.js",
|
|
23
|
-
"
|
|
24
|
-
"install": "node build.js"
|
|
25
|
-
"!prepublishOnly": "./prepare-npm.sh"
|
|
23
|
+
"build-dev": "node build-dev.js",
|
|
24
|
+
"install": "node build.js"
|
|
26
25
|
},
|
|
27
26
|
"gypfile": true,
|
|
28
27
|
"name": "mdbxmou",
|
|
29
|
-
"version": "0.
|
|
28
|
+
"version": "0.2.0",
|
|
30
29
|
"description": "Node bindings for mdbx",
|
|
31
30
|
"repository": {
|
|
32
31
|
"type": "git",
|
|
@@ -35,16 +35,23 @@ static Napi::Value write_row(Napi::Env env, const keys_line& row)
|
|
|
35
35
|
auto key_mode = row.key_mod;
|
|
36
36
|
auto key_flag = row.key_flag;
|
|
37
37
|
auto js_arr = Napi::Array::New(env, param.size());
|
|
38
|
-
for (std::
|
|
38
|
+
for (std::uint32_t j = 0; j < param.size(); ++j) {
|
|
39
39
|
const auto& item = param[j];
|
|
40
|
+
Napi::Value key_value;
|
|
40
41
|
if (key_mode.val & key_mode::ordinal) {
|
|
41
|
-
|
|
42
|
-
Napi::Number::New(env,
|
|
42
|
+
if (key_flag.val & base_flag::number) {
|
|
43
|
+
key_value = Napi::Number::New(env, static_cast<double>(item.id_buf));
|
|
44
|
+
} else {
|
|
45
|
+
key_value = Napi::BigInt::New(env, item.id_buf);
|
|
46
|
+
}
|
|
43
47
|
} else {
|
|
44
|
-
|
|
45
|
-
Napi::String::New(env, item.key_buf.data(), item.key_buf.size())
|
|
46
|
-
|
|
48
|
+
if (key_flag.val & base_flag::string) {
|
|
49
|
+
key_value = Napi::String::New(env, item.key_buf.data(), item.key_buf.size());
|
|
50
|
+
} else {
|
|
51
|
+
key_value = Napi::Buffer<char>::Copy(env, item.key_buf.data(), item.key_buf.size());
|
|
52
|
+
}
|
|
47
53
|
}
|
|
54
|
+
js_arr.Set(j, key_value);
|
|
48
55
|
}
|
|
49
56
|
return js_arr;
|
|
50
57
|
}
|
|
@@ -62,7 +69,7 @@ void async_keys::OnOK()
|
|
|
62
69
|
}
|
|
63
70
|
|
|
64
71
|
Napi::Array result = Napi::Array::New(env, query_.size());
|
|
65
|
-
for (std::
|
|
72
|
+
for (std::uint32_t i = 0; i < query_.size(); ++i) {
|
|
66
73
|
Napi::Object js_row = Napi::Object::New(env);
|
|
67
74
|
const auto& row = query_[i];
|
|
68
75
|
if (!row.db.empty()) {
|
|
@@ -47,15 +47,22 @@ static Napi::Value write_row(Napi::Env env, const query_line& row)
|
|
|
47
47
|
auto js_arr = Napi::Array::New(env, param.size());
|
|
48
48
|
for (std::size_t j = 0; j < param.size(); ++j) {
|
|
49
49
|
const auto& item = param[j];
|
|
50
|
+
Napi::Value key_value;
|
|
50
51
|
Napi::Object js_item = Napi::Object::New(env);
|
|
51
52
|
if (key_mode.val & key_mode::ordinal) {
|
|
52
|
-
|
|
53
|
-
Napi::Number::New(env,
|
|
53
|
+
if (key_flag.val & base_flag::number) {
|
|
54
|
+
key_value = Napi::Number::New(env, static_cast<double>(item.id_buf));
|
|
55
|
+
} else {
|
|
56
|
+
key_value = Napi::BigInt::New(env, item.id_buf);
|
|
57
|
+
}
|
|
54
58
|
} else {
|
|
55
|
-
|
|
56
|
-
Napi::String::New(env, item.key_buf.data(), item.key_buf.size())
|
|
57
|
-
|
|
59
|
+
if (key_flag.val & base_flag::string) {
|
|
60
|
+
key_value = Napi::String::New(env, item.key_buf.data(), item.key_buf.size());
|
|
61
|
+
} else {
|
|
62
|
+
key_value = Napi::Buffer<char>::Copy(env, item.key_buf.data(), item.key_buf.size());
|
|
63
|
+
}
|
|
58
64
|
}
|
|
65
|
+
js_item.Set("key", key_value);
|
|
59
66
|
|
|
60
67
|
// все методы которые должны показать value в результате
|
|
61
68
|
const auto mask{query_mode::get|query_mode::upsert|
|
|
@@ -67,9 +74,13 @@ static Napi::Value write_row(Napi::Env env, const query_line& row)
|
|
|
67
74
|
js_item.Set("value", env.Null());
|
|
68
75
|
} else {
|
|
69
76
|
auto value_flag = row.value_flag;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
Napi::
|
|
77
|
+
Napi::Value val_value;
|
|
78
|
+
if (value_flag.val & base_flag::string) {
|
|
79
|
+
val_value = Napi::String::New(env, val_buf.data(), val_buf.size());
|
|
80
|
+
} else {
|
|
81
|
+
val_value = Napi::Buffer<char>::Copy(env, val_buf.data(), val_buf.size());
|
|
82
|
+
}
|
|
83
|
+
js_item.Set("value", val_value);
|
|
73
84
|
}
|
|
74
85
|
}
|
|
75
86
|
|
|
@@ -77,7 +88,7 @@ static Napi::Value write_row(Napi::Env env, const query_line& row)
|
|
|
77
88
|
if (mode.val & query_mode::del) {
|
|
78
89
|
js_item.Set("found", Napi::Boolean::New(env, item.found));
|
|
79
90
|
}
|
|
80
|
-
js_arr.Set(j, js_item);
|
|
91
|
+
js_arr.Set(static_cast<uint32_t>(j), js_item);
|
|
81
92
|
}
|
|
82
93
|
return js_arr;
|
|
83
94
|
}
|
|
@@ -103,7 +114,7 @@ void async_query::OnOK()
|
|
|
103
114
|
if (!row.db.empty()) {
|
|
104
115
|
js_row.Set("db", Napi::String::New(env, row.db_name));
|
|
105
116
|
}
|
|
106
|
-
result.Set(i, write_row(env, row));
|
|
117
|
+
result.Set(static_cast<uint32_t>(i), write_row(env, row));
|
|
107
118
|
}
|
|
108
119
|
|
|
109
120
|
deferred_.Resolve(result);
|
package/src/dbi.cpp
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#include "dbi.hpp"
|
|
2
|
+
|
|
3
|
+
namespace mdbxmou {
|
|
4
|
+
|
|
5
|
+
MDBX_stat dbi::get_stat(const MDBX_txn* txn, MDBX_dbi dbi)
|
|
6
|
+
{
|
|
7
|
+
MDBX_stat stat;
|
|
8
|
+
auto rc = mdbx_dbi_stat(txn, dbi, &stat, sizeof(stat));
|
|
9
|
+
if (rc != MDBX_SUCCESS) {
|
|
10
|
+
throw std::runtime_error(mdbx_strerror(rc));
|
|
11
|
+
}
|
|
12
|
+
return stat;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
valuemou dbi::get(const MDBX_txn* txn, const keymou& key) const
|
|
16
|
+
{
|
|
17
|
+
valuemou val{};
|
|
18
|
+
auto rc = mdbx_get(txn, id_, key, val);
|
|
19
|
+
if (rc == MDBX_NOTFOUND)
|
|
20
|
+
return {};
|
|
21
|
+
if (rc != MDBX_SUCCESS) {
|
|
22
|
+
throw std::runtime_error(mdbx_strerror(rc));
|
|
23
|
+
}
|
|
24
|
+
return val;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
void dbi::put(MDBX_txn* txn, const keymou& key, valuemou& value, MDBX_put_flags_t flags)
|
|
28
|
+
{
|
|
29
|
+
auto rc = mdbx_put(txn, id_, key, value, flags);
|
|
30
|
+
if (rc != MDBX_SUCCESS) {
|
|
31
|
+
throw std::runtime_error(mdbx_strerror(rc));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
bool dbi::del(MDBX_txn* txn, const keymou& key)
|
|
36
|
+
{
|
|
37
|
+
auto rc = mdbx_del(txn, id_, key, nullptr);
|
|
38
|
+
if (rc == MDBX_NOTFOUND) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
if (rc != MDBX_SUCCESS) {
|
|
42
|
+
throw std::runtime_error(mdbx_strerror(rc));
|
|
43
|
+
}
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
cursormou_managed dbi::open_cursor(MDBX_txn* txn) const
|
|
49
|
+
{
|
|
50
|
+
MDBX_cursor* cursor_ptr;
|
|
51
|
+
auto rc = mdbx_cursor_open(txn, id_, &cursor_ptr);
|
|
52
|
+
if (rc != MDBX_SUCCESS) {
|
|
53
|
+
throw std::runtime_error(mdbx_strerror(rc));
|
|
54
|
+
}
|
|
55
|
+
return cursormou_managed{ cursor_ptr };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
void dbi::drop(MDBX_txn* txn, bool delete_db)
|
|
59
|
+
{
|
|
60
|
+
auto rc = mdbx_drop(txn, id_, delete_db);
|
|
61
|
+
if (rc != MDBX_SUCCESS) {
|
|
62
|
+
throw std::runtime_error(mdbx_strerror(rc));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
} // namespace mdbxmou
|
package/src/dbi.hpp
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "valuemou.hpp"
|
|
4
|
+
#include <memory>
|
|
5
|
+
|
|
6
|
+
namespace mdbxmou {
|
|
7
|
+
|
|
8
|
+
class dbi
|
|
9
|
+
{
|
|
10
|
+
protected:
|
|
11
|
+
MDBX_dbi id_{};
|
|
12
|
+
|
|
13
|
+
public:
|
|
14
|
+
dbi() = default;
|
|
15
|
+
|
|
16
|
+
void attach(MDBX_dbi id) noexcept {
|
|
17
|
+
id_ = id;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static MDBX_stat get_stat(const MDBX_txn* txn, MDBX_dbi dbi);
|
|
21
|
+
|
|
22
|
+
MDBX_stat get_stat(const MDBX_txn* txn) const
|
|
23
|
+
{
|
|
24
|
+
return get_stat(txn, id_);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
valuemou get(const MDBX_txn* txn, const keymou& key) const;
|
|
28
|
+
|
|
29
|
+
bool has(const MDBX_txn* txn, const keymou& key) const
|
|
30
|
+
{
|
|
31
|
+
return !get(txn, key).is_null();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
void put(MDBX_txn* txn, const keymou& key, valuemou& value,
|
|
35
|
+
MDBX_put_flags_t flags = MDBX_UPSERT);
|
|
36
|
+
|
|
37
|
+
bool del(MDBX_txn* txn, const keymou& key);
|
|
38
|
+
|
|
39
|
+
cursormou_managed open_cursor(MDBX_txn* txn) const;
|
|
40
|
+
|
|
41
|
+
// Drop database or delete it
|
|
42
|
+
void drop(MDBX_txn* txn, bool delete_db = false);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
} // namespace mdbxmou
|