mdbxmou 0.3.10 → 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/CMakeLists.txt CHANGED
@@ -23,6 +23,7 @@ add_library(${PROJECT_NAME} SHARED
23
23
  "src/querymou.cpp"
24
24
  "src/envmou.cpp"
25
25
  "src/txnmou.cpp"
26
+ "src/convmou.cpp"
26
27
  "src/dbimou.cpp"
27
28
  "src/cursormou.cpp"
28
29
  "src/dbi.cpp")
@@ -63,4 +64,3 @@ string(REPLACE "\n" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
63
64
  string(REPLACE "\"" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
64
65
  target_include_directories(${PROJECT_NAME} PRIVATE ${NODE_ADDON_API_DIR} "src")
65
66
 
66
-
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # mdbxmou
2
2
 
3
- High-performance Node.js binding for [libmdbx](https://github.com/erthink/libmdbx) — a fast, lightweight, embedded key-value database.
3
+ Node.js binding for [libmdbx](https://github.com/Mithril-mine/libmdbx) — a fast, lightweight, embedded key-value database.
4
4
 
5
5
  ## Features
6
6
 
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 (integer) keys
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
- dbMode: MDBX_Param.dbMode.accede,
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);
@@ -345,6 +364,47 @@ const bigIntKeys = dbi.keysFrom(txn, 42n, 50);
345
364
  const equalKeys = dbi.keysFrom(txn, 5, 10, 'keyEqual');
346
365
  ```
347
366
 
367
+ **getRange(txn, [options]) → Array<{ key, value }>**
368
+ ```javascript
369
+ const rows = dbi.getRange(txn, { start: 10, end: 15 });
370
+ // [
371
+ // { key: 10, value: ... },
372
+ // { key: 11, value: ... },
373
+ // ...
374
+ // ]
375
+ ```
376
+
377
+ **getCount(txn, [options]) → number**
378
+ ```javascript
379
+ const total = dbi.getCount(txn, { start: 10, end: 20 });
380
+ // 11
381
+ ```
382
+
383
+ **keysRange(txn, [options]) → Array**
384
+ ```javascript
385
+ const keys = dbi.keysRange(txn, { start: 10, end: 20, limit: 5 });
386
+ // [10, 11, 12, 13, 14]
387
+ ```
388
+
389
+ **valuesRange(txn, [options]) → Array**
390
+ ```javascript
391
+ const values = dbi.valuesRange(txn, {
392
+ start: 10,
393
+ end: 15,
394
+ reverse: true,
395
+ includeEnd: false
396
+ });
397
+ // values for keys 14, 13, 12, 11, 10
398
+ ```
399
+
400
+ Range options:
401
+ - `start`, `end` - inclusive bounds by default
402
+ - `includeStart`, `includeEnd` - control bound inclusion
403
+ - `reverse` - scan from upper bound to lower bound
404
+ - `limit` - maximum number of returned items
405
+ - `offset` - skip N items after initial positioning
406
+ - `getCount()` ignores `offset` and `limit` and returns the total size of the bounded range
407
+
348
408
  **drop(txn, [delete_db]) → void**
349
409
  ```javascript
350
410
  // Clear database contents (keep structure)
@@ -427,7 +487,7 @@ Insert or update a record at cursor position.
427
487
  cursor.put('newKey', 'newValue');
428
488
 
429
489
  // With flags (MDBX_NOOVERWRITE, etc.)
430
- cursor.put('key', 'value', MDBX_Param.queryMode.insertUnique);
490
+ cursor.put('key', 'value', MDBX_Param.putFlag.noOverwrite);
431
491
  ```
432
492
 
433
493
  **del([flags]) → boolean**
@@ -561,12 +621,20 @@ txn.commit();
561
621
  ### Value Modes (MDBX_Param.valueMode)
562
622
 
563
623
  - **single** - Single value per key (default)
564
- - **multi** - Multiple values per key (dupsort)
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`
565
629
 
566
630
  ### Value Flags (MDBX_Param.valueFlag)
567
631
 
568
- - **binary** - Raw binary data (default)
632
+ - **binary** - Raw binary data (default, represented by `0`)
569
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`.
570
638
 
571
639
  ## Examples
572
640
 
@@ -750,6 +818,101 @@ function cursorExample() {
750
818
  cursorExample();
751
819
  ```
752
820
 
821
+ ### Range Queries
822
+
823
+ ```javascript
824
+ const { MDBX_Env, MDBX_Param } = require('mdbxmou');
825
+
826
+ function rangeExample() {
827
+ const env = new MDBX_Env();
828
+ env.openSync({
829
+ path: './range-data',
830
+ valueFlag: MDBX_Param.valueFlag.string
831
+ });
832
+
833
+ const writeTxn = env.startWrite();
834
+ const dbi = writeTxn.createMap(MDBX_Param.keyMode.ordinal);
835
+ for (let i = 0; i < 10; i++) {
836
+ dbi.put(writeTxn, i, `value_${i}`);
837
+ }
838
+ writeTxn.commit();
839
+
840
+ const readTxn = env.startRead();
841
+ const readDbi = readTxn.openMap(MDBX_Param.keyMode.ordinal);
842
+
843
+ const rows = readDbi.getRange(readTxn, { start: 3, end: 6 });
844
+ console.log(rows);
845
+ // [
846
+ // { key: 3, value: 'value_3' },
847
+ // { key: 4, value: 'value_4' },
848
+ // { key: 5, value: 'value_5' },
849
+ // { key: 6, value: 'value_6' }
850
+ // ]
851
+
852
+ const total = readDbi.getCount(readTxn, { start: 3, end: 8 });
853
+ console.log(total); // 6
854
+
855
+ const keys = readDbi.keysRange(readTxn, {
856
+ start: 3,
857
+ end: 8,
858
+ offset: 1,
859
+ limit: 3
860
+ });
861
+ console.log(keys); // [4, 5, 6]
862
+
863
+ const values = readDbi.valuesRange(readTxn, {
864
+ start: 3,
865
+ end: 6,
866
+ reverse: true,
867
+ includeEnd: false
868
+ });
869
+ console.log(values); // ['value_5', 'value_4', 'value_3']
870
+
871
+ readTxn.commit();
872
+ env.closeSync();
873
+ }
874
+
875
+ rangeExample();
876
+ ```
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
+
753
916
  ### Query API (Advanced Async)
754
917
 
755
918
  ```javascript
@@ -768,7 +931,8 @@ async function queryExample() {
768
931
  const results = await env.query([
769
932
  {
770
933
  dbi,
771
- mode: MDBX_Param.queryMode.insertUnique,
934
+ mode: MDBX_Param.queryMode.upsert,
935
+ putFlag: MDBX_Param.putFlag.noOverwrite,
772
936
  item: [
773
937
  { key: 1, value: JSON.stringify({ name: "Alice" }) },
774
938
  { key: 2, value: JSON.stringify({ name: "Bob" }) }
@@ -869,6 +1033,7 @@ node test/readme-sync-example.js
869
1033
  node test/readme-async-example.js
870
1034
  node test/readme-key-types.js
871
1035
  node test/readme-cursor-example.js
1036
+ node test/readme-range-example.js
872
1037
  node test/readme-query-example.js
873
1038
  node test/readme-keys-example.js
874
1039
  node test/readme-error-handling.js
@@ -892,7 +1057,21 @@ MDBX_Param.keyFlag.number // Number type (used with ordinal mode)
892
1057
  MDBX_Param.keyFlag.bigint // BigInt type (used with ordinal mode)
893
1058
  // Default - Buffer representation
894
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
+
895
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.
896
1075
  ```
897
1076
 
898
1077
  ### Environment Flags
@@ -938,11 +1117,23 @@ Note: For ordinal (integer) keys, use keyFlag.number or keyFlag.bigint to specif
938
1117
 
939
1118
  ### Query Modes
940
1119
  - `MDBX_Param.queryMode.get` - Read operations
941
- - `MDBX_Param.queryMode.upsert` - Write operations (insert or update)
942
- - `MDBX_Param.queryMode.update` - Update existing (MDBX_CURRENT)
943
- - `MDBX_Param.queryMode.insertUnique` - Insert unique (MDBX_NOOVERWRITE)
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`
944
1123
  - `MDBX_Param.queryMode.del` - Delete operations
945
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
+
946
1137
  ### Cursor Modes
947
1138
  - `MDBX_Param.cursorMode.first` - First key
948
1139
  - `MDBX_Param.cursorMode.last` - Last key
package/lib/async.d.mts CHANGED
@@ -1,4 +1,6 @@
1
- import type { MDBXDbiStat, MDBXEnvOpenOptions, MDBXKey, MDBXValue } from "./types.js";
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: MDBXValue, flags?: number): Promise<boolean>;
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: MDBXValue, index: number) => void): Promise<void>;
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: MDBXValue }>, flags?: number): Promise<MDBXAsyncPutBatchResultItem[]>;
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
@@ -79,6 +79,16 @@ export interface MDBXCursorResult<K extends MDBXKey = MDBXKey, V extends MDBXVal
79
79
  value: V;
80
80
  }
81
81
 
82
+ export interface MDBXRangeOptions<K extends MDBXKey = MDBXKey> {
83
+ start?: K;
84
+ end?: K;
85
+ limit?: number;
86
+ offset?: number;
87
+ reverse?: boolean;
88
+ includeStart?: boolean;
89
+ includeEnd?: boolean;
90
+ }
91
+
82
92
  /**
83
93
  * Database cursor for sequential access and range queries.
84
94
  * Must be closed before transaction commit/abort.
@@ -192,7 +202,7 @@ export interface MDBX_Dbi<K extends MDBXKey = MDBXKey, V extends MDBXValue = MDB
192
202
  readonly keyFlag: number;
193
203
  readonly valueFlag: number;
194
204
 
195
- put(txn: MDBX_Txn, key: K, value: MDBXValue): void;
205
+ put(txn: MDBX_Txn, key: K, value: MDBXValue, flags?: number): void;
196
206
  get(txn: MDBX_Txn, key: K): V | undefined;
197
207
  del(txn: MDBX_Txn, key: K): boolean;
198
208
  has(txn: MDBX_Txn, key: K): boolean;
@@ -213,6 +223,10 @@ export interface MDBX_Dbi<K extends MDBXKey = MDBXKey, V extends MDBXValue = MDB
213
223
  stat(txn: MDBX_Txn): MDBXDbiStat;
214
224
  keys(txn: MDBX_Txn): K[];
215
225
  keysFrom(txn: MDBX_Txn, fromKey: K, limit?: number, cursorMode?: MDBXCursorMode): K[];
226
+ getRange(txn: MDBX_Txn, options?: MDBXRangeOptions<K>): MDBXCursorResult<K, V>[];
227
+ getCount(txn: MDBX_Txn, options?: MDBXRangeOptions<K>): number;
228
+ keysRange(txn: MDBX_Txn, options?: MDBXRangeOptions<K>): K[];
229
+ valuesRange(txn: MDBX_Txn, options?: MDBXRangeOptions<K>): V[];
216
230
  drop(txn: MDBX_Txn, deleteDb?: boolean): void;
217
231
  }
218
232
 
@@ -251,6 +265,7 @@ export interface MDBXQueryRequest {
251
265
  dbi: MDBX_Dbi;
252
266
  mode?: number;
253
267
  queryMode?: number;
268
+ putFlag?: number;
254
269
  item: MDBXQueryItem[];
255
270
  }
256
271
 
@@ -361,6 +376,8 @@ export interface MDBX_Param {
361
376
 
362
377
  readonly valueFlag: {
363
378
  readonly string: number;
379
+ readonly number: number;
380
+ readonly bigint: number;
364
381
  };
365
382
 
366
383
  readonly dbMode: {
@@ -376,6 +393,17 @@ export interface MDBX_Param {
376
393
  readonly del: number;
377
394
  };
378
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
+
379
407
  readonly cursorMode: {
380
408
  readonly first: number;
381
409
  readonly last: number;
package/package.json CHANGED
@@ -50,6 +50,7 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/node": "^22.10.2",
53
+ "msgpackr": "^1.11.9",
53
54
  "typescript": "^5.6.3"
54
55
  },
55
56
  "scripts": {
@@ -58,6 +59,9 @@
58
59
  "e4": "node ./test/e4.js",
59
60
  "e4async": "node ./test/e4async.mjs",
60
61
  "e5": "node ./test/e5.js",
62
+ "e7": "node ./test/e7.js",
63
+ "e8": "node ./test/e8.js",
64
+ "e9": "node ./test/e9.js",
61
65
  "test:types": "node ./test/types/run.mjs",
62
66
  "build": "node build.js",
63
67
  "build-dev": "node build-dev.js",
@@ -65,7 +69,7 @@
65
69
  },
66
70
  "gypfile": true,
67
71
  "name": "mdbxmou",
68
- "version": "0.3.10",
72
+ "version": "0.3.12",
69
73
  "description": "Node bindings for mdbx",
70
74
  "repository": {
71
75
  "type": "git",
@@ -1,10 +1,53 @@
1
1
  #include "envmou_keys.hpp"
2
2
  #include "envmou.hpp"
3
+ #include "convmou.hpp"
3
4
  #include "dbimou.hpp"
4
- #include "../valuemou.hpp"
5
+ #include "valuemou.hpp"
5
6
 
6
7
  namespace mdbxmou {
7
8
 
9
+ namespace {
10
+
11
+ template<bool Ordinal>
12
+ void scan_keys_from(mdbx::cursor_managed& cursor, keys_line& arg0,
13
+ keymou& from_key, mdbx::cursor::move_operation turn_mode)
14
+ {
15
+ auto& item = arg0.item;
16
+ auto cursor_mode = arg0.cursor_mode;
17
+ bool is_key_equal_mode = (cursor_mode == mdbx::cursor::move_operation::key_equal ||
18
+ cursor_mode == mdbx::cursor::move_operation::multi_exactkey_value_equal);
19
+
20
+ std::size_t index{};
21
+ cursor.scan_from([&](const mdbx::pair& f) {
22
+ if (index >= arg0.limit) {
23
+ return true;
24
+ }
25
+
26
+ keymou key{f.key};
27
+ if (is_key_equal_mode) {
28
+ if constexpr (Ordinal) {
29
+ if (arg0.id_buf != key.as_int64()) {
30
+ return true;
31
+ }
32
+ } else if (from_key != key) {
33
+ return true;
34
+ }
35
+ }
36
+
37
+ async_key rc{};
38
+ if constexpr (Ordinal) {
39
+ rc.id_buf = key.as_uint64();
40
+ } else {
41
+ rc.key_buf.assign(key.char_ptr(), key.end_char_ptr());
42
+ }
43
+ item.push_back(std::move(rc));
44
+ ++index;
45
+ return false;
46
+ }, from_key, cursor_mode, turn_mode);
47
+ }
48
+
49
+ } // namespace
50
+
8
51
  void async_keys::Execute()
9
52
  {
10
53
  try {
@@ -24,26 +67,14 @@ void async_keys::Execute()
24
67
  static Napi::Value write_row(Napi::Env env, const keys_line& row)
25
68
  {
26
69
  auto& param = row.item;
27
- auto key_mode = row.key_mod;
28
- auto key_flag = row.key_flag;
70
+ convmou conv{row.key_mod, {}, row.key_flag, {}};
29
71
  auto js_arr = Napi::Array::New(env, param.size());
30
72
  for (std::uint32_t j = 0; j < param.size(); ++j) {
31
73
  const auto& item = param[j];
32
- Napi::Value key_value;
33
- if (mdbx::is_ordinal(key_mode)) {
34
- if (key_flag.val & base_flag::number) {
35
- key_value = Napi::Number::New(env, static_cast<double>(item.id_buf));
36
- } else {
37
- key_value = Napi::BigInt::New(env, item.id_buf);
38
- }
39
- } else {
40
- if (key_flag.val & base_flag::string) {
41
- key_value = Napi::String::New(env, item.key_buf.data(), item.key_buf.size());
42
- } else {
43
- key_value = Napi::Buffer<char>::Copy(env, item.key_buf.data(), item.key_buf.size());
44
- }
45
- }
46
- js_arr.Set(j, key_value);
74
+ auto key = mdbx::is_ordinal(row.key_mod) ?
75
+ keymou{item.id_buf} :
76
+ keymou{item.key_buf};
77
+ js_arr.Set(j, conv.convert_key(env, key));
47
78
  }
48
79
  return js_arr;
49
80
  }
@@ -140,14 +171,12 @@ void async_keys::do_keys_batch(txnmou_managed& txn,
140
171
  void async_keys::do_keys_from(txnmou_managed& txn,
141
172
  mdbx::map_handle dbi, keys_line& arg0)
142
173
  {
143
- // сыллка на массив результатов
144
- auto& item = arg0.item;
145
- std::size_t count = 0;
146
174
  using move_operation = mdbx::cursor::move_operation;
175
+ auto is_ordinal = mdbx::is_ordinal(arg0.key_mod);
147
176
 
148
177
  auto cursor = txn.open_cursor(dbi);
149
178
 
150
- keymou from_key = mdbx::is_ordinal(arg0.key_mod) ?
179
+ keymou from_key = is_ordinal ?
151
180
  keymou{arg0.id_buf} :
152
181
  keymou{mdbx::slice{arg0.key_buf.data(), arg0.key_buf.size()}};
153
182
 
@@ -170,50 +199,10 @@ void async_keys::do_keys_from(txnmou_managed& txn,
170
199
  break;
171
200
  }
172
201
 
173
- bool is_key_equal_mode = (cursor_mode == move_operation::key_equal ||
174
- cursor_mode == move_operation::multi_exactkey_value_equal);
175
-
176
- std::size_t index{};
177
- if (mdbx::is_ordinal(arg0.key_mod)) {
178
- // Создаем ключ для позиционирования
179
- cursor.scan_from([&](const mdbx::pair& f) {
180
- if (index >= arg0.limit) {
181
- return true; // останавливаем сканирование
182
- }
183
-
184
- keymou key{f.key};
185
- if (is_key_equal_mode) {
186
- if (arg0.id_buf != key.as_int64()) {
187
- return true; // останавливаем сканирование
188
- }
189
- }
190
-
191
- async_key rc{};
192
- rc.id_buf = key.as_uint64();
193
- item.push_back(std::move(rc));
194
- index++;
195
- return false; // продолжаем сканирование
196
- }, from_key, arg0.cursor_mode, turn_mode);
202
+ if (is_ordinal) {
203
+ scan_keys_from<true>(cursor, arg0, from_key, turn_mode);
197
204
  } else {
198
- // Создаем ключ для позиционирования
199
- cursor.scan_from([&](const mdbx::pair& f) {
200
- if (index >= arg0.limit) {
201
- return true; // останавливаем сканирование
202
- }
203
-
204
- keymou key{f.key};
205
- if (is_key_equal_mode) {
206
- if (from_key != key) {
207
- return true; // останавливаем сканирование
208
- }
209
- }
210
-
211
- async_key rc{};
212
- rc.id_buf = key.as_uint64();
213
- item.push_back(std::move(rc));
214
- index++;
215
- return false; // продолжаем сканирование
216
- }, from_key, arg0.cursor_mode, turn_mode);
205
+ scan_keys_from<false>(cursor, arg0, from_key, turn_mode);
217
206
  }
218
207
  }
219
208