mdbxmou 0.2.1 → 0.2.4

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,8 +23,8 @@ add_library(${PROJECT_NAME} SHARED
23
23
  "src/querymou.cpp"
24
24
  "src/envmou.cpp"
25
25
  "src/txnmou.cpp"
26
- "src/dbi.cpp"
27
- "src/dbimou.cpp")
26
+ "src/dbimou.cpp"
27
+ "src/dbi.cpp")
28
28
 
29
29
  # Gives our library file a .node extension without any "lib" prefix
30
30
  set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
package/README.md CHANGED
@@ -19,6 +19,8 @@ npm install mdbxmou
19
19
 
20
20
  ## Quick Start
21
21
 
22
+ CommonJS:
23
+
22
24
  ```javascript
23
25
  const { MDBX_Env, MDBX_Param } = require('mdbxmou');
24
26
 
@@ -47,6 +49,12 @@ readTxn.commit();
47
49
  await env.close();
48
50
  ```
49
51
 
52
+ ESM:
53
+
54
+ ```javascript
55
+ import { MDBX_Env, MDBX_Param } from "mdbxmou";
56
+ ```
57
+
50
58
  ## API Reference
51
59
 
52
60
  ### Environment (MDBX_Env)
@@ -64,19 +72,19 @@ await env.open({
64
72
  path: './database', // Database directory
65
73
  keyFlag: MDBX_Param.keyFlag.string, // Default key encoding (optional)
66
74
  valueFlag: MDBX_Param.valueFlag.string, // Default value encoding (optional)
67
- envFlag: MDBX_Param.envFlag.nostickythreads
75
+ flags: MDBX_Param.envFlag.nostickythreads
68
76
  });
69
77
  ```
70
78
 
71
79
  Options:
72
80
  - `path` - Database directory path
81
+ - `flags` - Environment flags (optional, defaults to `0`)
73
82
  - `keyFlag` - Default key encoding for all operations (optional, defaults to Buffer)
74
83
  - Only `string` can be set (ordinal mode uses `number`/`bigint` separately)
75
84
  - `valueFlag` - Default value encoding for all operations (optional, defaults to Buffer)
76
- - `envFlag` - Environment flags
77
- - `mapSize` - Maximum database size
78
- - `maxReaders` - Maximum number of readers
79
- - `maxDbs` - Maximum number of databases
85
+ - `maxDbi` - Maximum number of databases (optional, default `32`)
86
+ - `mode` - Filesystem permissions mode (optional, default `0664`)
87
+ - `geometry` - Map size/geometry options (optional)
80
88
 
81
89
  Note: When `keyFlag` or `valueFlag` are set at environment level, they become defaults for all subsequent operations unless explicitly overridden.
82
90
 
@@ -124,14 +132,14 @@ const result = await env.query([
124
132
 
125
133
  #### Methods
126
134
 
127
- **createMap(keyMode, [valueMode], [flags], [name]) → DBI**
135
+ **createMap(db_name | keyMode, [keyMode | valueMode], [valueMode]) → DBI**
128
136
  ```javascript
129
- // No arguments - default keyMode (0) and valueMode (0)
130
- const dbi = txn.createMap();
131
-
132
137
  // One argument - keyMode only
133
138
  const dbi = txn.createMap(MDBX_Param.keyMode.ordinal);
134
139
 
140
+ // One argument - db_name only (uses default keyMode)
141
+ const namedDbi = txn.createMap("my-table");
142
+
135
143
  // Two arguments - keyMode + valueMode
136
144
  const dbi = txn.createMap(MDBX_Param.keyMode.ordinal, MDBX_Param.valueMode.multi);
137
145
 
