mdbxmou 0.3.9 → 0.3.11
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 +1 -1
- package/README.md +90 -1
- package/lib/nativemou.js +1 -2
- package/lib/types.d.ts +15 -1
- package/package.json +4 -1
- package/src/async/envmou_keys.cpp +54 -65
- package/src/async/envmou_query.cpp +9 -26
- package/src/convmou.cpp +34 -0
- package/src/convmou.hpp +30 -0
- package/src/cursormou.cpp +4 -74
- package/src/dbimou.cpp +325 -194
- package/src/dbimou.hpp +8 -0
- package/src/envmou.cpp +0 -14
- package/src/modulemou.cpp +21 -22
- package/src/querymou.cpp +3 -3
- package/src/txnmou.cpp +16 -0
- package/src/txnmou.hpp +3 -0
- package/src/typemou.hpp +57 -33
package/src/dbimou.cpp
CHANGED
|
@@ -2,9 +2,253 @@
|
|
|
2
2
|
#include "envmou.hpp"
|
|
3
3
|
#include "txnmou.hpp"
|
|
4
4
|
#include "typemou.hpp"
|
|
5
|
+
#include <limits>
|
|
5
6
|
|
|
6
7
|
namespace mdbxmou {
|
|
7
8
|
|
|
9
|
+
namespace {
|
|
10
|
+
|
|
11
|
+
enum class range_output {
|
|
12
|
+
items,
|
|
13
|
+
keys,
|
|
14
|
+
values,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
std::size_t parse_size_option(const Napi::Env& env, const Napi::Object& options, const char* key)
|
|
18
|
+
{
|
|
19
|
+
auto value = options.Get(key);
|
|
20
|
+
if (value.IsUndefined() || value.IsNull()) {
|
|
21
|
+
return std::numeric_limits<std::size_t>::max();
|
|
22
|
+
}
|
|
23
|
+
if (!value.IsNumber()) {
|
|
24
|
+
throw Napi::TypeError::New(env, std::string(key) + " must be a number");
|
|
25
|
+
}
|
|
26
|
+
auto parsed = value.As<Napi::Number>().Int64Value();
|
|
27
|
+
if (parsed < 0) {
|
|
28
|
+
throw Napi::TypeError::New(env, std::string(key) + " must be >= 0");
|
|
29
|
+
}
|
|
30
|
+
return static_cast<std::size_t>(parsed);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
bool parse_bool_option(const Napi::Env& env, const Napi::Object& options, const char* key, bool fallback)
|
|
34
|
+
{
|
|
35
|
+
auto value = options.Get(key);
|
|
36
|
+
if (value.IsUndefined() || value.IsNull()) {
|
|
37
|
+
return fallback;
|
|
38
|
+
}
|
|
39
|
+
if (!value.IsBoolean()) {
|
|
40
|
+
throw Napi::TypeError::New(env, std::string(key) + " must be a boolean");
|
|
41
|
+
}
|
|
42
|
+
return value.As<Napi::Boolean>().Value();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
struct range_options final
|
|
46
|
+
{
|
|
47
|
+
bool has_start{};
|
|
48
|
+
bool has_end{};
|
|
49
|
+
bool reverse{};
|
|
50
|
+
bool include_start{true};
|
|
51
|
+
bool include_end{true};
|
|
52
|
+
std::size_t limit{std::numeric_limits<std::size_t>::max()};
|
|
53
|
+
std::size_t offset{};
|
|
54
|
+
std::uint64_t start_num{};
|
|
55
|
+
std::uint64_t end_num{};
|
|
56
|
+
buffer_type start_buf{};
|
|
57
|
+
buffer_type end_buf{};
|
|
58
|
+
keymou start_key{};
|
|
59
|
+
keymou end_key{};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
range_options parse_range_options(const Napi::Env& env, const Napi::Value& arg0, const dbimou& self)
|
|
63
|
+
{
|
|
64
|
+
range_options options{};
|
|
65
|
+
if (arg0.IsUndefined() || arg0.IsNull()) {
|
|
66
|
+
return options;
|
|
67
|
+
}
|
|
68
|
+
if (!arg0.IsObject()) {
|
|
69
|
+
throw Napi::TypeError::New(env, "getRange options must be an object");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
auto obj = arg0.As<Napi::Object>();
|
|
73
|
+
options.limit = parse_size_option(env, obj, "limit");
|
|
74
|
+
|
|
75
|
+
auto offset = obj.Get("offset");
|
|
76
|
+
if (!offset.IsUndefined() && !offset.IsNull()) {
|
|
77
|
+
if (!offset.IsNumber()) {
|
|
78
|
+
throw Napi::TypeError::New(env, "offset must be a number");
|
|
79
|
+
}
|
|
80
|
+
auto parsed = offset.As<Napi::Number>().Int64Value();
|
|
81
|
+
if (parsed < 0) {
|
|
82
|
+
throw Napi::TypeError::New(env, "offset must be >= 0");
|
|
83
|
+
}
|
|
84
|
+
options.offset = static_cast<std::size_t>(parsed);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
options.reverse = parse_bool_option(env, obj, "reverse", false);
|
|
88
|
+
options.include_start = parse_bool_option(env, obj, "includeStart", true);
|
|
89
|
+
options.include_end = parse_bool_option(env, obj, "includeEnd", true);
|
|
90
|
+
|
|
91
|
+
auto start = obj.Get("start");
|
|
92
|
+
if (!start.IsUndefined() && !start.IsNull()) {
|
|
93
|
+
options.has_start = true;
|
|
94
|
+
options.start_key = mdbx::is_ordinal(self.get_key_mode()) ?
|
|
95
|
+
keymou::from(start, env, options.start_num) :
|
|
96
|
+
keymou::from(start, env, options.start_buf);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
auto end = obj.Get("end");
|
|
100
|
+
if (!end.IsUndefined() && !end.IsNull()) {
|
|
101
|
+
options.has_end = true;
|
|
102
|
+
options.end_key = mdbx::is_ordinal(self.get_key_mode()) ?
|
|
103
|
+
keymou::from(end, env, options.end_num) :
|
|
104
|
+
keymou::from(end, env, options.end_buf);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return options;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
bool cursor_get(cursormou_managed& cursor, MDBX_cursor_op op, mdbx::slice& key, mdbx::slice& value)
|
|
111
|
+
{
|
|
112
|
+
auto rc = ::mdbx_cursor_get(cursor, &key, &value, op);
|
|
113
|
+
switch (rc) {
|
|
114
|
+
case MDBX_SUCCESS:
|
|
115
|
+
case MDBX_RESULT_TRUE:
|
|
116
|
+
return true;
|
|
117
|
+
case MDBX_NOTFOUND:
|
|
118
|
+
return false;
|
|
119
|
+
default:
|
|
120
|
+
mdbx::error::throw_exception(rc);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
bool outside_range(MDBX_txn* txn, MDBX_dbi dbi, const mdbx::slice& key, const range_options& options)
|
|
126
|
+
{
|
|
127
|
+
if (options.reverse) {
|
|
128
|
+
if (!options.has_start) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
auto cmp = ::mdbx_cmp(
|
|
132
|
+
txn, dbi,
|
|
133
|
+
static_cast<const MDBX_val*>(&key),
|
|
134
|
+
static_cast<const MDBX_val*>(&options.start_key));
|
|
135
|
+
return cmp < 0 || (!options.include_start && cmp == 0);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!options.has_end) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
auto cmp = ::mdbx_cmp(
|
|
142
|
+
txn, dbi,
|
|
143
|
+
static_cast<const MDBX_val*>(&key),
|
|
144
|
+
static_cast<const MDBX_val*>(&options.end_key));
|
|
145
|
+
return cmp > 0 || (!options.include_end && cmp == 0);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
MDBX_cursor_op range_start_op(const range_options& options)
|
|
149
|
+
{
|
|
150
|
+
if (options.reverse) {
|
|
151
|
+
if (!options.has_end) {
|
|
152
|
+
return MDBX_LAST;
|
|
153
|
+
}
|
|
154
|
+
return options.include_end ? MDBX_TO_KEY_LESSER_OR_EQUAL : MDBX_TO_KEY_LESSER_THAN;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!options.has_start) {
|
|
158
|
+
return MDBX_FIRST;
|
|
159
|
+
}
|
|
160
|
+
return options.include_start ? MDBX_TO_KEY_GREATER_OR_EQUAL : MDBX_TO_KEY_GREATER_THAN;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
MDBX_cursor_op range_turn_op(const range_options& options)
|
|
164
|
+
{
|
|
165
|
+
return options.reverse ? MDBX_PREV : MDBX_NEXT;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
Napi::Array collect_range(const Napi::Env& env, dbimou& self, txnmou& txn, const range_options& options, range_output output)
|
|
169
|
+
{
|
|
170
|
+
Napi::Array result = Napi::Array::New(env);
|
|
171
|
+
if (options.limit == 0) {
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
auto conv = self.get_convmou();
|
|
176
|
+
auto cursor = self.open_cursor(txn);
|
|
177
|
+
mdbx::slice key{};
|
|
178
|
+
mdbx::slice value{};
|
|
179
|
+
|
|
180
|
+
if (options.reverse) {
|
|
181
|
+
if (options.has_end) {
|
|
182
|
+
key = options.end_key;
|
|
183
|
+
}
|
|
184
|
+
} else if (options.has_start) {
|
|
185
|
+
key = options.start_key;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (!cursor_get(cursor, range_start_op(options), key, value)) {
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
std::size_t skipped{};
|
|
193
|
+
std::size_t index{};
|
|
194
|
+
auto turn_op = range_turn_op(options);
|
|
195
|
+
|
|
196
|
+
while (true) {
|
|
197
|
+
if (outside_range(txn, self.get_id(), key, options)) {
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (skipped < options.offset) {
|
|
202
|
+
++skipped;
|
|
203
|
+
} else {
|
|
204
|
+
switch (output) {
|
|
205
|
+
case range_output::items: {
|
|
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;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
++index;
|
|
218
|
+
if (index >= options.limit) {
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!cursor_get(cursor, turn_op, key, value)) {
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return result;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
Napi::Value run_range_query(const Napi::CallbackInfo& info, dbimou& self, const char* method_name, range_output output)
|
|
232
|
+
{
|
|
233
|
+
Napi::Env env = info.Env();
|
|
234
|
+
if (info.Length() < 1) {
|
|
235
|
+
throw Napi::TypeError::New(env, std::string(method_name) + ": txnmou required");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
auto txn = txnmou::unwrap_checked(env, info[0], method_name);
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
auto options = info.Length() > 1 ?
|
|
242
|
+
parse_range_options(env, info[1], self) :
|
|
243
|
+
range_options{};
|
|
244
|
+
return collect_range(env, self, *txn, options, output);
|
|
245
|
+
} catch (const std::exception& e) {
|
|
246
|
+
throw Napi::Error::New(env, std::string(method_name) + ": " + e.what());
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
} // namespace
|
|
251
|
+
|
|
8
252
|
Napi::FunctionReference dbimou::ctor{};
|
|
9
253
|
|
|
10
254
|
void dbimou::init(const char *class_name, Napi::Env env)
|
|
@@ -18,6 +262,9 @@ void dbimou::init(const char *class_name, Napi::Env env)
|
|
|
18
262
|
InstanceMethod("stat", &dbimou::stat),
|
|
19
263
|
InstanceMethod("keys", &dbimou::keys),
|
|
20
264
|
InstanceMethod("keysFrom", &dbimou::keys_from),
|
|
265
|
+
InstanceMethod("getRange", &dbimou::get_range),
|
|
266
|
+
InstanceMethod("keysRange", &dbimou::keys_range),
|
|
267
|
+
InstanceMethod("valuesRange", &dbimou::values_range),
|
|
21
268
|
InstanceMethod("drop", &dbimou::drop),
|
|
22
269
|
|
|
23
270
|
// Свойства только для чтения
|
|
@@ -40,12 +287,7 @@ Napi::Value dbimou::put(const Napi::CallbackInfo& info)
|
|
|
40
287
|
if (arg_len < 3) {
|
|
41
288
|
throw Napi::Error::New(env, "put: txnmou, key and value required");
|
|
42
289
|
}
|
|
43
|
-
auto
|
|
44
|
-
// Дополнительная проверка - есть ли у объекта нужный constructor
|
|
45
|
-
if (!arg0.InstanceOf(txnmou::ctor.Value())) {
|
|
46
|
-
throw Napi::TypeError::New(env, "put: first argument must be MDBX_Txn instance");
|
|
47
|
-
}
|
|
48
|
-
auto txn = Napi::ObjectWrap<txnmou>::Unwrap(arg0);
|
|
290
|
+
auto txn = txnmou::unwrap_checked(env, info[0], "put");
|
|
49
291
|
try {
|
|
50
292
|
std::uint64_t t;
|
|
51
293
|
auto key = mdbx::is_ordinal(key_mode_) ?
|
|
@@ -68,14 +310,10 @@ Napi::Value dbimou::get(const Napi::CallbackInfo& info)
|
|
|
68
310
|
if (arg_len < 2) {
|
|
69
311
|
throw Napi::Error::New(env, "get: txnmou and key required");
|
|
70
312
|
}
|
|
71
|
-
auto
|
|
72
|
-
// Дополнительная проверка - есть ли у объекта нужный constructor
|
|
73
|
-
if (!arg0.InstanceOf(txnmou::ctor.Value())) {
|
|
74
|
-
throw Napi::TypeError::New(env, "get: first argument must be MDBX_Txn instance");
|
|
75
|
-
}
|
|
76
|
-
auto txn = Napi::ObjectWrap<txnmou>::Unwrap(arg0);
|
|
313
|
+
auto txn = txnmou::unwrap_checked(env, info[0], "get");
|
|
77
314
|
|
|
78
315
|
try {
|
|
316
|
+
auto conv = get_convmou();
|
|
79
317
|
std::uint64_t t;
|
|
80
318
|
auto key = mdbx::is_ordinal(key_mode_) ?
|
|
81
319
|
keymou::from(info[1], env, t) :
|
|
@@ -86,8 +324,7 @@ Napi::Value dbimou::get(const Napi::CallbackInfo& info)
|
|
|
86
324
|
return env.Undefined();
|
|
87
325
|
}
|
|
88
326
|
|
|
89
|
-
return (
|
|
90
|
-
val.to_string(env) : val.to_buffer(env);
|
|
327
|
+
return conv.convert_value(env, val);
|
|
91
328
|
} catch (const std::exception& e) {
|
|
92
329
|
throw Napi::Error::New(env, std::string("get: ") + e.what());
|
|
93
330
|
}
|
|
@@ -102,12 +339,7 @@ Napi::Value dbimou::del(const Napi::CallbackInfo& info)
|
|
|
102
339
|
if (arg_len < 2) {
|
|
103
340
|
throw Napi::Error::New(env, "del: txnmou and key required");
|
|
104
341
|
}
|
|
105
|
-
auto
|
|
106
|
-
// Дополнительная проверка - есть ли у объекта нужный constructor
|
|
107
|
-
if (!arg0.InstanceOf(txnmou::ctor.Value())) {
|
|
108
|
-
throw Napi::TypeError::New(env, "del: first argument must be MDBX_Txn instance");
|
|
109
|
-
}
|
|
110
|
-
auto txn = Napi::ObjectWrap<txnmou>::Unwrap(arg0);
|
|
342
|
+
auto txn = txnmou::unwrap_checked(env, info[0], "del");
|
|
111
343
|
|
|
112
344
|
try {
|
|
113
345
|
std::uint64_t t;
|
|
@@ -131,12 +363,7 @@ Napi::Value dbimou::has(const Napi::CallbackInfo& info)
|
|
|
131
363
|
if (arg_len < 2) {
|
|
132
364
|
throw Napi::Error::New(env, "has: txnmou and key required");
|
|
133
365
|
}
|
|
134
|
-
auto
|
|
135
|
-
// Дополнительная проверка - есть ли у объекта нужный constructor
|
|
136
|
-
if (!arg0.InstanceOf(txnmou::ctor.Value())) {
|
|
137
|
-
throw Napi::TypeError::New(env, "has: first argument must be MDBX_Txn instance");
|
|
138
|
-
}
|
|
139
|
-
auto txn = Napi::ObjectWrap<txnmou>::Unwrap(arg0);
|
|
366
|
+
auto txn = txnmou::unwrap_checked(env, info[0], "has");
|
|
140
367
|
|
|
141
368
|
try {
|
|
142
369
|
std::uint64_t t;
|
|
@@ -160,12 +387,7 @@ Napi::Value dbimou::for_each(const Napi::CallbackInfo& info)
|
|
|
160
387
|
if (arg_len < 2) {
|
|
161
388
|
throw Napi::Error::New(env, "for_each: txnmou and function required");
|
|
162
389
|
}
|
|
163
|
-
auto
|
|
164
|
-
// Дополнительная проверка - есть ли у объекта нужный constructor
|
|
165
|
-
if (!arg0.InstanceOf(txnmou::ctor.Value())) {
|
|
166
|
-
throw Napi::TypeError::New(env, "for_each: first argument must be MDBX_Txn instance");
|
|
167
|
-
}
|
|
168
|
-
auto txn = Napi::ObjectWrap<txnmou>::Unwrap(arg0);
|
|
390
|
+
auto txn = txnmou::unwrap_checked(env, info[0], "for_each");
|
|
169
391
|
|
|
170
392
|
// Проверяем тип вызова: forEach(txn, fn), forEach(txn, fromKey, fn) или forEach(txn, fromKey, cursorMode, fn)
|
|
171
393
|
if (info.Length() == 2 && info[1].IsFunction()) {
|
|
@@ -173,6 +395,7 @@ Napi::Value dbimou::for_each(const Napi::CallbackInfo& info)
|
|
|
173
395
|
auto fn = info[1].As<Napi::Function>();
|
|
174
396
|
|
|
175
397
|
try {
|
|
398
|
+
auto conv = get_convmou();
|
|
176
399
|
auto stat = get_stat(*txn);
|
|
177
400
|
|
|
178
401
|
// Проверяем, есть ли записи в базе данных
|
|
@@ -182,46 +405,20 @@ Napi::Value dbimou::for_each(const Napi::CallbackInfo& info)
|
|
|
182
405
|
|
|
183
406
|
auto cursor = open_cursor(*txn);
|
|
184
407
|
uint32_t index{};
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
// Конвертируем значение
|
|
193
|
-
Napi::Value rc_val = (value_flag_.val & base_flag::string) ?
|
|
194
|
-
val.to_string(env) : val.to_buffer(env);
|
|
195
|
-
// Формируем результат
|
|
196
|
-
Napi::Value result = fn.Call({ rc_key, rc_val,
|
|
197
|
-
Napi::Number::New(env, static_cast<double>(index)) });
|
|
198
|
-
|
|
199
|
-
index++;
|
|
200
|
-
|
|
201
|
-
// true will stop the scan, false will continue
|
|
202
|
-
return result.IsBoolean() ? result.ToBoolean() : false;
|
|
203
|
-
});
|
|
204
|
-
} else {
|
|
205
|
-
cursor.scan([&](const mdbx::pair& f) {
|
|
206
|
-
keymou key{f.key};
|
|
207
|
-
valuemou val{f.value};
|
|
208
|
-
// Конвертируем ключ
|
|
209
|
-
Napi::Value rc_key = (key_flag_.val & base_flag::string) ?
|
|
210
|
-
key.to_string(env) : key.to_buffer(env);
|
|
211
|
-
|
|
212
|
-
// Конвертируем значение
|
|
213
|
-
Napi::Value rc_val = (value_flag_.val & base_flag::string) ?
|
|
214
|
-
val.to_string(env) : val.to_buffer(env);
|
|
215
|
-
// Формируем результат
|
|
216
|
-
Napi::Value result = fn.Call({ rc_key, rc_val,
|
|
217
|
-
Napi::Number::New(env, static_cast<double>(index)) });
|
|
218
|
-
|
|
219
|
-
index++;
|
|
220
|
-
|
|
221
|
-
// true will stop the scan, false will continue
|
|
222
|
-
return result.IsBoolean() ? result.ToBoolean() : false;
|
|
408
|
+
cursor.scan([&](const mdbx::pair& f) {
|
|
409
|
+
keymou key{f.key};
|
|
410
|
+
valuemou val{f.value};
|
|
411
|
+
Napi::Value result = fn.Call({
|
|
412
|
+
conv.convert_key(env, key),
|
|
413
|
+
conv.convert_value(env, val),
|
|
414
|
+
Napi::Number::New(env, static_cast<double>(index))
|
|
223
415
|
});
|
|
224
|
-
|
|
416
|
+
|
|
417
|
+
index++;
|
|
418
|
+
|
|
419
|
+
// true will stop the scan, false will continue
|
|
420
|
+
return result.IsBoolean() ? result.ToBoolean() : false;
|
|
421
|
+
});
|
|
225
422
|
|
|
226
423
|
return Napi::Number::New(env, static_cast<double>(index));
|
|
227
424
|
} catch (const std::exception& e) {
|
|
@@ -247,12 +444,7 @@ Napi::Value dbimou::for_each_from(const Napi::CallbackInfo& info)
|
|
|
247
444
|
throw Napi::Error::New(env, "for_each_from: txnmou, fromKey and function required");
|
|
248
445
|
}
|
|
249
446
|
|
|
250
|
-
auto
|
|
251
|
-
// Дополнительная проверка - есть ли у объекта нужный constructor
|
|
252
|
-
if (!arg0.InstanceOf(txnmou::ctor.Value())) {
|
|
253
|
-
throw Napi::TypeError::New(env, "for_each_from: first argument must be MDBX_Txn instance");
|
|
254
|
-
}
|
|
255
|
-
auto txn = Napi::ObjectWrap<txnmou>::Unwrap(arg0);
|
|
447
|
+
auto txn = txnmou::unwrap_checked(env, info[0], "for_each_from");
|
|
256
448
|
|
|
257
449
|
// Определяем позицию функции: info[2] или info[3]
|
|
258
450
|
Napi::Function fn;
|
|
@@ -265,6 +457,7 @@ Napi::Value dbimou::for_each_from(const Napi::CallbackInfo& info)
|
|
|
265
457
|
}
|
|
266
458
|
|
|
267
459
|
try {
|
|
460
|
+
auto conv = get_convmou();
|
|
268
461
|
auto cursor = dbi::open_cursor(*txn);
|
|
269
462
|
auto stat = dbi::get_stat(*txn);
|
|
270
463
|
|
|
@@ -309,58 +502,30 @@ Napi::Value dbimou::for_each_from(const Napi::CallbackInfo& info)
|
|
|
309
502
|
std::size_t index{};
|
|
310
503
|
bool is_key_equal_mode = (cursor_mode == move_operation::key_equal ||
|
|
311
504
|
cursor_mode == move_operation::multi_exactkey_value_equal);
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if (
|
|
505
|
+
cursor.scan_from([&](const mdbx::pair& f) {
|
|
506
|
+
keymou key{f.key};
|
|
507
|
+
valuemou val{f.value};
|
|
508
|
+
if (is_key_equal_mode) {
|
|
509
|
+
if (mdbx::is_ordinal(key_mode_)) {
|
|
317
510
|
if (t != key.as_int64()) {
|
|
318
511
|
return true; // останавливаем сканирование
|
|
319
512
|
}
|
|
513
|
+
} else if (from_key != key) {
|
|
514
|
+
return true; // останавливаем сканирование
|
|
320
515
|
}
|
|
516
|
+
}
|
|
321
517
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
val.to_string(env) : val.to_buffer(env);
|
|
328
|
-
// Формируем результат
|
|
329
|
-
Napi::Value result = fn.Call({ rc_key, rc_val,
|
|
330
|
-
Napi::Number::New(env, static_cast<double>(index)) });
|
|
331
|
-
|
|
332
|
-
index++;
|
|
333
|
-
|
|
334
|
-
// true will stop the scan, false will continue
|
|
335
|
-
return result.IsBoolean() ? result.ToBoolean() : false;
|
|
336
|
-
}, from_key, cursor_mode, turn_mode);
|
|
337
|
-
} else {
|
|
338
|
-
cursor.scan_from([&](const mdbx::pair& f) {
|
|
339
|
-
keymou key{f.key};
|
|
340
|
-
valuemou val{f.value};
|
|
341
|
-
if (is_key_equal_mode) {
|
|
342
|
-
if (from_key != key) {
|
|
343
|
-
return true; // останавливаем сканирование
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Конвертируем ключ
|
|
348
|
-
Napi::Value rc_key = (key_flag_.val & base_flag::string) ?
|
|
349
|
-
key.to_string(env) : key.to_buffer(env);
|
|
350
|
-
|
|
351
|
-
// Конвертируем значение
|
|
352
|
-
Napi::Value rc_val = (value_flag_.val & base_flag::string) ?
|
|
353
|
-
val.to_string(env) : val.to_buffer(env);
|
|
354
|
-
// Формируем результат
|
|
355
|
-
Napi::Value result = fn.Call({ rc_key, rc_val,
|
|
356
|
-
Napi::Number::New(env, static_cast<double>(index)) });
|
|
518
|
+
Napi::Value result = fn.Call({
|
|
519
|
+
conv.convert_key(env, key),
|
|
520
|
+
conv.convert_value(env, val),
|
|
521
|
+
Napi::Number::New(env, static_cast<double>(index))
|
|
522
|
+
});
|
|
357
523
|
|
|
358
|
-
|
|
524
|
+
index++;
|
|
359
525
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
}
|
|
526
|
+
// true will stop the scan, false will continue
|
|
527
|
+
return result.IsBoolean() ? result.ToBoolean() : false;
|
|
528
|
+
}, from_key, cursor_mode, turn_mode);
|
|
364
529
|
|
|
365
530
|
return Napi::Number::New(env, static_cast<double>(index));
|
|
366
531
|
} catch (const std::exception& e) {
|
|
@@ -375,12 +540,7 @@ Napi::Value dbimou::stat(const Napi::CallbackInfo& info)
|
|
|
375
540
|
if (arg_len < 1) {
|
|
376
541
|
throw Napi::Error::New(env, "stat: txnmou required");
|
|
377
542
|
}
|
|
378
|
-
auto
|
|
379
|
-
// Дополнительная проверка - есть ли у объекта нужный constructor
|
|
380
|
-
if (!arg0.InstanceOf(txnmou::ctor.Value())) {
|
|
381
|
-
throw Napi::TypeError::New(env, "stat: first argument must be MDBX_Txn instance");
|
|
382
|
-
}
|
|
383
|
-
auto txn = Napi::ObjectWrap<txnmou>::Unwrap(arg0);
|
|
543
|
+
auto txn = txnmou::unwrap_checked(env, info[0], "stat");
|
|
384
544
|
|
|
385
545
|
try {
|
|
386
546
|
auto stat = dbi::get_stat(*txn);
|
|
@@ -414,14 +574,10 @@ Napi::Value dbimou::keys(const Napi::CallbackInfo& info)
|
|
|
414
574
|
if (arg_len < 1) {
|
|
415
575
|
throw Napi::Error::New(env, "keys: txnmou required");
|
|
416
576
|
}
|
|
417
|
-
auto
|
|
418
|
-
// Дополнительная проверка - есть ли у объекта нужный constructor
|
|
419
|
-
if (!arg0.InstanceOf(txnmou::ctor.Value())) {
|
|
420
|
-
throw Napi::TypeError::New(env, "keys: first argument must be MDBX_Txn instance");
|
|
421
|
-
}
|
|
422
|
-
auto txn = Napi::ObjectWrap<txnmou>::Unwrap(arg0);
|
|
577
|
+
auto txn = txnmou::unwrap_checked(env, info[0], "keys");
|
|
423
578
|
|
|
424
579
|
try {
|
|
580
|
+
auto conv = get_convmou();
|
|
425
581
|
auto stat = get_stat(*txn);
|
|
426
582
|
|
|
427
583
|
// Создаем массив для ключей
|
|
@@ -440,9 +596,6 @@ Napi::Value dbimou::keys(const Napi::CallbackInfo& info)
|
|
|
440
596
|
std::array<mdbx::slice, MDBXMOU_BATCH_LIMIT> pairs;
|
|
441
597
|
|
|
442
598
|
uint32_t index{};
|
|
443
|
-
auto is_ordinal = mdbx::is_ordinal(key_mode_);
|
|
444
|
-
auto is_bigint = key_flag_.val & base_flag::bigint;
|
|
445
|
-
auto is_string = key_flag_.val & base_flag::string;
|
|
446
599
|
|
|
447
600
|
// Первый вызов с MDBX_FIRST
|
|
448
601
|
size_t count = cursor.get_batch(pairs, MDBX_FIRST);
|
|
@@ -451,13 +604,7 @@ Napi::Value dbimou::keys(const Napi::CallbackInfo& info)
|
|
|
451
604
|
// pairs[0] = key1, pairs[1] = value1, pairs[2] = key2, ...
|
|
452
605
|
for (size_t i = 0; i < count; i += 2) {
|
|
453
606
|
keymou key{pairs[i]};
|
|
454
|
-
|
|
455
|
-
if (is_ordinal) {
|
|
456
|
-
rc_key = is_bigint ? key.to_bigint(env) : key.to_number(env);
|
|
457
|
-
} else {
|
|
458
|
-
rc_key = is_string ? key.to_string(env) : key.to_buffer(env);
|
|
459
|
-
}
|
|
460
|
-
keys.Set(index++, rc_key);
|
|
607
|
+
keys.Set(index++, conv.convert_key(env, key));
|
|
461
608
|
}
|
|
462
609
|
|
|
463
610
|
// Следующий batch
|
|
@@ -479,14 +626,10 @@ Napi::Value dbimou::keys_from(const Napi::CallbackInfo& info)
|
|
|
479
626
|
if (arg_len < 2) {
|
|
480
627
|
throw Napi::Error::New(env, "keysFrom: txnmou and 'from' key required");
|
|
481
628
|
}
|
|
482
|
-
auto
|
|
483
|
-
// Дополнительная проверка - есть ли у объекта нужный constructor
|
|
484
|
-
if (!arg0.InstanceOf(txnmou::ctor.Value())) {
|
|
485
|
-
throw Napi::TypeError::New(env, "keysFrom: first argument must be MDBX_Txn instance");
|
|
486
|
-
}
|
|
487
|
-
auto txn = Napi::ObjectWrap<txnmou>::Unwrap(arg0);
|
|
629
|
+
auto txn = txnmou::unwrap_checked(env, info[0], "keysFrom");
|
|
488
630
|
|
|
489
631
|
try {
|
|
632
|
+
auto conv = get_convmou();
|
|
490
633
|
auto cursor = dbi::open_cursor(*txn);
|
|
491
634
|
|
|
492
635
|
// Парсим аргументы: txn, from, limit, cursorMode
|
|
@@ -530,51 +673,28 @@ Napi::Value dbimou::keys_from(const Napi::CallbackInfo& info)
|
|
|
530
673
|
Napi::Array keys = Napi::Array::New(env);
|
|
531
674
|
uint32_t index{};
|
|
532
675
|
bool is_key_equal_mode = (cursor_mode == move_operation::key_equal ||
|
|
533
|
-
|
|
676
|
+
cursor_mode == move_operation::multi_exactkey_value_equal);
|
|
534
677
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
if (
|
|
678
|
+
cursor.scan_from([&](const mdbx::pair& f) {
|
|
679
|
+
if (index >= count) {
|
|
680
|
+
return true; // останавливаем сканирование
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
keymou key{f.key};
|
|
684
|
+
if (is_key_equal_mode) {
|
|
685
|
+
if (mdbx::is_ordinal(key_mode_)) {
|
|
543
686
|
if (t != key.as_int64()) {
|
|
544
687
|
return true; // останавливаем сканирование
|
|
545
688
|
}
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// Конвертируем ключ
|
|
549
|
-
Napi::Value rc_key = (key_flag_.val & base_flag::bigint) ?
|
|
550
|
-
key.to_bigint(env) : key.to_number(env);
|
|
551
|
-
|
|
552
|
-
keys.Set(index++, rc_key);
|
|
553
|
-
|
|
554
|
-
return false; // продолжаем сканирование
|
|
555
|
-
}, from_key, cursor_mode, turn_mode);
|
|
556
|
-
} else {
|
|
557
|
-
cursor.scan_from([&](const mdbx::pair& f) {
|
|
558
|
-
if (index >= count) {
|
|
689
|
+
} else if (from_key != key) {
|
|
559
690
|
return true; // останавливаем сканирование
|
|
560
691
|
}
|
|
692
|
+
}
|
|
561
693
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
// Конвертируем ключ
|
|
570
|
-
Napi::Value rc_key = (key_flag_.val & base_flag::string) ?
|
|
571
|
-
key.to_string(env) : key.to_buffer(env);
|
|
572
|
-
|
|
573
|
-
keys.Set(index++, rc_key);
|
|
574
|
-
|
|
575
|
-
return false; // продолжаем сканирование
|
|
576
|
-
}, from_key, cursor_mode, turn_mode);
|
|
577
|
-
}
|
|
694
|
+
keys.Set(index++, conv.convert_key(env, key));
|
|
695
|
+
|
|
696
|
+
return false; // продолжаем сканирование
|
|
697
|
+
}, from_key, cursor_mode, turn_mode);
|
|
578
698
|
|
|
579
699
|
return keys;
|
|
580
700
|
} catch (const std::exception& e) {
|
|
@@ -584,17 +704,28 @@ Napi::Value dbimou::keys_from(const Napi::CallbackInfo& info)
|
|
|
584
704
|
return env.Undefined();
|
|
585
705
|
}
|
|
586
706
|
|
|
707
|
+
Napi::Value dbimou::get_range(const Napi::CallbackInfo& info)
|
|
708
|
+
{
|
|
709
|
+
return run_range_query(info, *this, "getRange", range_output::items);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
Napi::Value dbimou::keys_range(const Napi::CallbackInfo& info)
|
|
713
|
+
{
|
|
714
|
+
return run_range_query(info, *this, "keysRange", range_output::keys);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
Napi::Value dbimou::values_range(const Napi::CallbackInfo& info)
|
|
718
|
+
{
|
|
719
|
+
return run_range_query(info, *this, "valuesRange", range_output::values);
|
|
720
|
+
}
|
|
721
|
+
|
|
587
722
|
Napi::Value dbimou::drop(const Napi::CallbackInfo& info)
|
|
588
723
|
{
|
|
589
724
|
Napi::Env env = info.Env();
|
|
590
725
|
if (info.Length() < 1) {
|
|
591
726
|
throw Napi::TypeError::New(env, "First argument must be a transaction");
|
|
592
727
|
}
|
|
593
|
-
auto
|
|
594
|
-
if (!arg0.InstanceOf(txnmou::ctor.Value())) {
|
|
595
|
-
throw Napi::TypeError::New(env, "First argument must be a txnmou instance");
|
|
596
|
-
}
|
|
597
|
-
auto txn = Napi::ObjectWrap<txnmou>::Unwrap(arg0);
|
|
728
|
+
auto txn = txnmou::unwrap_checked(env, info[0], "drop");
|
|
598
729
|
bool delete_db = false;
|
|
599
730
|
if (info.Length() > 1 && info[1].IsBoolean()) {
|
|
600
731
|
delete_db = info[1].As<Napi::Boolean>().Value();
|
|
@@ -607,4 +738,4 @@ Napi::Value dbimou::drop(const Napi::CallbackInfo& info)
|
|
|
607
738
|
return env.Undefined();
|
|
608
739
|
}
|
|
609
740
|
|
|
610
|
-
} // namespace mdbxmou
|
|
741
|
+
} // namespace mdbxmou
|