mdbxmou 0.3.11 → 0.3.12
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/README.md +113 -11
- package/lib/async.d.mts +6 -4
- package/lib/types.d.ts +17 -2
- package/package.json +2 -1
- package/src/async/envmou_keys.cpp +1 -1
- package/src/async/envmou_query.cpp +14 -13
- package/src/convmou.cpp +17 -0
- package/src/convmou.hpp +4 -8
- package/src/cursormou.cpp +2 -1
- package/src/cursormou.hpp +1 -0
- package/src/dbimou.cpp +71 -18
- package/src/dbimou.hpp +3 -1
- package/src/modulemou.cpp +14 -0
- package/src/querymou.cpp +15 -15
- package/src/querymou.hpp +3 -1
- package/src/txnmou.cpp +3 -3
- package/src/typemou.hpp +85 -5
- package/src/valuemou.hpp +62 -83
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Node.js binding for [libmdbx](https://github.com/Mithril-mine/libmdbx) — a fas
|
|
|
7
7
|
- **Synchronous API** — Direct MDBX operations in main thread
|
|
8
8
|
- **Asynchronous API** — Background operations with async/await
|
|
9
9
|
- **Transactions** — ACID transactions with read/write modes
|
|
10
|
-
- **Multiple key/value types** — String, binary, ordinal
|
|
10
|
+
- **Multiple key/value types** — String, binary, ordinal keys and ordinal duplicate values
|
|
11
11
|
- **Batch operations** — Efficient multi-key read/write
|
|
12
12
|
- **Memory-mapped** — High-performance memory-mapped I/O
|
|
13
13
|
|
|
@@ -86,6 +86,8 @@ Options:
|
|
|
86
86
|
- `keyFlag` - Default key encoding for all operations (optional, defaults to Buffer)
|
|
87
87
|
- Only `string` can be set (ordinal mode uses `number`/`bigint` separately)
|
|
88
88
|
- `valueFlag` - Default value encoding for all operations (optional, defaults to Buffer)
|
|
89
|
+
- `string` affects normal string values
|
|
90
|
+
- `number` and `bigint` are meaningful for `valueMode.multiOrdinal`
|
|
89
91
|
- `maxDbi` - Maximum number of databases (optional, default `32`)
|
|
90
92
|
- `mode` - Filesystem permissions mode (optional, default `0664`)
|
|
91
93
|
- `geometry` - Map size/geometry options (optional)
|
|
@@ -190,14 +192,21 @@ const txn = env.startRead();
|
|
|
190
192
|
```javascript
|
|
191
193
|
const result = await env.query([
|
|
192
194
|
{
|
|
193
|
-
|
|
194
|
-
keyMode: MDBX_Param.keyMode.ordinal,
|
|
195
|
+
dbi,
|
|
195
196
|
mode: MDBX_Param.queryMode.get,
|
|
196
197
|
item: [{ key: 1 }, { key: 2 }]
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
dbi,
|
|
201
|
+
mode: MDBX_Param.queryMode.upsert,
|
|
202
|
+
putFlag: MDBX_Param.putFlag.noOverwrite,
|
|
203
|
+
item: [{ key: 3, value: "v3" }]
|
|
197
204
|
}
|
|
198
205
|
]);
|
|
199
206
|
```
|
|
200
207
|
|
|
208
|
+
`query()` uses the passed `dbi` and inherits key/value settings from it. `queryMode` selects the operation (`get`, `del`, or base write mode), and optional `putFlag` adds write-only MDBX flags. In `query()` only `noOverwrite`, `noDupData`, `current`, `append`, and `appendDup` are supported.
|
|
209
|
+
|
|
201
210
|
### Transaction
|
|
202
211
|
|
|
203
212
|
#### Methods
|
|
@@ -271,6 +280,8 @@ const dbi = txn.openMap({
|
|
|
271
280
|
> - `keyMode: BigInt(number)` → keys returned as `BigInt`
|
|
272
281
|
> - When you pass `keyMode.ordinal` as a positional argument (Number/BigInt), it also updates `keyFlag` to number/bigint unless a numeric keyFlag was already set in env or explicitly provided.
|
|
273
282
|
|
|
283
|
+
> **Note**: When `valueMode.multiOrdinal` is used and `valueFlag` is not specified, values are returned as `number` by default. Set `valueFlag: MDBX_Param.valueFlag.bigint` if you need `BigInt` on read.
|
|
284
|
+
|
|
274
285
|
**commit()**
|
|
275
286
|
```javascript
|
|
276
287
|
txn.commit();
|
|
@@ -285,10 +296,16 @@ txn.abort();
|
|
|
285
296
|
|
|
286
297
|
#### Methods
|
|
287
298
|
|
|
288
|
-
**put(txn, key, value)**
|
|
299
|
+
**put(txn, key, value, [flags])**
|
|
289
300
|
```javascript
|
|
290
301
|
dbi.put(txn, 123, "value");
|
|
291
302
|
dbi.put(txn, "key", Buffer.from("binary data"));
|
|
303
|
+
|
|
304
|
+
// Insert only if key does not exist
|
|
305
|
+
dbi.put(txn, 123, "value", MDBX_Param.putFlag.noOverwrite);
|
|
306
|
+
|
|
307
|
+
// Fast append for sorted inserts
|
|
308
|
+
dbi.put(txn, 124, "value", MDBX_Param.putFlag.append);
|
|
292
309
|
```
|
|
293
310
|
|
|
294
311
|
**get(txn, key) → value**
|
|
@@ -297,6 +314,8 @@ const value = dbi.get(txn, 123);
|
|
|
297
314
|
const binary = dbi.get(txn, "key");
|
|
298
315
|
```
|
|
299
316
|
|
|
317
|
+
For `valueMode.multiOrdinal`, `get()` returns the first duplicate value for the key, decoded as `number` by default.
|
|
318
|
+
|
|
300
319
|
**del(txn, key) → boolean**
|
|
301
320
|
```javascript
|
|
302
321
|
const deleted = dbi.del(txn, 123);
|
|
@@ -355,6 +374,12 @@ const rows = dbi.getRange(txn, { start: 10, end: 15 });
|
|
|
355
374
|
// ]
|
|
356
375
|
```
|
|
357
376
|
|
|
377
|
+
**getCount(txn, [options]) → number**
|
|
378
|
+
```javascript
|
|
379
|
+
const total = dbi.getCount(txn, { start: 10, end: 20 });
|
|
380
|
+
// 11
|
|
381
|
+
```
|
|
382
|
+
|
|
358
383
|
**keysRange(txn, [options]) → Array**
|
|
359
384
|
```javascript
|
|
360
385
|
const keys = dbi.keysRange(txn, { start: 10, end: 20, limit: 5 });
|
|
@@ -378,6 +403,7 @@ Range options:
|
|
|
378
403
|
- `reverse` - scan from upper bound to lower bound
|
|
379
404
|
- `limit` - maximum number of returned items
|
|
380
405
|
- `offset` - skip N items after initial positioning
|
|
406
|
+
- `getCount()` ignores `offset` and `limit` and returns the total size of the bounded range
|
|
381
407
|
|
|
382
408
|
**drop(txn, [delete_db]) → void**
|
|
383
409
|
```javascript
|
|
@@ -461,7 +487,7 @@ Insert or update a record at cursor position.
|
|
|
461
487
|
cursor.put('newKey', 'newValue');
|
|
462
488
|
|
|
463
489
|
// With flags (MDBX_NOOVERWRITE, etc.)
|
|
464
|
-
cursor.put('key', 'value', MDBX_Param.
|
|
490
|
+
cursor.put('key', 'value', MDBX_Param.putFlag.noOverwrite);
|
|
465
491
|
```
|
|
466
492
|
|
|
467
493
|
**del([flags]) → boolean**
|
|
@@ -595,12 +621,20 @@ txn.commit();
|
|
|
595
621
|
### Value Modes (MDBX_Param.valueMode)
|
|
596
622
|
|
|
597
623
|
- **single** - Single value per key (default)
|
|
598
|
-
- **multi** -
|
|
624
|
+
- **multi** - `MDBX_DUPSORT`, multiple values per key
|
|
625
|
+
- **multiReverse** - `MDBX_DUPSORT | MDBX_REVERSEDUP`
|
|
626
|
+
- **multiSamelength** - `MDBX_DUPSORT | MDBX_DUPFIXED`
|
|
627
|
+
- **multiOrdinal** - `MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERDUP`
|
|
628
|
+
- **multiReverseSamelength** - `MDBX_DUPSORT | MDBX_REVERSEDUP | MDBX_DUPFIXED`
|
|
599
629
|
|
|
600
630
|
### Value Flags (MDBX_Param.valueFlag)
|
|
601
631
|
|
|
602
|
-
- **binary** - Raw binary data (default)
|
|
632
|
+
- **binary** - Raw binary data (default, represented by `0`)
|
|
603
633
|
- **string** - UTF-8 strings
|
|
634
|
+
- **number** - Numeric decode for ordinal duplicate values
|
|
635
|
+
- **bigint** - BigInt decode for ordinal duplicate values
|
|
636
|
+
|
|
637
|
+
`valueFlag.number` and `valueFlag.bigint` matter primarily for `valueMode.multiOrdinal`. For ordinary values, use Buffer (default) or `valueFlag.string`.
|
|
604
638
|
|
|
605
639
|
## Examples
|
|
606
640
|
|
|
@@ -815,6 +849,9 @@ function rangeExample() {
|
|
|
815
849
|
// { key: 6, value: 'value_6' }
|
|
816
850
|
// ]
|
|
817
851
|
|
|
852
|
+
const total = readDbi.getCount(readTxn, { start: 3, end: 8 });
|
|
853
|
+
console.log(total); // 6
|
|
854
|
+
|
|
818
855
|
const keys = readDbi.keysRange(readTxn, {
|
|
819
856
|
start: 3,
|
|
820
857
|
end: 8,
|
|
@@ -838,6 +875,44 @@ function rangeExample() {
|
|
|
838
875
|
rangeExample();
|
|
839
876
|
```
|
|
840
877
|
|
|
878
|
+
### MultiOrdinal Values
|
|
879
|
+
|
|
880
|
+
```javascript
|
|
881
|
+
const { MDBX_Env, MDBX_Param } = require('mdbxmou');
|
|
882
|
+
|
|
883
|
+
function multiOrdinalExample() {
|
|
884
|
+
const env = new MDBX_Env();
|
|
885
|
+
env.openSync({ path: './multi-ordinal-data' });
|
|
886
|
+
|
|
887
|
+
const writeTxn = env.startWrite();
|
|
888
|
+
const dbi = writeTxn.createMap({
|
|
889
|
+
name: 'dup-ids',
|
|
890
|
+
keyMode: MDBX_Param.keyMode.ordinal,
|
|
891
|
+
valueMode: MDBX_Param.valueMode.multiOrdinal
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
dbi.put(writeTxn, 5, 30);
|
|
895
|
+
dbi.put(writeTxn, 5, 10);
|
|
896
|
+
dbi.put(writeTxn, 5, 20n);
|
|
897
|
+
writeTxn.commit();
|
|
898
|
+
|
|
899
|
+
const readTxn = env.startRead();
|
|
900
|
+
const readDbi = readTxn.openMap({
|
|
901
|
+
name: 'dup-ids',
|
|
902
|
+
keyMode: MDBX_Param.keyMode.ordinal,
|
|
903
|
+
valueMode: MDBX_Param.valueMode.multiOrdinal
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
console.log(readDbi.get(readTxn, 5)); // 10
|
|
907
|
+
console.log(readDbi.valuesRange(readTxn, { start: 5, end: 5 })); // [10, 20, 30]
|
|
908
|
+
|
|
909
|
+
readTxn.commit();
|
|
910
|
+
env.closeSync();
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
multiOrdinalExample();
|
|
914
|
+
```
|
|
915
|
+
|
|
841
916
|
### Query API (Advanced Async)
|
|
842
917
|
|
|
843
918
|
```javascript
|
|
@@ -856,7 +931,8 @@ async function queryExample() {
|
|
|
856
931
|
const results = await env.query([
|
|
857
932
|
{
|
|
858
933
|
dbi,
|
|
859
|
-
mode: MDBX_Param.queryMode.
|
|
934
|
+
mode: MDBX_Param.queryMode.upsert,
|
|
935
|
+
putFlag: MDBX_Param.putFlag.noOverwrite,
|
|
860
936
|
item: [
|
|
861
937
|
{ key: 1, value: JSON.stringify({ name: "Alice" }) },
|
|
862
938
|
{ key: 2, value: JSON.stringify({ name: "Bob" }) }
|
|
@@ -981,7 +1057,21 @@ MDBX_Param.keyFlag.number // Number type (used with ordinal mode)
|
|
|
981
1057
|
MDBX_Param.keyFlag.bigint // BigInt type (used with ordinal mode)
|
|
982
1058
|
// Default - Buffer representation
|
|
983
1059
|
|
|
1060
|
+
// Value modes
|
|
1061
|
+
MDBX_Param.valueMode.multi // MDBX_DUPSORT
|
|
1062
|
+
MDBX_Param.valueMode.multiReverse // MDBX_DUPSORT | MDBX_REVERSEDUP
|
|
1063
|
+
MDBX_Param.valueMode.multiSamelength // MDBX_DUPSORT | MDBX_DUPFIXED
|
|
1064
|
+
MDBX_Param.valueMode.multiOrdinal // MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERDUP
|
|
1065
|
+
MDBX_Param.valueMode.multiReverseSamelength // MDBX_DUPSORT | MDBX_REVERSEDUP | MDBX_DUPFIXED
|
|
1066
|
+
|
|
1067
|
+
// Value flags (optional, control value representation)
|
|
1068
|
+
MDBX_Param.valueFlag.string // UTF-8 string values
|
|
1069
|
+
MDBX_Param.valueFlag.number // Number values for multiOrdinal
|
|
1070
|
+
MDBX_Param.valueFlag.bigint // BigInt values for multiOrdinal
|
|
1071
|
+
// Default - Buffer representation
|
|
1072
|
+
|
|
984
1073
|
Note: For ordinal (integer) keys, use keyFlag.number or keyFlag.bigint to specify the data type.
|
|
1074
|
+
For `valueMode.multiOrdinal`, values are returned as `number` by default, or as `bigint` when `valueFlag.bigint` is used.
|
|
985
1075
|
```
|
|
986
1076
|
|
|
987
1077
|
### Environment Flags
|
|
@@ -1027,11 +1117,23 @@ Note: For ordinal (integer) keys, use keyFlag.number or keyFlag.bigint to specif
|
|
|
1027
1117
|
|
|
1028
1118
|
### Query Modes
|
|
1029
1119
|
- `MDBX_Param.queryMode.get` - Read operations
|
|
1030
|
-
- `MDBX_Param.queryMode.upsert` -
|
|
1031
|
-
- `MDBX_Param.queryMode.update` -
|
|
1032
|
-
- `MDBX_Param.queryMode.insertUnique` -
|
|
1120
|
+
- `MDBX_Param.queryMode.upsert` - Base write mode (insert or update)
|
|
1121
|
+
- `MDBX_Param.queryMode.update` - Base write mode with `MDBX_CURRENT`
|
|
1122
|
+
- `MDBX_Param.queryMode.insertUnique` - Base write mode with `MDBX_NOOVERWRITE`
|
|
1033
1123
|
- `MDBX_Param.queryMode.del` - Delete operations
|
|
1034
1124
|
|
|
1125
|
+
### Put Flags
|
|
1126
|
+
- `MDBX_Param.putFlag.noOverwrite` - `MDBX_NOOVERWRITE`
|
|
1127
|
+
- `MDBX_Param.putFlag.noDupData` - `MDBX_NODUPDATA`
|
|
1128
|
+
- `MDBX_Param.putFlag.current` - `MDBX_CURRENT`
|
|
1129
|
+
- `MDBX_Param.putFlag.allDups` - `MDBX_ALLDUPS`
|
|
1130
|
+
- `MDBX_Param.putFlag.reserve` - `MDBX_RESERVE`
|
|
1131
|
+
- `MDBX_Param.putFlag.append` - `MDBX_APPEND`
|
|
1132
|
+
- `MDBX_Param.putFlag.appendDup` - `MDBX_APPENDDUP`
|
|
1133
|
+
- `MDBX_Param.putFlag.multiple` - `MDBX_MULTIPLE`
|
|
1134
|
+
|
|
1135
|
+
For `env.query()` write requests, only `noOverwrite`, `noDupData`, `current`, `append`, and `appendDup` are supported.
|
|
1136
|
+
|
|
1035
1137
|
### Cursor Modes
|
|
1036
1138
|
- `MDBX_Param.cursorMode.first` - First key
|
|
1037
1139
|
- `MDBX_Param.cursorMode.last` - Last key
|
package/lib/async.d.mts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { MDBXDbiStat, MDBXEnvOpenOptions, MDBXKey
|
|
1
|
+
import type { MDBXDbiStat, MDBXEnvOpenOptions, MDBXKey } from "./types.js";
|
|
2
|
+
|
|
3
|
+
type MDBXAsyncValue = Buffer | string;
|
|
2
4
|
|
|
3
5
|
export interface MDBXAsyncMapOpenOptions {
|
|
4
6
|
name?: string;
|
|
@@ -35,15 +37,15 @@ export interface MDBXAsyncDelBatchResultItem {
|
|
|
35
37
|
export declare class MDBX_Async_Dbi {
|
|
36
38
|
readonly meta: MDBXAsyncDbiMeta;
|
|
37
39
|
|
|
38
|
-
put(key: MDBXKey, value:
|
|
40
|
+
put(key: MDBXKey, value: MDBXAsyncValue, flags?: number): Promise<boolean>;
|
|
39
41
|
get(key: MDBXKey): Promise<string | null | undefined>;
|
|
40
42
|
del(key: MDBXKey): Promise<boolean>;
|
|
41
43
|
stat(): Promise<MDBXDbiStat>;
|
|
42
44
|
|
|
43
|
-
forEach(cb: (key: MDBXKey, value:
|
|
45
|
+
forEach(cb: (key: MDBXKey, value: MDBXAsyncValue, index: number) => void): Promise<void>;
|
|
44
46
|
|
|
45
47
|
getBatch(keys: MDBXKey[]): Promise<MDBXAsyncGetBatchResultItem[]>;
|
|
46
|
-
putBatch(items: Array<{ key: MDBXKey; value:
|
|
48
|
+
putBatch(items: Array<{ key: MDBXKey; value: MDBXAsyncValue }>, flags?: number): Promise<MDBXAsyncPutBatchResultItem[]>;
|
|
47
49
|
delBatch(keys: MDBXKey[]): Promise<MDBXAsyncDelBatchResultItem[]>;
|
|
48
50
|
}
|
|
49
51
|
|
package/lib/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
|
|
3
3
|
export type MDBXKey = Buffer | string | number | bigint;
|
|
4
|
-
export type MDBXValue = Buffer | string;
|
|
4
|
+
export type MDBXValue = Buffer | string | number | bigint;
|
|
5
5
|
|
|
6
6
|
export type MDBXCursorMode =
|
|
7
7
|
| number
|
|
@@ -202,7 +202,7 @@ export interface MDBX_Dbi<K extends MDBXKey = MDBXKey, V extends MDBXValue = MDB
|
|
|
202
202
|
readonly keyFlag: number;
|
|
203
203
|
readonly valueFlag: number;
|
|
204
204
|
|
|
205
|
-
put(txn: MDBX_Txn, key: K, value: MDBXValue): void;
|
|
205
|
+
put(txn: MDBX_Txn, key: K, value: MDBXValue, flags?: number): void;
|
|
206
206
|
get(txn: MDBX_Txn, key: K): V | undefined;
|
|
207
207
|
del(txn: MDBX_Txn, key: K): boolean;
|
|
208
208
|
has(txn: MDBX_Txn, key: K): boolean;
|
|
@@ -224,6 +224,7 @@ export interface MDBX_Dbi<K extends MDBXKey = MDBXKey, V extends MDBXValue = MDB
|
|
|
224
224
|
keys(txn: MDBX_Txn): K[];
|
|
225
225
|
keysFrom(txn: MDBX_Txn, fromKey: K, limit?: number, cursorMode?: MDBXCursorMode): K[];
|
|
226
226
|
getRange(txn: MDBX_Txn, options?: MDBXRangeOptions<K>): MDBXCursorResult<K, V>[];
|
|
227
|
+
getCount(txn: MDBX_Txn, options?: MDBXRangeOptions<K>): number;
|
|
227
228
|
keysRange(txn: MDBX_Txn, options?: MDBXRangeOptions<K>): K[];
|
|
228
229
|
valuesRange(txn: MDBX_Txn, options?: MDBXRangeOptions<K>): V[];
|
|
229
230
|
drop(txn: MDBX_Txn, deleteDb?: boolean): void;
|
|
@@ -264,6 +265,7 @@ export interface MDBXQueryRequest {
|
|
|
264
265
|
dbi: MDBX_Dbi;
|
|
265
266
|
mode?: number;
|
|
266
267
|
queryMode?: number;
|
|
268
|
+
putFlag?: number;
|
|
267
269
|
item: MDBXQueryItem[];
|
|
268
270
|
}
|
|
269
271
|
|
|
@@ -374,6 +376,8 @@ export interface MDBX_Param {
|
|
|
374
376
|
|
|
375
377
|
readonly valueFlag: {
|
|
376
378
|
readonly string: number;
|
|
379
|
+
readonly number: number;
|
|
380
|
+
readonly bigint: number;
|
|
377
381
|
};
|
|
378
382
|
|
|
379
383
|
readonly dbMode: {
|
|
@@ -389,6 +393,17 @@ export interface MDBX_Param {
|
|
|
389
393
|
readonly del: number;
|
|
390
394
|
};
|
|
391
395
|
|
|
396
|
+
readonly putFlag: {
|
|
397
|
+
readonly noOverwrite: number;
|
|
398
|
+
readonly noDupData: number;
|
|
399
|
+
readonly current: number;
|
|
400
|
+
readonly allDups: number;
|
|
401
|
+
readonly reserve: number;
|
|
402
|
+
readonly append: number;
|
|
403
|
+
readonly appendDup: number;
|
|
404
|
+
readonly multiple: number;
|
|
405
|
+
};
|
|
406
|
+
|
|
392
407
|
readonly cursorMode: {
|
|
393
408
|
readonly first: number;
|
|
394
409
|
readonly last: number;
|
package/package.json
CHANGED
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"e5": "node ./test/e5.js",
|
|
62
62
|
"e7": "node ./test/e7.js",
|
|
63
63
|
"e8": "node ./test/e8.js",
|
|
64
|
+
"e9": "node ./test/e9.js",
|
|
64
65
|
"test:types": "node ./test/types/run.mjs",
|
|
65
66
|
"build": "node build.js",
|
|
66
67
|
"build-dev": "node build-dev.js",
|
|
@@ -68,7 +69,7 @@
|
|
|
68
69
|
},
|
|
69
70
|
"gypfile": true,
|
|
70
71
|
"name": "mdbxmou",
|
|
71
|
-
"version": "0.3.
|
|
72
|
+
"version": "0.3.12",
|
|
72
73
|
"description": "Node bindings for mdbx",
|
|
73
74
|
"repository": {
|
|
74
75
|
"type": "git",
|
|
@@ -67,7 +67,7 @@ void async_keys::Execute()
|
|
|
67
67
|
static Napi::Value write_row(Napi::Env env, const keys_line& row)
|
|
68
68
|
{
|
|
69
69
|
auto& param = row.item;
|
|
70
|
-
convmou conv{row.key_mod, row.key_flag};
|
|
70
|
+
convmou conv{row.key_mod, {}, row.key_flag, {}};
|
|
71
71
|
auto js_arr = Napi::Array::New(env, param.size());
|
|
72
72
|
for (std::uint32_t j = 0; j < param.size(); ++j) {
|
|
73
73
|
const auto& item = param[j];
|
|
@@ -13,9 +13,9 @@ void async_query::Execute()
|
|
|
13
13
|
{
|
|
14
14
|
mdbx::map_handle dbi{req.id};
|
|
15
15
|
auto mode = req.mode;
|
|
16
|
-
if (mode.
|
|
16
|
+
if (mode.is_get()) {
|
|
17
17
|
do_get(txn, dbi, req);
|
|
18
|
-
} else if (mode.
|
|
18
|
+
} else if (mode.is_del()) {
|
|
19
19
|
do_del(txn, dbi, req);
|
|
20
20
|
} else {
|
|
21
21
|
do_put(txn, dbi, req);
|
|
@@ -33,7 +33,7 @@ static Napi::Value write_row(Napi::Env env, const query_line& row)
|
|
|
33
33
|
{
|
|
34
34
|
auto& param = row.item;
|
|
35
35
|
auto mode = row.mode;
|
|
36
|
-
convmou conv{row.key_mod, row.key_flag, row.value_flag};
|
|
36
|
+
convmou conv{row.key_mod, row.val_mod, row.key_flag, row.value_flag};
|
|
37
37
|
auto js_arr = Napi::Array::New(env, param.size());
|
|
38
38
|
for (std::size_t j = 0; j < param.size(); ++j) {
|
|
39
39
|
const auto& item = param[j];
|
|
@@ -43,13 +43,11 @@ static Napi::Value write_row(Napi::Env env, const query_line& row)
|
|
|
43
43
|
keymou{item.key_buf};
|
|
44
44
|
js_item.Set("key", conv.convert_key(env, key));
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
const auto mask{query_mode::get|query_mode::upsert|
|
|
48
|
-
query_mode::update|query_mode::insert_unique};
|
|
49
|
-
if (mode.val & mask)
|
|
50
|
-
{
|
|
46
|
+
if (mode.is_get() || mode.is_write()) {
|
|
51
47
|
auto& val_buf = item.val_buf;
|
|
52
|
-
if (val_buf.empty()) {
|
|
48
|
+
if (is_ordinal(row.val_mod) && mode.is_write() && val_buf.empty()) {
|
|
49
|
+
js_item.Set("value", conv.convert_value(env, valuemou{item.val_num}));
|
|
50
|
+
} else if (val_buf.empty()) {
|
|
53
51
|
js_item.Set("value", env.Null());
|
|
54
52
|
} else {
|
|
55
53
|
js_item.Set("value",
|
|
@@ -58,7 +56,7 @@ static Napi::Value write_row(Napi::Env env, const query_line& row)
|
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
// выдадим флаги удаления и успешности
|
|
61
|
-
if (mode.
|
|
59
|
+
if (mode.is_del()) {
|
|
62
60
|
js_item.Set("found", Napi::Boolean::New(env, item.found));
|
|
63
61
|
}
|
|
64
62
|
js_arr.Set(static_cast<uint32_t>(j), js_item);
|
|
@@ -133,15 +131,18 @@ void async_query::do_get(const txnmou_managed& txn,
|
|
|
133
131
|
void async_query::do_put(txnmou_managed& txn,
|
|
134
132
|
mdbx::map_handle dbi, query_line& arg0)
|
|
135
133
|
{
|
|
136
|
-
auto
|
|
134
|
+
auto flags = static_cast<MDBX_put_flags_t>(
|
|
135
|
+
arg0.mode.write_flags() | arg0.put_flags.val);
|
|
137
136
|
// очищаем put флаги
|
|
138
137
|
auto key_mode = arg0.key_mod;
|
|
139
138
|
for (auto& q : arg0.item)
|
|
140
139
|
{
|
|
141
140
|
auto key = mdbx::is_ordinal(key_mode) ?
|
|
142
141
|
keymou{q.id_buf} : keymou{q.key_buf};
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
valuemou val = is_ordinal(arg0.val_mod) ?
|
|
143
|
+
valuemou{q.val_num} :
|
|
144
|
+
valuemou{q.val_buf};
|
|
145
|
+
mdbx::error::success_or_throw(txn.put(dbi, key, &val, flags));
|
|
145
146
|
}
|
|
146
147
|
}
|
|
147
148
|
|
package/src/convmou.cpp
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
#include "convmou.hpp"
|
|
2
|
+
#include "dbimou.hpp"
|
|
2
3
|
|
|
3
4
|
namespace mdbxmou {
|
|
4
5
|
|
|
6
|
+
convmou convmou::for_dbi(const dbimou& dbi) noexcept
|
|
7
|
+
{
|
|
8
|
+
return {
|
|
9
|
+
dbi.get_key_mode(),
|
|
10
|
+
dbi.get_value_mode(),
|
|
11
|
+
dbi.get_key_flag(),
|
|
12
|
+
dbi.get_value_flag()
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
5
16
|
Napi::Value convmou::convert_key(const Napi::Env& env, const keymou& key) const
|
|
6
17
|
{
|
|
7
18
|
if (mdbx::is_ordinal(key_mode_)) {
|
|
@@ -17,6 +28,12 @@ Napi::Value convmou::convert_key(const Napi::Env& env, const keymou& key) const
|
|
|
17
28
|
|
|
18
29
|
Napi::Value convmou::convert_value(const Napi::Env& env, const valuemou& val) const
|
|
19
30
|
{
|
|
31
|
+
if (is_ordinal(value_mode_)) {
|
|
32
|
+
return (value_flag_ & base_flag::bigint) ?
|
|
33
|
+
val.to_bigint(env) :
|
|
34
|
+
val.to_number(env);
|
|
35
|
+
}
|
|
36
|
+
|
|
20
37
|
return (value_flag_ & base_flag::string) ?
|
|
21
38
|
val.to_string(env) :
|
|
22
39
|
val.to_buffer(env);
|
package/src/convmou.hpp
CHANGED
|
@@ -4,20 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
namespace mdbxmou {
|
|
6
6
|
|
|
7
|
+
class dbimou;
|
|
8
|
+
|
|
7
9
|
struct convmou
|
|
8
10
|
{
|
|
9
11
|
key_mode key_mode_{};
|
|
12
|
+
value_mode value_mode_{};
|
|
10
13
|
base_flag key_flag_{};
|
|
11
14
|
base_flag value_flag_{};
|
|
12
15
|
|
|
13
|
-
convmou()
|
|
14
|
-
|
|
15
|
-
convmou(key_mode key_mode, base_flag key_flag,
|
|
16
|
-
base_flag value_flag = {}) noexcept
|
|
17
|
-
: key_mode_{key_mode}
|
|
18
|
-
, key_flag_{key_flag}
|
|
19
|
-
, value_flag_{value_flag}
|
|
20
|
-
{ }
|
|
16
|
+
static convmou for_dbi(const dbimou& dbi) noexcept;
|
|
21
17
|
|
|
22
18
|
Napi::Value convert_key(const Napi::Env& env, const keymou& key) const;
|
|
23
19
|
|
package/src/cursormou.cpp
CHANGED
|
@@ -230,7 +230,8 @@ namespace mdbxmou
|
|
|
230
230
|
keymou::from(info[0], env, key_num_) :
|
|
231
231
|
keymou::from(info[0], env, key_buf_);
|
|
232
232
|
|
|
233
|
-
valuemou val = valuemou::from(info[1], env, val_buf_
|
|
233
|
+
valuemou val = valuemou::from(info[1], env, val_buf_, val_num_,
|
|
234
|
+
is_ordinal(dbi_->get_value_mode()));
|
|
234
235
|
|
|
235
236
|
// Опциональный флаг put_mode (по умолчанию MDBX_UPSERT)
|
|
236
237
|
MDBX_put_flags_t flags = MDBX_UPSERT;
|
package/src/cursormou.hpp
CHANGED
package/src/dbimou.cpp
CHANGED
|
@@ -165,14 +165,13 @@ MDBX_cursor_op range_turn_op(const range_options& options)
|
|
|
165
165
|
return options.reverse ? MDBX_PREV : MDBX_NEXT;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
|
|
168
|
+
template<class Fn>
|
|
169
|
+
std::size_t scan_range(dbimou& self, txnmou& txn, const range_options& options, Fn&& fn)
|
|
169
170
|
{
|
|
170
|
-
Napi::Array result = Napi::Array::New(env);
|
|
171
171
|
if (options.limit == 0) {
|
|
172
|
-
return
|
|
172
|
+
return 0;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
auto conv = self.get_convmou();
|
|
176
175
|
auto cursor = self.open_cursor(txn);
|
|
177
176
|
mdbx::slice key{};
|
|
178
177
|
mdbx::slice value{};
|
|
@@ -186,7 +185,7 @@ Napi::Array collect_range(const Napi::Env& env, dbimou& self, txnmou& txn, const
|
|
|
186
185
|
}
|
|
187
186
|
|
|
188
187
|
if (!cursor_get(cursor, range_start_op(options), key, value)) {
|
|
189
|
-
return
|
|
188
|
+
return 0;
|
|
190
189
|
}
|
|
191
190
|
|
|
192
191
|
std::size_t skipped{};
|
|
@@ -201,17 +200,8 @@ Napi::Array collect_range(const Napi::Env& env, dbimou& self, txnmou& txn, const
|
|
|
201
200
|
if (skipped < options.offset) {
|
|
202
201
|
++skipped;
|
|
203
202
|
} else {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
result.Set(index, conv.make_result(env, keymou{key}, valuemou{value}));
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
case range_output::keys:
|
|
210
|
-
result.Set(index, conv.convert_key(env, keymou{key}));
|
|
211
|
-
break;
|
|
212
|
-
case range_output::values:
|
|
213
|
-
result.Set(index, conv.convert_value(env, valuemou{value}));
|
|
214
|
-
break;
|
|
203
|
+
if (fn(keymou{key}, valuemou{value}, index)) {
|
|
204
|
+
break;
|
|
215
205
|
}
|
|
216
206
|
|
|
217
207
|
++index;
|
|
@@ -225,9 +215,39 @@ Napi::Array collect_range(const Napi::Env& env, dbimou& self, txnmou& txn, const
|
|
|
225
215
|
}
|
|
226
216
|
}
|
|
227
217
|
|
|
218
|
+
return index;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
Napi::Array collect_range(const Napi::Env& env, dbimou& self, txnmou& txn, const range_options& options, range_output output)
|
|
222
|
+
{
|
|
223
|
+
Napi::Array result = Napi::Array::New(env);
|
|
224
|
+
auto conv = self.get_convmou();
|
|
225
|
+
scan_range(self, txn, options, [&](const keymou& key, const valuemou& value, std::size_t index) {
|
|
226
|
+
switch (output) {
|
|
227
|
+
case range_output::items:
|
|
228
|
+
result.Set(index, conv.make_result(env, key, value));
|
|
229
|
+
break;
|
|
230
|
+
case range_output::keys:
|
|
231
|
+
result.Set(index, conv.convert_key(env, key));
|
|
232
|
+
break;
|
|
233
|
+
case range_output::values:
|
|
234
|
+
result.Set(index, conv.convert_value(env, value));
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
return false;
|
|
238
|
+
});
|
|
228
239
|
return result;
|
|
229
240
|
}
|
|
230
241
|
|
|
242
|
+
std::size_t count_range(dbimou& self, txnmou& txn, range_options options)
|
|
243
|
+
{
|
|
244
|
+
options.offset = 0;
|
|
245
|
+
options.limit = std::numeric_limits<std::size_t>::max();
|
|
246
|
+
return scan_range(self, txn, options, [](const keymou&, const valuemou&, std::size_t) {
|
|
247
|
+
return false;
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
231
251
|
Napi::Value run_range_query(const Napi::CallbackInfo& info, dbimou& self, const char* method_name, range_output output)
|
|
232
252
|
{
|
|
233
253
|
Napi::Env env = info.Env();
|
|
@@ -247,6 +267,26 @@ Napi::Value run_range_query(const Napi::CallbackInfo& info, dbimou& self, const
|
|
|
247
267
|
}
|
|
248
268
|
}
|
|
249
269
|
|
|
270
|
+
Napi::Value run_range_count(const Napi::CallbackInfo& info, dbimou& self, const char* method_name)
|
|
271
|
+
{
|
|
272
|
+
Napi::Env env = info.Env();
|
|
273
|
+
if (info.Length() < 1) {
|
|
274
|
+
throw Napi::TypeError::New(env, std::string(method_name) + ": txnmou required");
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
auto txn = txnmou::unwrap_checked(env, info[0], method_name);
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
auto options = info.Length() > 1 ?
|
|
281
|
+
parse_range_options(env, info[1], self) :
|
|
282
|
+
range_options{};
|
|
283
|
+
auto count = count_range(self, *txn, options);
|
|
284
|
+
return Napi::Number::New(env, static_cast<double>(count));
|
|
285
|
+
} catch (const std::exception& e) {
|
|
286
|
+
throw Napi::Error::New(env, std::string(method_name) + ": " + e.what());
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
250
290
|
} // namespace
|
|
251
291
|
|
|
252
292
|
Napi::FunctionReference dbimou::ctor{};
|
|
@@ -263,6 +303,7 @@ void dbimou::init(const char *class_name, Napi::Env env)
|
|
|
263
303
|
InstanceMethod("keys", &dbimou::keys),
|
|
264
304
|
InstanceMethod("keysFrom", &dbimou::keys_from),
|
|
265
305
|
InstanceMethod("getRange", &dbimou::get_range),
|
|
306
|
+
InstanceMethod("getCount", &dbimou::get_count),
|
|
266
307
|
InstanceMethod("keysRange", &dbimou::keys_range),
|
|
267
308
|
InstanceMethod("valuesRange", &dbimou::values_range),
|
|
268
309
|
InstanceMethod("drop", &dbimou::drop),
|
|
@@ -294,8 +335,15 @@ Napi::Value dbimou::put(const Napi::CallbackInfo& info)
|
|
|
294
335
|
keymou::from(info[1], env, t) :
|
|
295
336
|
keymou::from(info[1], env, key_buf_);
|
|
296
337
|
|
|
297
|
-
auto val = valuemou::from(info[2], env, val_buf_);
|
|
298
|
-
|
|
338
|
+
auto val = valuemou::from(info[2], env, val_buf_, val_num_, is_ordinal(value_mode_));
|
|
339
|
+
MDBX_put_flags_t flags = MDBX_UPSERT;
|
|
340
|
+
if (arg_len > 3 && !info[3].IsUndefined() && !info[3].IsNull()) {
|
|
341
|
+
if (!info[3].IsNumber()) {
|
|
342
|
+
throw Napi::TypeError::New(env, "put: flags must be a number");
|
|
343
|
+
}
|
|
344
|
+
flags = put_flag::parse(info[3]);
|
|
345
|
+
}
|
|
346
|
+
dbi::put(*txn, key, val, flags);
|
|
299
347
|
} catch (const std::exception& e) {
|
|
300
348
|
throw Napi::Error::New(env, std::string("put: ") + e.what());
|
|
301
349
|
}
|
|
@@ -709,6 +757,11 @@ Napi::Value dbimou::get_range(const Napi::CallbackInfo& info)
|
|
|
709
757
|
return run_range_query(info, *this, "getRange", range_output::items);
|
|
710
758
|
}
|
|
711
759
|
|
|
760
|
+
Napi::Value dbimou::get_count(const Napi::CallbackInfo& info)
|
|
761
|
+
{
|
|
762
|
+
return run_range_count(info, *this, "getCount");
|
|
763
|
+
}
|
|
764
|
+
|
|
712
765
|
Napi::Value dbimou::keys_range(const Napi::CallbackInfo& info)
|
|
713
766
|
{
|
|
714
767
|
return run_range_query(info, *this, "keysRange", range_output::keys);
|
package/src/dbimou.hpp
CHANGED
|
@@ -25,6 +25,7 @@ class dbimou final
|
|
|
25
25
|
|
|
26
26
|
buffer_type key_buf_{};
|
|
27
27
|
buffer_type val_buf_{};
|
|
28
|
+
std::uint64_t val_num_{};
|
|
28
29
|
|
|
29
30
|
public:
|
|
30
31
|
static Napi::FunctionReference ctor;
|
|
@@ -73,6 +74,7 @@ public:
|
|
|
73
74
|
Napi::Value keys(const Napi::CallbackInfo&);
|
|
74
75
|
Napi::Value keys_from(const Napi::CallbackInfo&);
|
|
75
76
|
Napi::Value get_range(const Napi::CallbackInfo&);
|
|
77
|
+
Napi::Value get_count(const Napi::CallbackInfo&);
|
|
76
78
|
Napi::Value keys_range(const Napi::CallbackInfo&);
|
|
77
79
|
Napi::Value values_range(const Napi::CallbackInfo&);
|
|
78
80
|
Napi::Value drop(const Napi::CallbackInfo&);
|
|
@@ -124,7 +126,7 @@ public:
|
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
convmou get_convmou() const noexcept {
|
|
127
|
-
return
|
|
129
|
+
return convmou::for_dbi(*this);
|
|
128
130
|
}
|
|
129
131
|
};
|
|
130
132
|
|
package/src/modulemou.cpp
CHANGED
|
@@ -80,6 +80,8 @@ Napi::Object Init(Napi::Env env, Napi::Object exports)
|
|
|
80
80
|
|
|
81
81
|
Napi::Object value_flag = Napi::Object::New(env);
|
|
82
82
|
MDBXMOU_DECLARE_FLAG_NAME(value_flag, "string", base_flag::string);
|
|
83
|
+
MDBXMOU_DECLARE_FLAG_NAME(value_flag, "number", base_flag::number);
|
|
84
|
+
MDBXMOU_DECLARE_FLAG_NAME(value_flag, "bigint", base_flag::bigint);
|
|
83
85
|
mdbx_mou.Set("valueFlag", value_flag);
|
|
84
86
|
|
|
85
87
|
using mdbxmou::db_mode;
|
|
@@ -97,6 +99,18 @@ Napi::Object Init(Napi::Env env, Napi::Object exports)
|
|
|
97
99
|
MDBXMOU_DECLARE_FLAG_NAME(queryMode, "del", query_mode::del);
|
|
98
100
|
mdbx_mou.Set("queryMode", queryMode);
|
|
99
101
|
|
|
102
|
+
using mdbxmou::put_flag;
|
|
103
|
+
Napi::Object putFlag = Napi::Object::New(env);
|
|
104
|
+
MDBXMOU_DECLARE_FLAG_NAME(putFlag, "noOverwrite", put_flag::no_overwrite);
|
|
105
|
+
MDBXMOU_DECLARE_FLAG_NAME(putFlag, "noDupData", put_flag::no_dup_data);
|
|
106
|
+
MDBXMOU_DECLARE_FLAG_NAME(putFlag, "current", put_flag::current);
|
|
107
|
+
MDBXMOU_DECLARE_FLAG_NAME(putFlag, "allDups", put_flag::all_dups);
|
|
108
|
+
MDBXMOU_DECLARE_FLAG_NAME(putFlag, "reserve", put_flag::reserve);
|
|
109
|
+
MDBXMOU_DECLARE_FLAG_NAME(putFlag, "append", put_flag::append);
|
|
110
|
+
MDBXMOU_DECLARE_FLAG_NAME(putFlag, "appendDup", put_flag::append_dup);
|
|
111
|
+
MDBXMOU_DECLARE_FLAG_NAME(putFlag, "multiple", put_flag::multiple);
|
|
112
|
+
mdbx_mou.Set("putFlag", putFlag);
|
|
113
|
+
|
|
100
114
|
using move_operation = mdbx::cursor::move_operation;
|
|
101
115
|
Napi::Object cursor_mode = Napi::Object::New(env);
|
|
102
116
|
MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "first", move_operation::first);
|
package/src/querymou.cpp
CHANGED
|
@@ -23,20 +23,11 @@ dbimou* async_common::parse(const Napi::Object& arg0)
|
|
|
23
23
|
|
|
24
24
|
void async_key::parse(const async_common& common, const Napi::Value& item)
|
|
25
25
|
{
|
|
26
|
-
// утснавлиаем общие параметры
|
|
27
|
-
auto key_flag = common.key_flag;
|
|
28
|
-
|
|
29
26
|
keymou key{};
|
|
30
27
|
if (mdbx::is_ordinal(common.key_mod)) {
|
|
31
|
-
|
|
32
|
-
key = keymou{item.As<Napi::BigInt>(), id_buf};
|
|
33
|
-
} else if (item.IsNumber()) {
|
|
34
|
-
key = keymou{item.As<Napi::Number>(), id_buf};
|
|
35
|
-
}
|
|
28
|
+
key = keymou::from(item, item.Env(), id_buf);
|
|
36
29
|
} else {
|
|
37
|
-
key = (
|
|
38
|
-
keymou{item.As<Napi::String>(), item.Env(), key_buf} :
|
|
39
|
-
keymou{item.As<Napi::Buffer<char>>(), key_buf};
|
|
30
|
+
key = keymou::from(item, item.Env(), key_buf);
|
|
40
31
|
}
|
|
41
32
|
}
|
|
42
33
|
|
|
@@ -44,12 +35,14 @@ void async_keyval::parse(const query_line& common, const Napi::Object& item)
|
|
|
44
35
|
{
|
|
45
36
|
async_key::parse(common, item);
|
|
46
37
|
// проверяем надо ли что-то писать
|
|
47
|
-
if (common.mode.
|
|
38
|
+
if (common.mode.is_write()) {
|
|
48
39
|
valuemou val{};
|
|
49
40
|
auto item_val = item.Get("value");
|
|
50
|
-
val = (common.
|
|
51
|
-
valuemou
|
|
52
|
-
|
|
41
|
+
val = is_ordinal(common.val_mod) ?
|
|
42
|
+
valuemou::from(item_val, item_val.Env(), val_num) :
|
|
43
|
+
(common.value_flag & base_flag::string) ?
|
|
44
|
+
valuemou{item_val.As<Napi::String>(), item_val.Env(), val_buf} :
|
|
45
|
+
valuemou{item_val.As<Napi::Buffer<char>>(), val_buf};
|
|
53
46
|
}
|
|
54
47
|
}
|
|
55
48
|
|
|
@@ -63,6 +56,13 @@ void query_line::parse(txn_mode txn, const Napi::Object& arg0)
|
|
|
63
56
|
} else if (arg0.Has("queryMode")) {
|
|
64
57
|
mode = query_mode::parse(txn, arg0.Get("queryMode").As<Napi::Number>());
|
|
65
58
|
}
|
|
59
|
+
if (arg0.Has("putFlag")) {
|
|
60
|
+
put_flags = put_flag::parse_query(arg0.Get("putFlag"));
|
|
61
|
+
if (!mode.is_write()) {
|
|
62
|
+
throw Napi::TypeError::New(arg0.Env(),
|
|
63
|
+
"query putFlag requires write queryMode");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
66
|
auto items_array = arg0.Get("item").As<Napi::Array>();
|
|
67
67
|
auto item_len = items_array.Length();
|
|
68
68
|
if (item_len > 0) {
|
package/src/querymou.hpp
CHANGED
|
@@ -39,6 +39,7 @@ struct async_keyval
|
|
|
39
39
|
: async_key
|
|
40
40
|
{
|
|
41
41
|
buffer_type val_buf{};
|
|
42
|
+
std::uint64_t val_num{};
|
|
42
43
|
bool found{false};
|
|
43
44
|
|
|
44
45
|
void parse(const query_line& line, const Napi::Object& obj);
|
|
@@ -57,6 +58,7 @@ struct query_line
|
|
|
57
58
|
{
|
|
58
59
|
base_flag value_flag{};
|
|
59
60
|
query_mode mode{};
|
|
61
|
+
put_flag put_flags{};
|
|
60
62
|
// буффер для запроса / ответа
|
|
61
63
|
std::vector<async_keyval> item{};
|
|
62
64
|
void parse(txn_mode txn, const Napi::Object& arg0);
|
|
@@ -83,4 +85,4 @@ struct keys_line
|
|
|
83
85
|
using keys_request = std::vector<keys_line>;
|
|
84
86
|
keys_request parse_keys(const Napi::Value& obj);
|
|
85
87
|
|
|
86
|
-
} // namespace mdbxmou
|
|
88
|
+
} // namespace mdbxmou
|
package/src/txnmou.cpp
CHANGED
|
@@ -159,7 +159,7 @@ Napi::Value txnmou::get_dbi(const Napi::Object& arg0, db_mode db_mode)
|
|
|
159
159
|
if (arg0.Has("valueMode")) {
|
|
160
160
|
auto value = arg0.Get("valueMode");
|
|
161
161
|
if (!value.IsUndefined() && !value.IsNull()) {
|
|
162
|
-
value_mode =
|
|
162
|
+
value_mode = parse_value_mode(value, value_flag);
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
|
|
@@ -189,7 +189,7 @@ Napi::Value txnmou::get_dbi(const Napi::CallbackInfo& info, db_mode db_mode)
|
|
|
189
189
|
auto arg2 = info[2]; // value_mode
|
|
190
190
|
db_name = arg0.As<Napi::String>().Utf8Value();
|
|
191
191
|
key_mode = parse_key_mode(env, arg1, key_flag);
|
|
192
|
-
value_mode =
|
|
192
|
+
value_mode = parse_value_mode(arg2, value_flag);
|
|
193
193
|
} else if (arg_count == 2) {
|
|
194
194
|
// db_name + key_mode || key_mode + value_mode
|
|
195
195
|
auto arg0 = info[0];
|
|
@@ -199,7 +199,7 @@ Napi::Value txnmou::get_dbi(const Napi::CallbackInfo& info, db_mode db_mode)
|
|
|
199
199
|
key_mode = parse_key_mode(env, arg1, key_flag);
|
|
200
200
|
} else {
|
|
201
201
|
key_mode = parse_key_mode(env, arg0, key_flag);
|
|
202
|
-
value_mode =
|
|
202
|
+
value_mode = parse_value_mode(arg1, value_flag);
|
|
203
203
|
}
|
|
204
204
|
} else if (arg_count == 1) {
|
|
205
205
|
// db_name || key_mode
|
package/src/typemou.hpp
CHANGED
|
@@ -171,19 +171,80 @@ struct query_mode
|
|
|
171
171
|
};
|
|
172
172
|
int val{get};
|
|
173
173
|
|
|
174
|
+
bool is_get() const noexcept {
|
|
175
|
+
return (val & get) != 0;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
bool is_del() const noexcept {
|
|
179
|
+
return (val & del) != 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
bool is_write() const noexcept {
|
|
183
|
+
return !is_get() && !is_del();
|
|
184
|
+
}
|
|
185
|
+
|
|
174
186
|
static inline query_mode parse(const txn_mode& mode, const Napi::Value& arg0) {
|
|
175
187
|
query_mode rc{arg0.As<Napi::Number>().Int32Value() & mask};
|
|
176
|
-
if ((
|
|
188
|
+
if ((rc.is_get() || rc.is_del()) && (rc.val & write_mask)) {
|
|
189
|
+
throw std::runtime_error(
|
|
190
|
+
"queryMode must be one of get/del/upsert/update/insertUnique");
|
|
191
|
+
}
|
|
192
|
+
if (rc.is_get() && rc.is_del()) {
|
|
193
|
+
throw std::runtime_error(
|
|
194
|
+
"queryMode must be one of get/del/upsert/update/insertUnique");
|
|
195
|
+
}
|
|
196
|
+
if ((mode.val & txn_mode::ro) && (rc.is_del() || rc.is_write())) {
|
|
177
197
|
throw std::runtime_error("rw query in read-only transaction");
|
|
178
198
|
}
|
|
179
199
|
return rc;
|
|
180
200
|
}
|
|
181
201
|
|
|
202
|
+
int write_flags() const noexcept {
|
|
203
|
+
return val & write_mask;
|
|
204
|
+
}
|
|
205
|
+
|
|
182
206
|
operator mdbx::put_mode() const noexcept {
|
|
183
207
|
return static_cast<mdbx::put_mode>(val & write_mask);
|
|
184
208
|
}
|
|
185
209
|
};
|
|
186
210
|
|
|
211
|
+
struct put_flag
|
|
212
|
+
{
|
|
213
|
+
enum type : int {
|
|
214
|
+
no_overwrite = MDBX_NOOVERWRITE,
|
|
215
|
+
no_dup_data = MDBX_NODUPDATA,
|
|
216
|
+
current = MDBX_CURRENT,
|
|
217
|
+
all_dups = MDBX_ALLDUPS,
|
|
218
|
+
reserve = MDBX_RESERVE,
|
|
219
|
+
append = MDBX_APPEND,
|
|
220
|
+
append_dup = MDBX_APPENDDUP,
|
|
221
|
+
multiple = MDBX_MULTIPLE,
|
|
222
|
+
query_mask = MDBX_NOOVERWRITE | MDBX_NODUPDATA | MDBX_CURRENT |
|
|
223
|
+
MDBX_APPEND | MDBX_APPENDDUP,
|
|
224
|
+
mask = MDBX_NOOVERWRITE | MDBX_NODUPDATA | MDBX_CURRENT |
|
|
225
|
+
MDBX_ALLDUPS | MDBX_RESERVE | MDBX_APPEND |
|
|
226
|
+
MDBX_APPENDDUP | MDBX_MULTIPLE
|
|
227
|
+
};
|
|
228
|
+
int val{};
|
|
229
|
+
|
|
230
|
+
static inline put_flag parse(const Napi::Value& arg0) {
|
|
231
|
+
return {arg0.As<Napi::Number>().Int32Value() & mask};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
static inline put_flag parse_query(const Napi::Value& arg0) {
|
|
235
|
+
put_flag rc = parse(arg0);
|
|
236
|
+
if (rc.val & ~query_mask) {
|
|
237
|
+
throw Napi::TypeError::New(arg0.Env(),
|
|
238
|
+
"query putFlag supports only noOverwrite/noDupData/current/append/appendDup");
|
|
239
|
+
}
|
|
240
|
+
return rc;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
operator MDBX_put_flags_t() const noexcept {
|
|
244
|
+
return static_cast<MDBX_put_flags_t>(val & mask);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
187
248
|
struct key_mode
|
|
188
249
|
{
|
|
189
250
|
enum type : int {
|
|
@@ -223,6 +284,11 @@ struct value_mode
|
|
|
223
284
|
}
|
|
224
285
|
};
|
|
225
286
|
|
|
287
|
+
static inline bool is_ordinal(const value_mode& mode) noexcept
|
|
288
|
+
{
|
|
289
|
+
return (mode.val & static_cast<int>(MDBX_INTEGERDUP)) != 0;
|
|
290
|
+
}
|
|
291
|
+
|
|
226
292
|
|
|
227
293
|
struct base_flag
|
|
228
294
|
{
|
|
@@ -231,7 +297,7 @@ struct base_flag
|
|
|
231
297
|
number = 4,
|
|
232
298
|
bigint = 8,
|
|
233
299
|
mask_key = string | number | bigint,
|
|
234
|
-
mask_val = string
|
|
300
|
+
mask_val = string | number | bigint
|
|
235
301
|
};
|
|
236
302
|
int val{};
|
|
237
303
|
|
|
@@ -270,11 +336,12 @@ struct base_flag
|
|
|
270
336
|
}
|
|
271
337
|
|
|
272
338
|
static inline void validate_value(const Napi::Value& arg0, int value) {
|
|
273
|
-
if (value == 0 || value == string
|
|
339
|
+
if (value == 0 || value == string ||
|
|
340
|
+
value == number || value == bigint) {
|
|
274
341
|
return;
|
|
275
342
|
}
|
|
276
343
|
throw Napi::Error::New(arg0.Env(),
|
|
277
|
-
"valueFlag must be 0 or
|
|
344
|
+
"valueFlag must be 0, string, number or bigint");
|
|
278
345
|
}
|
|
279
346
|
|
|
280
347
|
static inline base_flag parse_key(const Napi::Value& arg0) {
|
|
@@ -287,7 +354,11 @@ struct base_flag
|
|
|
287
354
|
const Napi::Value& arg0) {
|
|
288
355
|
auto value = arg0.As<Napi::Number>().Int32Value() & mask_val;
|
|
289
356
|
validate_value(arg0, value);
|
|
290
|
-
|
|
357
|
+
base_flag rc{value};
|
|
358
|
+
if (is_ordinal(mode) && !rc.is_numeric()) {
|
|
359
|
+
rc = number;
|
|
360
|
+
}
|
|
361
|
+
return rc;
|
|
291
362
|
}
|
|
292
363
|
|
|
293
364
|
static inline base_flag parse_value(const Napi::Value& arg0) {
|
|
@@ -327,6 +398,15 @@ static inline key_mode parse_key_mode(Napi::Env env, const Napi::Value& arg0, ba
|
|
|
327
398
|
return mode;
|
|
328
399
|
}
|
|
329
400
|
|
|
401
|
+
static inline value_mode parse_value_mode(const Napi::Value& arg0, base_flag& value_flag)
|
|
402
|
+
{
|
|
403
|
+
auto mode = value_mode::parse(arg0);
|
|
404
|
+
if (is_ordinal(mode) && !value_flag.is_numeric()) {
|
|
405
|
+
value_flag = base_flag::number;
|
|
406
|
+
}
|
|
407
|
+
return mode;
|
|
408
|
+
}
|
|
409
|
+
|
|
330
410
|
struct db_mode
|
|
331
411
|
{
|
|
332
412
|
enum type : int {
|
package/src/valuemou.hpp
CHANGED
|
@@ -29,6 +29,10 @@ struct valuemou
|
|
|
29
29
|
: mdbx::slice{arg0.data(), arg0.size()}
|
|
30
30
|
{ }
|
|
31
31
|
|
|
32
|
+
valuemou(const std::uint64_t& arg0) noexcept
|
|
33
|
+
: mdbx::slice{&arg0, sizeof(arg0)}
|
|
34
|
+
{ }
|
|
35
|
+
|
|
32
36
|
valuemou(const Napi::Buffer<char>& arg0, buffer_type& mem)
|
|
33
37
|
{
|
|
34
38
|
auto ptr = arg0.Data();
|
|
@@ -59,6 +63,28 @@ struct valuemou
|
|
|
59
63
|
assign(mem.data(), mem.size());
|
|
60
64
|
}
|
|
61
65
|
|
|
66
|
+
valuemou(const Napi::Number& arg0,
|
|
67
|
+
const Napi::Env& env, std::uint64_t& mem)
|
|
68
|
+
{
|
|
69
|
+
auto value = arg0.Int64Value();
|
|
70
|
+
if (value < 0) {
|
|
71
|
+
throw Napi::Error::New(env, "Number negative");
|
|
72
|
+
}
|
|
73
|
+
mem = static_cast<std::uint64_t>(value);
|
|
74
|
+
assign(&mem, sizeof(mem));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
valuemou(const Napi::BigInt& arg0,
|
|
78
|
+
const Napi::Env& env, std::uint64_t& mem)
|
|
79
|
+
{
|
|
80
|
+
bool looseless;
|
|
81
|
+
mem = arg0.Uint64Value(&looseless);
|
|
82
|
+
if (!looseless) {
|
|
83
|
+
throw Napi::Error::New(env, "BigInt !looseless");
|
|
84
|
+
}
|
|
85
|
+
assign(&mem, sizeof(mem));
|
|
86
|
+
}
|
|
87
|
+
|
|
62
88
|
static inline valuemou from(const Napi::Value& arg0,
|
|
63
89
|
const Napi::Env& env, buffer_type& mem)
|
|
64
90
|
{
|
|
@@ -70,6 +96,23 @@ struct valuemou
|
|
|
70
96
|
return {arg0.As<Napi::String>(), env, mem};
|
|
71
97
|
}
|
|
72
98
|
|
|
99
|
+
static inline valuemou from(const Napi::Value& arg0,
|
|
100
|
+
const Napi::Env& env, std::uint64_t& mem)
|
|
101
|
+
{
|
|
102
|
+
if (arg0.IsBigInt()) {
|
|
103
|
+
return {arg0.As<Napi::BigInt>(), env, mem};
|
|
104
|
+
} else if (!arg0.IsNumber()) {
|
|
105
|
+
throw Napi::Error::New(env, "value must be a Number or BigInt");
|
|
106
|
+
}
|
|
107
|
+
return {arg0.As<Napi::Number>(), env, mem};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static inline valuemou from(const Napi::Value& arg0,
|
|
111
|
+
const Napi::Env& env, buffer_type& buf, std::uint64_t& num, bool ordinal)
|
|
112
|
+
{
|
|
113
|
+
return ordinal ? from(arg0, env, num) : from(arg0, env, buf);
|
|
114
|
+
}
|
|
115
|
+
|
|
73
116
|
Napi::Value to_string(const Napi::Env& env) const
|
|
74
117
|
{
|
|
75
118
|
return Napi::String::New(env,
|
|
@@ -81,92 +124,38 @@ struct valuemou
|
|
|
81
124
|
return Napi::Buffer<char>::Copy(env,
|
|
82
125
|
char_ptr(), length());
|
|
83
126
|
}
|
|
127
|
+
|
|
128
|
+
Napi::Value to_number(const Napi::Env& env) const
|
|
129
|
+
{
|
|
130
|
+
return Napi::Number::New(env, static_cast<double>(as_int64()));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
Napi::Value to_bigint(const Napi::Env& env) const
|
|
134
|
+
{
|
|
135
|
+
return Napi::BigInt::New(env, as_uint64());
|
|
136
|
+
}
|
|
84
137
|
};
|
|
85
138
|
|
|
86
139
|
struct keymou final
|
|
87
140
|
: valuemou
|
|
88
141
|
{
|
|
142
|
+
using valuemou::valuemou;
|
|
143
|
+
|
|
89
144
|
keymou() = default;
|
|
90
145
|
keymou(const keymou&) = default;
|
|
91
146
|
keymou& operator=(const keymou&) = default;
|
|
92
147
|
keymou(keymou&&) = default;
|
|
93
148
|
keymou& operator=(keymou&&) = default;
|
|
94
149
|
|
|
95
|
-
keymou(const valuemou& arg0) noexcept
|
|
96
|
-
: valuemou{arg0}
|
|
97
|
-
{ }
|
|
98
|
-
|
|
99
|
-
keymou(const mdbx::slice& arg0) noexcept
|
|
100
|
-
: valuemou{arg0}
|
|
101
|
-
{ }
|
|
102
|
-
|
|
103
|
-
keymou(const Napi::Buffer<char>& arg0)
|
|
104
|
-
: valuemou{arg0}
|
|
105
|
-
{ }
|
|
106
|
-
|
|
107
|
-
keymou(const buffer_type& arg0) noexcept
|
|
108
|
-
: valuemou{arg0}
|
|
109
|
-
{ }
|
|
110
|
-
|
|
111
|
-
keymou(const std::uint64_t& arg0) noexcept
|
|
112
|
-
: valuemou{mdbx::slice{&arg0, sizeof(arg0)}}
|
|
113
|
-
{ }
|
|
114
|
-
|
|
115
|
-
keymou(const Napi::Buffer<char>& arg0, buffer_type& mem)
|
|
116
|
-
: valuemou{arg0, mem}
|
|
117
|
-
{ }
|
|
118
|
-
|
|
119
|
-
keymou(const Napi::String& arg0,
|
|
120
|
-
const Napi::Env& env, buffer_type& mem)
|
|
121
|
-
: valuemou{arg0, env, mem}
|
|
122
|
-
{ }
|
|
123
|
-
|
|
124
|
-
keymou(const Napi::Number& arg0, std::uint64_t& mem)
|
|
125
|
-
{
|
|
126
|
-
auto value = arg0.Int64Value();
|
|
127
|
-
if (value < 0) {
|
|
128
|
-
throw std::runtime_error("Number negative");
|
|
129
|
-
}
|
|
130
|
-
mem = static_cast<std::uint64_t>(value);
|
|
131
|
-
assign(&mem, sizeof(mem));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
keymou(const Napi::Number& arg0,
|
|
135
|
-
const Napi::Env& env, std::uint64_t& mem)
|
|
136
|
-
{
|
|
137
|
-
auto value = arg0.Int64Value();
|
|
138
|
-
if (value < 0) {
|
|
139
|
-
throw Napi::Error::New(env, "Number negative");
|
|
140
|
-
}
|
|
141
|
-
mem = static_cast<std::uint64_t>(value);
|
|
142
|
-
assign(&mem, sizeof(mem));
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
keymou(const Napi::BigInt& arg0,std::uint64_t& mem)
|
|
146
|
-
{
|
|
147
|
-
bool looseless;
|
|
148
|
-
mem = arg0.Uint64Value(&looseless);
|
|
149
|
-
if (!looseless) {
|
|
150
|
-
throw std::runtime_error("BigInt !looseless");
|
|
151
|
-
}
|
|
152
|
-
assign(&mem, sizeof(mem));
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
keymou(const Napi::BigInt& arg0,
|
|
156
|
-
const Napi::Env& env, std::uint64_t& mem)
|
|
157
|
-
{
|
|
158
|
-
bool looseless;
|
|
159
|
-
mem = arg0.Uint64Value(&looseless);
|
|
160
|
-
if (!looseless) {
|
|
161
|
-
throw Napi::Error::New(env, "BigInt !looseless");
|
|
162
|
-
}
|
|
163
|
-
assign(&mem, sizeof(mem));
|
|
164
|
-
}
|
|
165
|
-
|
|
166
150
|
static inline keymou from(const Napi::Value& arg0,
|
|
167
151
|
const Napi::Env& env, buffer_type& mem)
|
|
168
152
|
{
|
|
169
|
-
|
|
153
|
+
if (arg0.IsBuffer()) {
|
|
154
|
+
return {arg0.As<Napi::Buffer<char>>()};
|
|
155
|
+
} else if (!arg0.IsString()) {
|
|
156
|
+
throw Napi::Error::New(env, "key must be a Buffer or String");
|
|
157
|
+
}
|
|
158
|
+
return {arg0.As<Napi::String>(), env, mem};
|
|
170
159
|
}
|
|
171
160
|
|
|
172
161
|
static inline keymou from(const Napi::Value& arg0,
|
|
@@ -190,16 +179,6 @@ struct keymou final
|
|
|
190
179
|
}
|
|
191
180
|
return from(arg0, env, num);
|
|
192
181
|
}
|
|
193
|
-
|
|
194
|
-
Napi::Value to_number(const Napi::Env& env) const
|
|
195
|
-
{
|
|
196
|
-
return Napi::Number::New(env, static_cast<double>(as_int64()));
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
Napi::Value to_bigint(const Napi::Env& env) const
|
|
200
|
-
{
|
|
201
|
-
return Napi::BigInt::New(env, as_uint64());
|
|
202
|
-
}
|
|
203
182
|
};
|
|
204
183
|
|
|
205
|
-
} // mdbxmou
|
|
184
|
+
} // mdbxmou
|