@@ -144,17 +152,17 @@ const namedDbi = txn.createMap("my-table", MDBX_Param.keyMode.ordinal, MDBX_Para
144
152
 
145
153
  > **Note**: Use `createMap` in write transactions - it will create the database if it doesn't exist, or open it if it does. This is safer for new environments.
146
154
 
147
- **openMap(keyMode, [name]) → DBI**
155
+ **openMap(db_name | keyMode, [keyMode]) → DBI**
148
156
  ```javascript
149
- // No arguments - default keyMode (0)
150
- const dbi = txn.openMap();
151
-
152
157
  // One argument - keyMode only
153
158
  // Number keyMode - keys returned as numbers
154
159
  const dbi = txn.openMap(MDBX_Param.keyMode.ordinal);
155
160
  // BigInt keyMode - keys returned as BigInts
156
161
  const dbi = txn.openMap(BigInt(MDBX_Param.keyMode.ordinal));
157
162
 
163
+ // One argument - db_name only (uses default keyMode)
164
+ const namedDbi = txn.openMap("my-table");
165
+
158
166
  // Two arguments - db_name + keyMode
159
167
  const namedDbi = txn.openMap("my-table", MDBX_Param.keyMode.ordinal);
160
168
  const namedDbiBigInt = txn.openMap("my-table", BigInt(MDBX_Param.keyMode.ordinal));
@@ -454,24 +462,27 @@ async function queryExample() {
454
462
  const env = new MDBX_Env();
455
463
  await env.open({ path: './query-data' });
456
464
 
457
- // Async query with multiple databases
465
+ // Create DBI first in synchronous transaction
466
+ const writeTxn = env.startWrite();
467
+ const dbi = writeTxn.createMap(MDBX_Param.keyMode.ordinal);
468
+ writeTxn.commit();
469
+
470
+ // Async query with DBI object (not database name)
458
471
  const results = await env.query([
459
472
  {
460
- db: "users",
461
- dbMode: MDBX_Param.dbMode.create | MDBX_Param.dbMode.accede,
462
- mode: MDBX_Param.queryMode.put,
473
+ dbi: dbi,
474
+ mode: MDBX_Param.queryMode.insertUnique,
463
475
  item: [
464
- { key: "user1", value: JSON.stringify({ name: "Alice" }) },
465
- { key: "user2", value: JSON.stringify({ name: "Bob" }) }
476
+ { key: 1, value: JSON.stringify({ name: "Alice" }) },
477
+ { key: 2, value: JSON.stringify({ name: "Bob" }) }
466
478
  ]
467
479
  },
468
480
  {
469
- db: "users",
470
- dbMode: MDBX_Param.dbMode.accede,
481
+ dbi: dbi,
471
482
  mode: MDBX_Param.queryMode.get,
472
483
  item: [
473
- { key: "user1" },
474
- { key: "user2" }
484
+ { key: 1 },
485
+ { key: 2 }
475
486
  ]
476
487
  }
477
488
  ]);
@@ -481,6 +492,47 @@ async function queryExample() {
481
492
  }
482
493
  ```
483
494
 
495
+ ### Async Keys API
496
+
497
+ ```javascript
498
+ const { MDBX_Env, MDBX_Param } = require('mdbxmou');
499
+
500
+ async function keysExample() {
501
+ const env = new MDBX_Env();
502
+ await env.open({ path: './keys-data' });
503
+
504
+ // Create DBI first
505
+ const writeTxn = env.startWrite();
506
+ const dbi = writeTxn.createMap(MDBX_Param.keyMode.ordinal);
507
+
508
+ // Add some test data
509
+ for (let i = 1; i <= 10; i++) {
510
+ dbi.put(writeTxn, i, `value-${i}`);
511
+ }
512
+ writeTxn.commit();
513
+
514
+ // Get all keys from DBI
515
+ const allKeys = await env.keys(dbi);
516
+ console.log("All keys:", allKeys);
517
+
518
+ // Get keys with DBI object parameter
519
+ const allKeys2 = await env.keys({ dbi: dbi });
520
+ console.log("All keys (object):", allKeys2);
521
+
522
+ // Get keys from multiple DBIs
523
+ const multiKeys = await env.keys([dbi, dbi]);
524
+ console.log("Multi DBI keys:", multiKeys);
525
+
526
+ // Get limited keys from specific position
527
+ const limitedKeys = await env.keys([
528
+ { dbi: dbi, limit: 3, from: 5 }
529
+ ]);
530
+ console.log("Limited keys:", limitedKeys);
531
+
532
+ await env.close();
533
+ }
534
+ ```
535
+
484
536
  ## Error Handling
485
537
 
486
538
  ```javascript
@@ -492,7 +544,7 @@ try {
492
544
  const dbi = txn.createMap(MDBX_Param.keyMode.ordinal);
493
545
 
494
546
  // This might throw if key already exists with MDBX_NOOVERWRITE
495
- dbi.put(txn, 123, "value", MDBX_Param.putFlag.nooverwrite);
547
+ dbi.put(txn, 123, "value");
496
548
 
497
549
  txn.commit();
498
550
  } catch (error) {
@@ -524,7 +576,17 @@ Note: For ordinal (integer) keys, use keyFlag.number or keyFlag.bigint to specif
524
576
 
525
577
  ### Environment Flags
526
578
  - `MDBX_Param.envFlag.nostickythreads` - Don't stick reader transactions to threads
527
- - `MDBX_Param.envFlag.readonly` - Open database in read-only mode
579
+ - `MDBX_Param.envFlag.rdonly` - Open database in read-only mode
580
+ - `MDBX_Param.envFlag.validation` - Enable page validation
581
+ - `MDBX_Param.envFlag.exclusive` - Exclusive mode
582
+ - `MDBX_Param.envFlag.accede` - Open existing environment
583
+ - `MDBX_Param.envFlag.writemap` - Use writable memory map
584
+ - `MDBX_Param.envFlag.nordahead` - Disable OS readahead
585
+ - `MDBX_Param.envFlag.nomeminit` - Disable memory initialization
586
+ - `MDBX_Param.envFlag.liforeclaim` - LIFO reclaim
587
+ - `MDBX_Param.envFlag.nometasync` - Disable metadata flushes
588
+ - `MDBX_Param.envFlag.safeNosync` - Safe nosync mode
589
+ - `MDBX_Param.envFlag.utterlyNosync` - Utterly nosync mode
528
590
 
529
591
  ### Database Modes
530
592
  - `MDBX_Param.dbMode.create` - Create database if it doesn't exist
@@ -532,9 +594,24 @@ Note: For ordinal (integer) keys, use keyFlag.number or keyFlag.bigint to specif
532
594
 
533
595
  ### Query Modes
534
596
  - `MDBX_Param.queryMode.get` - Read operations
535
- - `MDBX_Param.queryMode.put` - Write operations
597
+ - `MDBX_Param.queryMode.upsert` - Write operations (insert or update)
598
+ - `MDBX_Param.queryMode.update` - Update existing (MDBX_CURRENT)
599
+ - `MDBX_Param.queryMode.insertUnique` - Insert unique (MDBX_NOOVERWRITE)
536
600
  - `MDBX_Param.queryMode.del` - Delete operations
537
601
 
602
+ ### Cursor Modes
603
+ - `MDBX_Param.cursorMode.first` - First key
604
+ - `MDBX_Param.cursorMode.last` - Last key
605
+ - `MDBX_Param.cursorMode.next` - Next key
606
+ - `MDBX_Param.cursorMode.prev` - Previous key
607
+ - `MDBX_Param.cursorMode.keyLesserThan` - Keys less than target
608
+ - `MDBX_Param.cursorMode.keyLesserOrEqual` - Keys less than or equal to target
609
+ - `MDBX_Param.cursorMode.keyEqual` - Keys exactly equal to target
610
+ - `MDBX_Param.cursorMode.keyGreaterOrEqual` - Keys greater than or equal to target
611
+ - `MDBX_Param.cursorMode.keyGreaterThan` - Keys greater than target
612
+
613
+ > **Note**: Cursor modes can be used with `keysFrom()` and `forEach()` methods to control iteration direction and filtering.
614
+
538
615
  ## Performance Tips
539
616
 
540
617
  1. **Use ordinal keys** for integer data - much faster than string keys
@@ -549,5 +626,5 @@ Apache License 2.0
549
626
 
550
627
  ---
551
628
 
552
- **Documentation generated by GitHub Copilot (Claude 3.5 Sonnet) on August 13, 2025**
629
+ **Documentation generated by GitHub Copilot (Claude 3.5 Sonnet) on August 27, 2025**
553
630
  **Reviewed and approved by the library author**
package/build.js CHANGED
@@ -1,6 +1,7 @@
1
1
 
2
2
  var spawnSync = require('child_process').spawnSync;
3
3
  var fs = require('fs');
4
+ var path = require('path');
4
5
 
5
6
  function exec(cmd) {
6
7
  const { status } = spawnSync(cmd, {
@@ -14,6 +15,7 @@ function exec(cmd) {
14
15
 
15
16
  // Create VERSION.json for libmdbx (needed for npm package)
16
17
  const versionFile = 'deps/libmdbx/VERSION.json';
18
+ const libmdbxGitMarker = 'deps/libmdbx/.git';
17
19
  if (!fs.existsSync(versionFile)) {
18
20
  console.log('Creating VERSION.json for libmdbx...');
19
21
  const versionJson = {
@@ -27,14 +29,20 @@ if (!fs.existsSync(versionFile)) {
27
29
  console.log('VERSION.json created successfully!');
28
30
  }
29
31
 
30
- // Patch CMakeLists.txt line 56: if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git" -> if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git"
32
+ // Workaround for npm package: npm does not ship git metadata, while libmdbx
33
+ // may rely on it to determine version info during CMake configure.
34
+ // Apply this patch only when git metadata is missing.
31
35
  const cmakeFile = 'deps/libmdbx/CMakeLists.txt';
32
- if (fs.existsSync(cmakeFile)) {
33
- let cmakeContent = fs.readFileSync(cmakeFile, 'utf8').split('\n');
34
- if (cmakeContent[55] && cmakeContent[55].trim().startsWith('if(EXISTS')) {
35
- cmakeContent[55] = cmakeContent[55].replace('if(EXISTS', 'if(NOT EXISTS');
36
- fs.writeFileSync(cmakeFile, cmakeContent.join('\n'));
37
- console.log('Patched CMakeLists.txt line 56: if(NOT EXISTS ...');
36
+ if (!fs.existsSync(libmdbxGitMarker) && fs.existsSync(cmakeFile)) {
37
+ const cmakeText = fs.readFileSync(cmakeFile, 'utf8');
38
+ const from = 'if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git"';
39
+ const to = 'if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git"';
40
+ if (cmakeText.includes(from)) {
41
+ const patched = cmakeText.replace(from, to);
42
+ if (patched !== cmakeText) {
43
+ fs.writeFileSync(cmakeFile, patched);
44
+ console.log('Patched libmdbx CMakeLists.txt for npm package (no .git).');
45
+ }
38
46
  }
39
47
  }
40
48
 
package/lib/async.mjs ADDED
@@ -0,0 +1,7 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ const require = createRequire(import.meta.url);
4
+ const { MDBX_Async_Env } = require("./mdbx_evn_async.js");
5
+
6
+ export { MDBX_Async_Env };
7
+ export default MDBX_Async_Env;
package/lib/index.mjs ADDED
@@ -0,0 +1,12 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ const require = createRequire(import.meta.url);
4
+
5
+ const native = require("./nativemou.js");
6
+ const { MDBX_Async_Env } = require("./mdbx_evn_async.js");
7
+
8
+ export const MDBX_Env = native.MDBX_Env;
9
+ export const MDBX_Param = native.MDBX_Param;
10
+ export { MDBX_Async_Env };
11
+
12
+ export default native;
@@ -82,17 +82,21 @@ async function handler(msg) {
82
82
 
83
83
  case "dbi_put": {
84
84
  const { txnId, dbiId, key, value, flags = 0 } = params;
85
+ const t = txns.get(txnId);
86
+ if (!t) throw new Error("no txn");
85
87
  const d = dbis.get(dbiId);
86
88
  if (!d || d.txnId !== txnId) throw new Error("no dbi");
87
- d.dbi.put(key, value, flags);
89
+ d.dbi.put(t.txn, key, value, flags);
88
90
  return ok(id, true);
89
91
  }
90
92
 
91
93
  case "dbi_get": {
92
94
  const { txnId, dbiId, key } = params;
95
+ const t = txns.get(txnId);
96
+ if (!t) throw new Error("no txn");
93
97
  const d = dbis.get(dbiId);
94
98
  if (!d || d.txnId !== txnId) throw new Error("no dbi");
95
- const val = d.dbi.get(key);
99
+ const val = d.dbi.get(t.txn, key);
96
100
  // Если val это Buffer, преобразуем в строку для удобства
97
101
  const result = (val && Buffer.isBuffer(val)) ? val.toString() : val;
98
102
  return ok(id, result);
@@ -100,25 +104,31 @@ async function handler(msg) {
100
104
 
101
105
  case "dbi_del": {
102
106
  const { txnId, dbiId, key } = params;
107
+ const t = txns.get(txnId);
108
+ if (!t) throw new Error("no txn");
103
109
  const d = dbis.get(dbiId);
104
110
  if (!d || d.txnId !== txnId) throw new Error("no dbi");
105
- const r = d.dbi.del(key);
111
+ const r = d.dbi.del(t.txn, key);
106
112
  return ok(id, r);
107
113
  }
108
114
 
109
115
  case "dbi_stat": {
110
116
  const { txnId, dbiId } = params;
117
+ const t = txns.get(txnId);
118
+ if (!t) throw new Error("no txn");
111
119
  const d = dbis.get(dbiId);
112
120
  if (!d || d.txnId !== txnId) throw new Error("no dbi");
113
- return ok(id, d.dbi.stat());
121
+ return ok(id, d.dbi.stat(t.txn));
114
122
  }
115
123
 
116
124
  case "dbi_iter_all": {
117
125
  const { txnId, dbiId } = params;
126
+ const t = txns.get(txnId);
127
+ if (!t) throw new Error("no txn");
118
128
  const d = dbis.get(dbiId);
119
129
  if (!d || d.txnId !== txnId) throw new Error("no dbi");
120
130
  const out = [];
121
- d.dbi.forEach((k, v) => {
131
+ d.dbi.forEach(t.txn, (k, v) => {
122
132
  out.push({ key: k, value: v });
123
133
  return true;
124
134
  });
@@ -128,13 +138,15 @@ async function handler(msg) {
128
138
  case "dbi_get_batch": {
129
139
  // Групповое чтение множества ключей
130
140
  const { txnId, dbiId, keys } = params;
141
+ const t = txns.get(txnId);
142
+ if (!t) throw new Error("no txn");
131
143
  const d = dbis.get(dbiId);
132
144
  if (!d || d.txnId !== txnId) throw new Error("no dbi");
133
145
 
134
146
  const results = [];
135
147
  for (const key of keys) {
136
148
  try {
137
- const val = d.dbi.get(key);
149
+ const val = d.dbi.get(t.txn, key);
138
150
  if (val !== undefined && val !== null) {
139
151
  const result = (val && Buffer.isBuffer(val)) ? val.toString() : val;
140
152
  results.push({ key, value: result, found: true });
@@ -151,13 +163,15 @@ async function handler(msg) {
151
163
  case "dbi_put_batch": {
152
164
  // Групповая запись множества пар ключ-значение
153
165
  const { txnId, dbiId, items, flags = 0 } = params;
166
+ const t = txns.get(txnId);
167
+ if (!t) throw new Error("no txn");
154
168
  const d = dbis.get(dbiId);
155
169
  if (!d || d.txnId !== txnId) throw new Error("no dbi");
156
170
 
157
171
  const results = [];
158
172
  for (const item of items) {
159
173
  try {
160
- d.dbi.put(item.key, item.value, flags);
174
+ d.dbi.put(t.txn, item.key, item.value, flags);
161
175
  results.push({ key: item.key, success: true });
162
176
  } catch (e) {
163
177
  results.push({ key: item.key, success: false, error: e.message });
@@ -169,13 +183,15 @@ async function handler(msg) {
169
183
  case "dbi_del_batch": {
170
184
  // Групповое удаление множества ключей
171
185
  const { txnId, dbiId, keys } = params;
186
+ const t = txns.get(txnId);
187
+ if (!t) throw new Error("no txn");
172
188
  const d = dbis.get(dbiId);
173
189
  if (!d || d.txnId !== txnId) throw new Error("no dbi");
174
190
 
175
191
  const results = [];
176
192
  for (const key of keys) {
177
193
  try {
178
- const r = d.dbi.del(key);
194
+ const r = d.dbi.del(t.txn, key);
179
195
  results.push({ key, deleted: r });
180
196
  } catch (e) {
181
197
  results.push({ key, deleted: false, error: e.message });
package/package.json CHANGED
@@ -1,5 +1,17 @@
1
1
  {
2
2
  "main": "lib/nativemou.js",
3
+ "exports": {
4
+ ".": {
5
+ "import": "./lib/index.mjs",
6
+ "require": "./lib/nativemou.js"
7
+ },
8
+ "./async": {
9
+ "import": "./lib/async.mjs",
10
+ "require": "./lib/mdbx_evn_async.js"
11
+ },
12
+ "./nativemou": "./lib/nativemou.js",
13
+ "./package.json": "./package.json"
14
+ },
3
15
  "files": [
4
16
  "lib/**/*",
5
17
  "src/**/*",
@@ -18,6 +30,7 @@
18
30
  "e3": "node ./test/e3.js",
19
31
  "e33": "node ./test/e33.js",
20
32
  "e4": "node ./test/e4.js",
33
+ "e4async": "node ./test/e4async.mjs",
21
34
  "e5": "node ./test/e5.js",
22
35
  "build": "node build.js",
23
36
  "build-dev": "node build-dev.js",
@@ -25,7 +38,7 @@
25
38
  },
26
39
  "gypfile": true,
27
40
  "name": "mdbxmou",
28
- "version": "0.2.1",
41
+ "version": "0.2.4",
29
42
  "description": "Node bindings for mdbx",
30
43
  "repository": {
31
44
  "type": "git",
@@ -10,16 +10,7 @@ void async_keys::Execute()
10
10
  // стартуем транзакцию
11
11
  auto txn = start_transaction();
12
12
  for (auto& req : query_)
13
- {
14
- mdbx::map_handle dbi{};
15
- auto db_mode = req.db_mod;
16
- if (db_mode.val & db_mode::accede) {
17
- dbi = txn.open_map_accede(req.db);
18
- } else {
19
- dbi = txn.open_map(req.db, req.key_mod, req.val_mod);
20
- }
21
- do_keys(txn, dbi, req);
22
- }
13
+ do_keys(txn, {req.id}, req);
23
14
 
24
15
  txn.commit();
25
16
  } catch (const std::exception& e) {
@@ -72,9 +63,6 @@ void async_keys::OnOK()
72
63
  for (std::uint32_t i = 0; i < query_.size(); ++i) {
73
64
  Napi::Object js_row = Napi::Object::New(env);
74
65
  const auto& row = query_[i];
75
- if (!row.db.empty()) {
76
- js_row.Set("db", Napi::String::New(env, row.db_name));
77
- }
78
66
  result.Set(i, write_row(env, row));
79
67
  }
80
68
 
@@ -10,16 +10,7 @@ void async_query::Execute()
10
10
  auto txn = start_transaction();
11
11
  for (auto& req : query_)
12
12
  {
13
- mdbx::map_handle dbi{};
14
- auto db_mode = req.db_mod;
15
- if (db_mode.val & db_mode::accede) {
16
- dbi = txn.open_map_accede(req.db);
17
- } else if (db_mode.val & db_mode::create) {
18
- dbi = txn.create_map(req.db, req.key_mod, req.val_mod);
19
- } else {
20
- dbi = txn.open_map(req.db, req.key_mod, req.val_mod);
21
- }
22
-
13
+ mdbx::map_handle dbi{req.id};
23
14
  auto mode = req.mode;
24
15
  if (mode.val & query_mode::get) {
25
16
  do_get(txn, dbi, req);
@@ -29,7 +20,6 @@ void async_query::Execute()
29
20
  do_put(txn, dbi, req);
30
21
  }
31
22
  }
32
-
33
23
  txn.commit();
34
24
  } catch (const std::exception& e) {
35
25
  SetError(e.what());
@@ -111,9 +101,6 @@ void async_query::OnOK()
111
101
  for (std::size_t i = 0; i < query_.size(); ++i) {
112
102
  Napi::Object js_row = Napi::Object::New(env);
113
103
  const auto& row = query_[i];
114
- if (!row.db.empty()) {
115
- js_row.Set("db", Napi::String::New(env, row.db_name));
116
- }
117
104
  result.Set(static_cast<uint32_t>(i), write_row(env, row));
118
105
  }
119
106
 
package/src/dbimou.cpp CHANGED
@@ -569,13 +569,11 @@ Napi::Value dbimou::keys_from(const Napi::CallbackInfo& info) {
569
569
  Napi::Value dbimou::drop(const Napi::CallbackInfo& info) {
570
570
  Napi::Env env = info.Env();
571
571
  if (info.Length() < 1) {
572
- Napi::TypeError::New(env, "First argument must be a transaction").ThrowAsJavaScriptException();
573
- return env.Undefined();
572
+ throw Napi::TypeError::New(env, "First argument must be a transaction");
574
573
  }
575
574
  auto arg0 = info[0].As<Napi::Object>();
576
575
  if (!arg0.InstanceOf(txnmou::ctor.Value())) {
577
- Napi::TypeError::New(env, "First argument must be a txnmou instance").ThrowAsJavaScriptException();
578
- return env.Undefined();
576
+ throw Napi::TypeError::New(env, "First argument must be a txnmou instance");
579
577
  }
580
578
  auto txn = Napi::ObjectWrap<txnmou>::Unwrap(arg0);
581
579
  bool delete_db = false;
package/src/dbimou.hpp CHANGED
@@ -24,7 +24,6 @@ class dbimou final
24
24
 
25
25
  buffer_type key_buf_{};
26
26
  buffer_type val_buf_{};
27
- std::uint64_t id_buf_{};
28
27
 
29
28
  public:
30
29
  static Napi::FunctionReference ctor;
@@ -60,6 +59,9 @@ public:
60
59
 
61
60
  static void init(const char *class_name, Napi::Env env);
62
61
 
62
+ // valuemou read(const MDBX_txn* txn);
63
+ // valuemou read(const MDBX_txn* txn, const keymou& key);
64
+
63
65
  // Основные операции (только синхронные)
64
66
  Napi::Value put(const Napi::CallbackInfo&);
65
67
  Napi::Value get(const Napi::CallbackInfo&);
@@ -69,7 +71,7 @@ public:
69
71
  Napi::Value stat(const Napi::CallbackInfo&);
70
72
  Napi::Value keys(const Napi::CallbackInfo&);
71
73
  Napi::Value keys_from(const Napi::CallbackInfo&);
72
- Napi::Value drop(const Napi::CallbackInfo& info);
74
+ Napi::Value drop(const Napi::CallbackInfo&);
73
75
 
74
76
  private:
75
77
  // Внутренний метод для forEach с начальным ключом
@@ -92,6 +94,30 @@ public:
92
94
  operator MDBX_put_flags_t() const noexcept {
93
95
  return static_cast<MDBX_put_flags_t>(key_mode_.val & value_mode_.val);
94
96
  }
97
+
98
+ MDBX_dbi get_id() const noexcept {
99
+ return id_;
100
+ }
101
+
102
+ db_mode get_mode() const noexcept {
103
+ return mode_;
104
+ }
105
+
106
+ key_mode get_key_mode() const noexcept {
107
+ return key_mode_;
108
+ }
109
+
110
+ value_mode get_value_mode() const noexcept {
111
+ return value_mode_;
112
+ }
113
+
114
+ base_flag get_key_flag() const noexcept {
115
+ return key_flag_;
116
+ }
117
+
118
+ base_flag get_value_flag() const noexcept {
119
+ return value_flag_;
120
+ }
95
121
  };
96
122
 
97
123
  } // namespace mdbxmou
package/src/envmou.cpp CHANGED
@@ -372,8 +372,7 @@ Napi::Value envmou::query(const Napi::CallbackInfo& info)
372
372
  txn_mode mode{};
373
373
 
374
374
  if (info.Length() < 1) {
375
- throw Napi::TypeError::New(env,
376
- "expected array of requests: [{ db: String, db_mode: Number, key_mode: Number, key_flag: Number, value_mode: Number, value_flag: Number, mode: Number, item: [] }, ...]");
375
+ throw Napi::TypeError::New(env, "expected array of requests");
377
376
  }
378
377
 
379
378
  if (info.Length() > 1 || info[1].IsNumber()) {
@@ -389,8 +388,7 @@ Napi::Value envmou::query(const Napi::CallbackInfo& info)
389
388
  auto conf = get_env_userctx(*this);
390
389
 
391
390
  auto arg0 = info[0];
392
- query_request query = parse_query(mode,
393
- conf->key_flag, conf->value_flag, arg0);
391
+ query_request query = parse_query(mode, arg0);
394
392
  auto* worker = new async_query(env, *this, mode,
395
393
  std::move(query), arg0.IsObject());
396
394
  auto promise = worker->GetPromise();
@@ -429,11 +427,8 @@ Napi::Value envmou::keys(const Napi::CallbackInfo& info)
429
427
 
430
428
  check();
431
429
 
432
- auto conf = get_env_userctx(*this);
433
-
434
430
  auto arg0 = info[0];
435
- keys_request query = parse_keys(mode,
436
- conf->key_flag, conf->value_flag, arg0);
431
+ keys_request query = parse_keys(arg0);
437
432
 
438
433
  auto* worker = new async_keys(env, *this, mode,
439
434
  std::move(query), arg0.IsObject());
package/src/modulemou.cpp CHANGED
@@ -78,24 +78,24 @@ Napi::Object Init(Napi::Env env, Napi::Object exports)
78
78
  MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "last", move_operation::last);
79
79
  MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "next", move_operation::next);
80
80
  MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "prev", move_operation::previous);
81
- MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "key_lesser_than",
81
+ MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "keyLesserThan",
82
82
  move_operation::key_lesser_than);
83
- MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "key_lesser_or_equal",
83
+ MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "keyLesserOrEqual",
84
84
  move_operation::key_lesser_or_equal);
85
- MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "key_equal", move_operation::key_equal);
86
- MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "key_greater_or_equal",
85
+ MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "keyEqual", move_operation::key_equal);
86
+ MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "keyGreaterOrEqual",
87
87
  move_operation::key_greater_or_equal);
88
- MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "key_greater_than",
88
+ MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "keyGreaterThan",
89
89
  move_operation::key_greater_than);
90
- MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "multi_exactkey_value_lesser_than",
90
+ MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "multiExactKeyValueLesserThan",
91
91
  move_operation::multi_exactkey_value_lesser_than);
92
- MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "multi_exactkey_value_lesser_or_equal",
92
+ MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "multiExactKeyValueLesserOrEqual",
93
93
  move_operation::multi_exactkey_value_lesser_or_equal);
94
- MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "multi_exactkey_value_equal",
94
+ MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "multiExactKeyValueEqual",
95
95
  move_operation::multi_exactkey_value_equal);
96
- MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "multi_exactkey_value_greater_or_equal",
96
+ MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "multiExactKeyValueGreaterOrEqual",
97
97
  move_operation::multi_exactkey_value_greater_or_equal);
98
- MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "multi_exactkey_value_greater",
98
+ MDBXMOU_DECLARE_FLAG_NAME(cursor_mode, "multiExactKeyValueGreater",
99
99
  move_operation::multi_exactkey_value_greater);
100
100
  mdbx_mou.Set("cursorMode", cursor_mode);
101
101
 
package/src/querymou.cpp CHANGED
@@ -1,30 +1,24 @@
1
1
  #include "querymou.hpp"
2
+ #include "dbimou.hpp"
2
3
 
3
4
  namespace mdbxmou {
4
5
 
5
- void async_common::parse(txn_mode txn, const Napi::Object& obj)
6
+ dbimou* async_common::parse(const Napi::Object& arg0)
6
7
  {
7
- if (obj.Has("db")) {
8
- db_name = obj.Get("db").As<Napi::String>().Utf8Value();
9
- db = mdbx::slice{db_name};
10
- }
11
-
12
- if (obj.Has("dbMode")) {
13
- db_mod = db_mode::parse(txn, obj.Get("dbMode").As<Napi::Number>());
14
- }
15
-
16
- if (obj.Has("keyFlag")) {
17
- key_flag = base_flag::parse_key(obj.Get("keyFlag").As<Napi::Number>());
18
- }
19
-
20
- if (obj.Has("keyMode")) {
21
- key_mod = parse_key_mode(obj.Env(), obj.Get("keyMode").As<Napi::Number>(), key_flag);
8
+ dbimou* dbi = nullptr;
9
+ // если просто передали dbi
10
+ if (arg0.InstanceOf(dbimou::ctor.Value())) {
11
+ dbi = Napi::ObjectWrap<dbimou>::Unwrap(arg0);
12
+ } else {
13
+ auto t = arg0.Get("dbi").As<Napi::Object>();
14
+ dbi = Napi::ObjectWrap<dbimou>::Unwrap(t);
22
15
  }
23
16
 
24
- // парсим value
25
- if (obj.Has("valueMode")) {
26
- val_mod = value_mode::parse(obj.Get("valueMode").As<Napi::Number>());
27
- }
17
+ id = dbi->get_id();
18
+ key_mod = dbi->get_key_mode();
19
+ val_mod = dbi->get_value_mode();
20
+ key_flag = dbi->get_key_flag();
21
+ return dbi;
28
22
  }
29
23
 
30
24
  void async_key::parse(const async_common& common, const Napi::Value& item)
@@ -59,101 +53,75 @@ void async_keyval::parse(const query_line& common, const Napi::Object& item)
59
53
  }
60
54
  }
61
55
 
62
- void query_line::parse(txn_mode txn, const Napi::Object& obj)
56
+ void query_line::parse(txn_mode txn, const Napi::Object& arg0)
63
57
  {
64
58
  // парсим общие параметры
65
- async_common::parse(txn, obj);
66
-
67
- if (obj.Has("valueFlag")) {
68
- value_flag = base_flag::parse_value(val_mod,
69
- obj.Get("valueFlag").As<Napi::Number>());
70
- }
71
-
72
- if (obj.Has("mode")) {
73
- mode = query_mode::parse(txn, obj.Get("mode").As<Napi::Number>());
74
- } else if (obj.Has("queryMode")) {
75
- mode = query_mode::parse(txn, obj.Get("queryMode").As<Napi::Number>());
76
- }
77
- }
78
-
79
- void query_line::parse(txn_mode txn, base_flag kf,
80
- base_flag vf, const Napi::Object& obj)
81
- {
82
- // утснавлиаем общие параметры
83
- this->key_flag = kf;
84
- this->value_flag = vf;
85
-
86
- // парсим общие параметры
87
- parse(txn, obj);
88
-
89
- // Парсим элементы
90
- if (obj.Has("item")) {
91
- auto items_array = obj.Get("item").As<Napi::Array>();
92
- auto length = items_array.Length();
93
- item.reserve(length);
94
- for (uint32_t i = 0; i < length; ++i) {
59
+ auto dbi = async_common::parse(arg0);
60
+ value_flag = dbi->get_value_flag();
61
+ if (arg0.Has("mode")) {
62
+ mode = query_mode::parse(txn, arg0.Get("mode").As<Napi::Number>());
63
+ } else if (arg0.Has("queryMode")) {
64
+ mode = query_mode::parse(txn, arg0.Get("queryMode").As<Napi::Number>());
65
+ }
66
+ auto items_array = arg0.Get("item").As<Napi::Array>();
67
+ auto item_len = items_array.Length();
68
+ if (item_len > 0) {
69
+ item.reserve(item_len);
70
+ for (uint32_t i = 0; i < item_len; ++i) {
95
71
  auto item_obj = items_array.Get(i).As<Napi::Object>();
96
72
  async_keyval keyval{};
97
73
  keyval.parse(*this, item_obj);
98
74
  item.emplace_back(std::move(keyval));
99
75
  }
100
- } else {
101
- throw std::runtime_error("query: no item");
102
76
  }
103
77
  }
104
78
 
105
- query_request parse_query(txn_mode mode, base_flag key_flag,
106
- base_flag value_flag, const Napi::Value& obj)
79
+ query_request parse_query(txn_mode txn, const Napi::Value& arg0)
107
80
  {
108
81
  query_request rc{};
109
- if (obj.IsArray()) {
110
- auto arr = obj.As<Napi::Array>();
82
+ if (arg0.IsArray()) {
83
+ auto arr = arg0.As<Napi::Array>();
111
84
  rc.reserve(arr.Length());
112
85
  for (uint32_t i = 0; i < arr.Length(); ++i) {
113
86
  query_line row{};
114
- row.parse(mode, key_flag, value_flag, arr.Get(i).As<Napi::Object>());
87
+ row.parse(txn, arr.Get(i).As<Napi::Object>());
115
88
  rc.push_back(std::move(row));
116
89
  }
117
- } else if (obj.IsObject()) {
90
+ } else if (arg0.IsObject()) {
118
91
  query_line row{};
119
- row.parse(mode, key_flag, value_flag, obj.As<Napi::Object>());
92
+ row.parse(txn, arg0.As<Napi::Object>());
120
93
  rc.push_back(std::move(row));
121
94
  } else {
122
- throw Napi::TypeError::New(obj.Env(), "Expected array or object for query");
95
+ throw Napi::TypeError::New(arg0.Env(), "Expected array or object for query");
123
96
  }
124
97
  return rc;
125
98
  }
126
99
 
127
- void keys_line::parse(txn_mode txn,
128
- base_flag kf, const Napi::Object& obj)
100
+ void keys_line::parse(const Napi::Object& arg0)
129
101
  {
130
- // утснавлиаем общие параметры
131
- this->key_flag = kf;
132
-
133
102
  // парсим общие параметры
134
- async_common::parse(txn, obj);
103
+ async_common::parse(arg0);
135
104
 
136
105
  // парсим параметры scan_from
137
- if (obj.Has("from")) {
106
+ if (arg0.Has("from")) {
138
107
  keymou key{};
139
108
  has_from_key = true;
140
- async_key::parse(*this, obj.Get("from"));
109
+ async_key::parse(*this, arg0.Get("from"));
141
110
  }
142
111
 
143
- if (obj.Has("limit")) {
144
- auto limit_val = obj.Get("limit");
112
+ if (arg0.Has("limit")) {
113
+ auto limit_val = arg0.Get("limit");
145
114
  if (limit_val.IsNumber()) {
146
115
  limit = limit_val.As<Napi::Number>().Uint32Value();
147
116
  }
148
117
  }
149
118
 
150
- if (obj.Has("cursorMode")) {
151
- cursor_mode = parse_cursor_mode(obj.Get("cursorMode"));
119
+ if (arg0.Has("cursorMode")) {
120
+ cursor_mode = parse_cursor_mode(arg0.Get("cursorMode"));
152
121
  }
153
122
  }
154
123
 
155
- keys_request parse_keys(txn_mode txn, base_flag key_flag,
156
- base_flag value_flag, const Napi::Value& obj)
124
+ keys_request parse_keys(const Napi::Value& obj)
157
125
  {
158
126
  keys_request rc{};
159
127
  if (obj.IsArray()) {
@@ -161,12 +129,12 @@ keys_request parse_keys(txn_mode txn, base_flag key_flag,
161
129
  rc.reserve(arr.Length());
162
130
  for (uint32_t i = 0; i < arr.Length(); ++i) {
163
131
  keys_line row{};
164
- row.parse(txn, key_flag, arr.Get(i).As<Napi::Object>());
132
+ row.parse(arr.Get(i).As<Napi::Object>());
165
133
  rc.push_back(std::move(row));
166
134
  }
167
135
  } else if (obj.IsObject()) {
168
136
  keys_line row{};
169
- row.parse(txn, key_flag, obj.As<Napi::Object>());
137
+ row.parse(obj.As<Napi::Object>());
170
138
  rc.push_back(std::move(row));
171
139
  } else {
172
140
  throw Napi::TypeError::New(obj.Env(), "Expected array or object for query");
package/src/querymou.hpp CHANGED
@@ -5,28 +5,28 @@
5
5
 
6
6
  namespace mdbxmou {
7
7
 
8
+ class dbimou;
8
9
  struct keys_line;
9
10
  struct query_line;
10
11
 
11
12
  struct async_common
12
13
  {
13
14
  // чтобы уметь открыть базу по умолчанию
14
- mdbx::slice db{};
15
- std::string db_name{};
16
- db_mode db_mod{};
15
+ MDBX_dbi id{};
17
16
  // тут важен для нас ordinal он влияет на option_mask
18
17
  key_mode key_mod{};
19
18
  base_flag key_flag{};
20
19
  // общий используется для открытия db
21
20
  value_mode val_mod{};
22
21
 
23
- void parse(txn_mode mode, const Napi::Object& obj);
22
+ dbimou* parse(const Napi::Object& arg0);
24
23
  };
25
24
 
26
25
  struct async_key
27
26
  {
28
- buffer_type key_buf{};
29
27
  std::uint64_t id_buf{};
28
+ buffer_type key_buf{};
29
+
30
30
  void parse(const async_common& common, const Napi::Value& item);
31
31
 
32
32
  void parse(const async_common& common, const Napi::Object& item)
@@ -57,18 +57,13 @@ struct query_line
57
57
  {
58
58
  base_flag value_flag{};
59
59
  query_mode mode{};
60
-
61
- void parse(txn_mode mode, const Napi::Object& obj);
62
-
63
60
  // буффер для запроса / ответа
64
61
  std::vector<async_keyval> item{};
65
- void parse(txn_mode txn, base_flag key_flag,
66
- base_flag value_flag, const Napi::Object& obj);
62
+ void parse(txn_mode txn, const Napi::Object& arg0);
67
63
  };
68
64
 
69
65
  using query_request = std::vector<query_line>;
70
- query_request parse_query(txn_mode txn, base_flag key_flag,
71
- base_flag value_flag, const Napi::Value& obj);
66
+ query_request parse_query(txn_mode txn, const Napi::Value& arg0);
72
67
 
73
68
 
74
69
  struct keys_line
@@ -82,12 +77,10 @@ struct keys_line
82
77
  // буффер для ответов
83
78
  std::vector<async_key> item{};
84
79
 
85
- void parse(txn_mode txn, base_flag key_flag,
86
- const Napi::Object& obj);
80
+ void parse(const Napi::Object& arg0);
87
81
  };
88
82
 
89
83
  using keys_request = std::vector<keys_line>;
90
- keys_request parse_keys(txn_mode txn, base_flag key_flag,
91
- base_flag value_flag, const Napi::Value& obj);
84
+ keys_request parse_keys(const Napi::Value& obj);
92
85
 
93
86
  } // namespace mdbxmou
package/src/txnmou.cpp CHANGED
@@ -251,12 +251,4 @@ void txnmou::free_txn::operator()(MDBX_txn* txn) const noexcept {
251
251
  }
252
252
  }
253
253
 
254
- void txnmou::drop(MDBX_dbi id, bool del)
255
- {
256
- auto rc = mdbx_drop(*this, id, del);
257
- if (rc != MDBX_SUCCESS) {
258
- throw std::runtime_error(mdbx_strerror(rc));
259
- }
260
- }
261
-
262
254
  } // namespace mdbxmou
package/src/txnmou.hpp CHANGED
@@ -117,8 +117,6 @@ public:
117
117
 
118
118
  void attach(envmou& env, MDBX_txn* txn,
119
119
  txn_mode mode, txnmou* parent = nullptr);
120
-
121
- void drop(MDBX_dbi id, bool del);
122
120
  };
123
121
 
124
122
  } // namespace mdbxmou
package/src/typemou.hpp CHANGED
@@ -10,7 +10,7 @@ namespace mdbxmou {
10
10
  using buffer_type = std::vector<char>;
11
11
 
12
12
  struct txnmou_managed final
13
- : public mdbx::txn_managed
13
+ : mdbx::txn_managed
14
14
  {
15
15
  txnmou_managed(MDBX_txn* txn)
16
16
  {
@@ -19,7 +19,7 @@ struct txnmou_managed final
19
19
  };
20
20
 
21
21
  struct cursormou_managed final
22
- : public mdbx::cursor_managed
22
+ : mdbx::cursor_managed
23
23
  {
24
24
  cursormou_managed(MDBX_cursor* cursor) noexcept
25
25
  {