mdbxmou 0.1.26

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.
Files changed (220) hide show
  1. package/.github/workflows/ci.yml +32 -0
  2. package/.github/workflows/publish.yml +27 -0
  3. package/.gitmodules +3 -0
  4. package/CMakeLists.txt +53 -0
  5. package/LICENSE +201 -0
  6. package/README.md +639 -0
  7. package/build.js +11 -0
  8. package/deps/libmdbx/.clang-format +3 -0
  9. package/deps/libmdbx/.cmake-format.yaml +3 -0
  10. package/deps/libmdbx/.le.ini +40 -0
  11. package/deps/libmdbx/CMakeLists.txt +1269 -0
  12. package/deps/libmdbx/COPYRIGHT +159 -0
  13. package/deps/libmdbx/ChangeLog.md +2786 -0
  14. package/deps/libmdbx/GNUmakefile +950 -0
  15. package/deps/libmdbx/LICENSE +177 -0
  16. package/deps/libmdbx/Makefile +16 -0
  17. package/deps/libmdbx/NOTICE +39 -0
  18. package/deps/libmdbx/README.md +863 -0
  19. package/deps/libmdbx/TODO.md +43 -0
  20. package/deps/libmdbx/cmake/compiler.cmake +1221 -0
  21. package/deps/libmdbx/cmake/profile.cmake +58 -0
  22. package/deps/libmdbx/cmake/utils.cmake +524 -0
  23. package/deps/libmdbx/conanfile.py +323 -0
  24. package/deps/libmdbx/docs/Doxyfile.in +2734 -0
  25. package/deps/libmdbx/docs/_preface.md +47 -0
  26. package/deps/libmdbx/docs/_restrictions.md +248 -0
  27. package/deps/libmdbx/docs/_starting.md +245 -0
  28. package/deps/libmdbx/docs/_toc.md +34 -0
  29. package/deps/libmdbx/docs/header.html +96 -0
  30. package/deps/libmdbx/example/CMakeLists.txt +6 -0
  31. package/deps/libmdbx/example/README.md +1 -0
  32. package/deps/libmdbx/example/example-mdbx.c +154 -0
  33. package/deps/libmdbx/example/sample-bdb.txt +77 -0
  34. package/deps/libmdbx/mdbx.h +6655 -0
  35. package/deps/libmdbx/mdbx.h++ +6428 -0
  36. package/deps/libmdbx/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +173 -0
  37. package/deps/libmdbx/src/alloy.c +54 -0
  38. package/deps/libmdbx/src/api-cold.c +543 -0
  39. package/deps/libmdbx/src/api-copy.c +912 -0
  40. package/deps/libmdbx/src/api-cursor.c +754 -0
  41. package/deps/libmdbx/src/api-dbi.c +315 -0
  42. package/deps/libmdbx/src/api-env.c +1434 -0
  43. package/deps/libmdbx/src/api-extra.c +165 -0
  44. package/deps/libmdbx/src/api-key-transform.c +197 -0
  45. package/deps/libmdbx/src/api-misc.c +286 -0
  46. package/deps/libmdbx/src/api-opts.c +575 -0
  47. package/deps/libmdbx/src/api-range-estimate.c +365 -0
  48. package/deps/libmdbx/src/api-txn-data.c +454 -0
  49. package/deps/libmdbx/src/api-txn.c +921 -0
  50. package/deps/libmdbx/src/atomics-ops.h +364 -0
  51. package/deps/libmdbx/src/atomics-types.h +97 -0
  52. package/deps/libmdbx/src/audit.c +109 -0
  53. package/deps/libmdbx/src/bits.md +34 -0
  54. package/deps/libmdbx/src/chk.c +1796 -0
  55. package/deps/libmdbx/src/cogs.c +309 -0
  56. package/deps/libmdbx/src/cogs.h +506 -0
  57. package/deps/libmdbx/src/coherency.c +170 -0
  58. package/deps/libmdbx/src/config.h.in +88 -0
  59. package/deps/libmdbx/src/cursor.c +2396 -0
  60. package/deps/libmdbx/src/cursor.h +391 -0
  61. package/deps/libmdbx/src/dbi.c +717 -0
  62. package/deps/libmdbx/src/dbi.h +142 -0
  63. package/deps/libmdbx/src/debug_begin.h +36 -0
  64. package/deps/libmdbx/src/debug_end.h +15 -0
  65. package/deps/libmdbx/src/dpl.c +486 -0
  66. package/deps/libmdbx/src/dpl.h +134 -0
  67. package/deps/libmdbx/src/dxb.c +1335 -0
  68. package/deps/libmdbx/src/env.c +607 -0
  69. package/deps/libmdbx/src/essentials.h +125 -0
  70. package/deps/libmdbx/src/gc-get.c +1345 -0
  71. package/deps/libmdbx/src/gc-put.c +970 -0
  72. package/deps/libmdbx/src/gc.h +40 -0
  73. package/deps/libmdbx/src/global.c +474 -0
  74. package/deps/libmdbx/src/internals.h +585 -0
  75. package/deps/libmdbx/src/layout-dxb.h +288 -0
  76. package/deps/libmdbx/src/layout-lck.h +289 -0
  77. package/deps/libmdbx/src/lck-posix.c +859 -0
  78. package/deps/libmdbx/src/lck-windows.c +607 -0
  79. package/deps/libmdbx/src/lck.c +174 -0
  80. package/deps/libmdbx/src/lck.h +110 -0
  81. package/deps/libmdbx/src/logging_and_debug.c +250 -0
  82. package/deps/libmdbx/src/logging_and_debug.h +159 -0
  83. package/deps/libmdbx/src/man1/mdbx_chk.1 +106 -0
  84. package/deps/libmdbx/src/man1/mdbx_copy.1 +95 -0
  85. package/deps/libmdbx/src/man1/mdbx_drop.1 +48 -0
  86. package/deps/libmdbx/src/man1/mdbx_dump.1 +101 -0
  87. package/deps/libmdbx/src/man1/mdbx_load.1 +105 -0
  88. package/deps/libmdbx/src/man1/mdbx_stat.1 +86 -0
  89. package/deps/libmdbx/src/mdbx.c++ +1837 -0
  90. package/deps/libmdbx/src/meta.c +656 -0
  91. package/deps/libmdbx/src/meta.h +168 -0
  92. package/deps/libmdbx/src/mvcc-readers.c +414 -0
  93. package/deps/libmdbx/src/node.c +365 -0
  94. package/deps/libmdbx/src/node.h +102 -0
  95. package/deps/libmdbx/src/ntdll.def +1246 -0
  96. package/deps/libmdbx/src/options.h +534 -0
  97. package/deps/libmdbx/src/osal.c +3485 -0
  98. package/deps/libmdbx/src/osal.h +587 -0
  99. package/deps/libmdbx/src/page-get.c +483 -0
  100. package/deps/libmdbx/src/page-iov.c +185 -0
  101. package/deps/libmdbx/src/page-iov.h +34 -0
  102. package/deps/libmdbx/src/page-ops.c +744 -0
  103. package/deps/libmdbx/src/page-ops.h +142 -0
  104. package/deps/libmdbx/src/pnl.c +236 -0
  105. package/deps/libmdbx/src/pnl.h +146 -0
  106. package/deps/libmdbx/src/preface.h +990 -0
  107. package/deps/libmdbx/src/proto.h +105 -0
  108. package/deps/libmdbx/src/refund.c +212 -0
  109. package/deps/libmdbx/src/sort.h +484 -0
  110. package/deps/libmdbx/src/spill.c +431 -0
  111. package/deps/libmdbx/src/spill.h +74 -0
  112. package/deps/libmdbx/src/table.c +107 -0
  113. package/deps/libmdbx/src/tls.c +551 -0
  114. package/deps/libmdbx/src/tls.h +43 -0
  115. package/deps/libmdbx/src/tools/chk.c +673 -0
  116. package/deps/libmdbx/src/tools/copy.c +166 -0
  117. package/deps/libmdbx/src/tools/drop.c +199 -0
  118. package/deps/libmdbx/src/tools/dump.c +515 -0
  119. package/deps/libmdbx/src/tools/load.c +831 -0
  120. package/deps/libmdbx/src/tools/stat.c +516 -0
  121. package/deps/libmdbx/src/tools/wingetopt.c +87 -0
  122. package/deps/libmdbx/src/tools/wingetopt.h +30 -0
  123. package/deps/libmdbx/src/tree-ops.c +1554 -0
  124. package/deps/libmdbx/src/tree-search.c +140 -0
  125. package/deps/libmdbx/src/txl.c +99 -0
  126. package/deps/libmdbx/src/txl.h +26 -0
  127. package/deps/libmdbx/src/txn.c +1083 -0
  128. package/deps/libmdbx/src/unaligned.h +205 -0
  129. package/deps/libmdbx/src/utils.c +32 -0
  130. package/deps/libmdbx/src/utils.h +76 -0
  131. package/deps/libmdbx/src/version.c.in +44 -0
  132. package/deps/libmdbx/src/walk.c +290 -0
  133. package/deps/libmdbx/src/walk.h +20 -0
  134. package/deps/libmdbx/src/windows-import.c +152 -0
  135. package/deps/libmdbx/src/windows-import.h +128 -0
  136. package/deps/libmdbx/test/CMakeLists.txt +317 -0
  137. package/deps/libmdbx/test/append.c++ +237 -0
  138. package/deps/libmdbx/test/base.h++ +92 -0
  139. package/deps/libmdbx/test/battery-tmux.sh +64 -0
  140. package/deps/libmdbx/test/cases.c++ +118 -0
  141. package/deps/libmdbx/test/chrono.c++ +134 -0
  142. package/deps/libmdbx/test/chrono.h++ +85 -0
  143. package/deps/libmdbx/test/config.c++ +643 -0
  144. package/deps/libmdbx/test/config.h++ +334 -0
  145. package/deps/libmdbx/test/copy.c++ +62 -0
  146. package/deps/libmdbx/test/dead.c++ +39 -0
  147. package/deps/libmdbx/test/dump-load.sh +40 -0
  148. package/deps/libmdbx/test/extra/crunched_delete.c++ +409 -0
  149. package/deps/libmdbx/test/extra/cursor_closing.c++ +410 -0
  150. package/deps/libmdbx/test/extra/dbi.c++ +229 -0
  151. package/deps/libmdbx/test/extra/doubtless_positioning.c++ +253 -0
  152. package/deps/libmdbx/test/extra/dupfix_addodd.c +94 -0
  153. package/deps/libmdbx/test/extra/dupfix_multiple.c++ +311 -0
  154. package/deps/libmdbx/test/extra/early_close_dbi.c++ +137 -0
  155. package/deps/libmdbx/test/extra/hex_base64_base58.c++ +118 -0
  156. package/deps/libmdbx/test/extra/maindb_ordinal.c++ +61 -0
  157. package/deps/libmdbx/test/extra/open.c++ +96 -0
  158. package/deps/libmdbx/test/extra/pcrf/README.md +2 -0
  159. package/deps/libmdbx/test/extra/pcrf/pcrf_test.c +380 -0
  160. package/deps/libmdbx/test/extra/probe.c++ +10 -0
  161. package/deps/libmdbx/test/extra/txn.c++ +407 -0
  162. package/deps/libmdbx/test/extra/upsert_alldups.c +193 -0
  163. package/deps/libmdbx/test/fork.c++ +263 -0
  164. package/deps/libmdbx/test/hill.c++ +447 -0
  165. package/deps/libmdbx/test/jitter.c++ +197 -0
  166. package/deps/libmdbx/test/keygen.c++ +393 -0
  167. package/deps/libmdbx/test/keygen.h++ +130 -0
  168. package/deps/libmdbx/test/log.c++ +358 -0
  169. package/deps/libmdbx/test/log.h++ +91 -0
  170. package/deps/libmdbx/test/main.c++ +706 -0
  171. package/deps/libmdbx/test/nested.c++ +318 -0
  172. package/deps/libmdbx/test/osal-unix.c++ +647 -0
  173. package/deps/libmdbx/test/osal-windows.c++ +440 -0
  174. package/deps/libmdbx/test/osal.h++ +41 -0
  175. package/deps/libmdbx/test/stochastic.sh +690 -0
  176. package/deps/libmdbx/test/stub/LICENSE +24 -0
  177. package/deps/libmdbx/test/stub/README.md +8 -0
  178. package/deps/libmdbx/test/stub/pthread_barrier.c +104 -0
  179. package/deps/libmdbx/test/stub/pthread_barrier.h +77 -0
  180. package/deps/libmdbx/test/test.c++ +1551 -0
  181. package/deps/libmdbx/test/test.h++ +298 -0
  182. package/deps/libmdbx/test/tmux.conf +3 -0
  183. package/deps/libmdbx/test/try.c++ +30 -0
  184. package/deps/libmdbx/test/ttl.c++ +240 -0
  185. package/deps/libmdbx/test/utils.c++ +203 -0
  186. package/deps/libmdbx/test/utils.h++ +326 -0
  187. package/deps/libmdbx/test/valgrind_suppress.txt +536 -0
  188. package/lib/mdbx_evn_async.js +211 -0
  189. package/lib/mdbx_worker.js +195 -0
  190. package/lib/nativemou.js +6 -0
  191. package/package.json +38 -0
  192. package/src/async/envmou_close.cpp +34 -0
  193. package/src/async/envmou_close.hpp +32 -0
  194. package/src/async/envmou_copy_to.cpp +29 -0
  195. package/src/async/envmou_copy_to.hpp +38 -0
  196. package/src/async/envmou_keys.cpp +201 -0
  197. package/src/async/envmou_keys.hpp +50 -0
  198. package/src/async/envmou_open.cpp +38 -0
  199. package/src/async/envmou_open.hpp +33 -0
  200. package/src/async/envmou_query.cpp +167 -0
  201. package/src/async/envmou_query.hpp +53 -0
  202. package/src/dbimou.cpp +522 -0
  203. package/src/dbimou.hpp +82 -0
  204. package/src/env_arg0.hpp +24 -0
  205. package/src/envmou.cpp +445 -0
  206. package/src/envmou.hpp +116 -0
  207. package/src/modulemou.cpp +113 -0
  208. package/src/querymou.cpp +177 -0
  209. package/src/querymou.hpp +93 -0
  210. package/src/txnmou.cpp +254 -0
  211. package/src/txnmou.hpp +122 -0
  212. package/src/typemou.hpp +239 -0
  213. package/src/valuemou.hpp +194 -0
  214. package/test/async.js +67 -0
  215. package/test/e3.js +38 -0
  216. package/test/e4.js +89 -0
  217. package/test/e5.js +162 -0
  218. package/test/test-batch-ops.js +243 -0
  219. package/test/test-cursor-mode.js +84 -0
  220. package/test/test-multi-mode.js +87 -0
package/src/dbimou.cpp ADDED
@@ -0,0 +1,522 @@
1
+ #include "dbimou.hpp"
2
+ #include "envmou.hpp"
3
+ #include "txnmou.hpp"
4
+ #include "typemou.hpp"
5
+
6
+ namespace mdbxmou {
7
+
8
+ Napi::FunctionReference dbimou::ctor{};
9
+
10
+ void dbimou::init(const char *class_name, Napi::Env env)
11
+ {
12
+ auto func = DefineClass(env, class_name, {
13
+ InstanceMethod("put", &dbimou::put),
14
+ InstanceMethod("get", &dbimou::get),
15
+ InstanceMethod("del", &dbimou::del),
16
+ InstanceMethod("has", &dbimou::has),
17
+ InstanceMethod("forEach", &dbimou::for_each),
18
+ InstanceMethod("stat", &dbimou::stat),
19
+ InstanceMethod("keys", &dbimou::keys),
20
+ InstanceMethod("keysFrom", &dbimou::keys_from),
21
+ });
22
+
23
+ ctor = Napi::Persistent(func);
24
+ ctor.SuppressDestruct();
25
+ }
26
+
27
+ Napi::Value dbimou::put(const Napi::CallbackInfo& info) {
28
+ Napi::Env env = info.Env();
29
+
30
+ auto arg_len = info.Length();
31
+ if (arg_len < 2) {
32
+ throw Napi::Error::New(env, "put: key and value required");
33
+ }
34
+
35
+ try {
36
+ auto key = (key_mode_.val & key_mode::ordinal) ?
37
+ keymou::from(info[0], env, id_buf_) :
38
+ keymou::from(info[0], env, key_buf_);
39
+ auto val = valuemou::from(info[1], env, val_buf_);
40
+ auto flag = static_cast<MDBX_put_flags_t>(key_mode_.val & value_mode_.val);
41
+ auto rc = mdbx_put(*txn_, dbi_, key, val, flag);
42
+ if (rc != MDBX_SUCCESS) {
43
+ throw Napi::Error::New(env, mdbx_strerror(rc));
44
+ }
45
+ } catch (const std::exception& e) {
46
+ throw Napi::Error::New(env, std::string("put: ") + e.what());
47
+ }
48
+
49
+ return env.Undefined();
50
+ }
51
+
52
+ Napi::Value dbimou::get(const Napi::CallbackInfo& info) {
53
+ Napi::Env env = info.Env();
54
+
55
+ if (info.Length() < 1) {
56
+ throw Napi::Error::New(env, "get: key required");
57
+ }
58
+
59
+ try {
60
+ valuemou val{};
61
+ auto key = (key_mode_.val & key_mode::ordinal) ?
62
+ keymou::from(info[0], env, id_buf_) :
63
+ keymou::from(info[0], env, key_buf_);
64
+ auto rc = mdbx_get(*txn_, dbi_, key, val);
65
+ if (rc == MDBX_NOTFOUND)
66
+ return env.Undefined();
67
+ if (rc != MDBX_SUCCESS) {
68
+ throw Napi::Error::New(env, mdbx_strerror(rc));
69
+ }
70
+ return (value_flag_.val & base_flag::string) ?
71
+ val.to_string(env) : val.to_buffer(env);
72
+ } catch (const std::exception& e) {
73
+ throw Napi::Error::New(env, std::string("get: ") + e.what());
74
+ }
75
+
76
+ return env.Undefined();
77
+ }
78
+
79
+ Napi::Value dbimou::del(const Napi::CallbackInfo& info) {
80
+ Napi::Env env = info.Env();
81
+
82
+ if (info.Length() < 1) {
83
+ throw Napi::Error::New(env, "del: key required");
84
+ }
85
+
86
+ try {
87
+ auto key = (key_mode_.val & key_mode::ordinal) ?
88
+ keymou::from(info[0], env, id_buf_) :
89
+ keymou::from(info[0], env, key_buf_);
90
+ auto rc = mdbx_del(*txn_, dbi_, key, nullptr);
91
+ if (rc == MDBX_NOTFOUND) {
92
+ return Napi::Value::From(env, false);
93
+ }
94
+ if (rc != MDBX_SUCCESS) {
95
+ throw Napi::Error::New(env, mdbx_strerror(rc));
96
+ }
97
+ return Napi::Value::From(env, true);
98
+ } catch (const std::exception& e) {
99
+ throw Napi::Error::New(env, std::string("del: ") + e.what());
100
+ }
101
+
102
+ return env.Undefined();
103
+ }
104
+
105
+ Napi::Value dbimou::has(const Napi::CallbackInfo& info) {
106
+ Napi::Env env = info.Env();
107
+
108
+ if (info.Length() < 1) {
109
+ throw Napi::Error::New(env, "Key is required");
110
+ }
111
+
112
+ try {
113
+ auto key = (key_mode_.val & key_mode::ordinal) ?
114
+ keymou::from(info[0], env, id_buf_) :
115
+ keymou::from(info[0], env, key_buf_);
116
+ auto rc = mdbx_get(*txn_, dbi_, key, nullptr);
117
+ if (rc == MDBX_NOTFOUND) {
118
+ return Napi::Value::From(env, false);
119
+ }
120
+ if (rc != MDBX_SUCCESS) {
121
+ throw Napi::Error::New(env, mdbx_strerror(rc));
122
+ }
123
+ return Napi::Value::From(env, true);
124
+ } catch (const std::exception& e) {
125
+ throw Napi::Error::New(env, std::string("has: ") + e.what());
126
+ }
127
+
128
+ return env.Undefined();
129
+ }
130
+
131
+ Napi::Value dbimou::for_each(const Napi::CallbackInfo& info) {
132
+ Napi::Env env = info.Env();
133
+
134
+ if (info.Length() < 1) {
135
+ throw Napi::TypeError::New(env, "Expected at least one argument");
136
+ }
137
+
138
+ // Проверяем тип вызова: forEach(fn), forEach(fromKey, fn) или forEach(fromKey, cursorMode, fn)
139
+ if (info.Length() == 1 && info[0].IsFunction()) {
140
+ // Обычный forEach(fn)
141
+ auto fn = info[0].As<Napi::Function>();
142
+
143
+ MDBX_cursor* cursor_ptr;
144
+ auto rc = mdbx_cursor_open(*txn_, dbi_, &cursor_ptr);
145
+ if (rc != MDBX_SUCCESS) {
146
+ throw Napi::Error::New(env, mdbx_strerror(rc));
147
+ }
148
+
149
+ std::size_t index{};
150
+
151
+ try {
152
+ cursormou_managed cursor{ cursor_ptr };
153
+ if (key_mode_.val & key_mode::ordinal) {
154
+ cursor.scan([&](const mdbx::pair& f) {
155
+ keymou key{f.key};
156
+ valuemou val{f.value};
157
+ // Конвертируем ключ
158
+ Napi::Value rc_key = (key_flag_.val & base_flag::bigint) ?
159
+ key.to_bigint(env) : key.to_number(env);
160
+ // Конвертируем значение
161
+ Napi::Value rc_val = (value_flag_.val & base_flag::string) ?
162
+ val.to_string(env) : val.to_buffer(env);
163
+
164
+ Napi::Value result = fn.Call({ rc_key, rc_val,
165
+ Napi::Number::New(env, index) });
166
+
167
+ index++;
168
+
169
+ // true will stop the scan, false will continue
170
+ return result.IsBoolean() ? result.ToBoolean() : false;
171
+ });
172
+ } else {
173
+ cursor.scan([&](const mdbx::pair& f) {
174
+ keymou key{f.key};
175
+ valuemou val{f.value};
176
+ // Конвертируем ключ
177
+ Napi::Value rc_key = (key_flag_.val & base_flag::string) ?
178
+ key.to_string(env) : key.to_buffer(env);
179
+
180
+ // Конвертируем значение
181
+ Napi::Value rc_val = (value_flag_.val & base_flag::string) ?
182
+ val.to_string(env) : val.to_buffer(env);
183
+
184
+ Napi::Value result = fn.Call({ rc_key, rc_val,
185
+ Napi::Number::New(env, index) });
186
+
187
+ index++;
188
+
189
+ // true will stop the scan, false will continue
190
+ return result.IsBoolean() ? result.ToBoolean() : false;
191
+ });
192
+ }
193
+ } catch (const std::exception& e) {
194
+ throw Napi::Error::New(env, std::string("forEach: ") + e.what());
195
+ }
196
+
197
+ return Napi::Number::New(env, index);
198
+
199
+ } else if ((info.Length() == 2 && info[1].IsFunction()) ||
200
+ (info.Length() == 3 && info[2].IsFunction())) {
201
+ // forEach(fromKey, fn) или forEach(fromKey, cursorMode, fn) - делегируем внутреннему методу
202
+ return for_each_from(info);
203
+
204
+ } else {
205
+ throw Napi::TypeError::New(env, "Expected function, (key, function) or (key, cursorMode, function)");
206
+ }
207
+ }
208
+
209
+ Napi::Value dbimou::for_each_from(const Napi::CallbackInfo& info) {
210
+ Napi::Env env = info.Env();
211
+
212
+ // Определяем позицию функции: info[1] или info[2]
213
+ Napi::Function fn;
214
+ if (info.Length() == 2 && info[1].IsFunction()) {
215
+ fn = info[1].As<Napi::Function>();
216
+ } else if (info.Length() == 3 && info[2].IsFunction()) {
217
+ fn = info[2].As<Napi::Function>();
218
+ } else {
219
+ throw Napi::TypeError::New(env, "Function argument required");
220
+ }
221
+
222
+ MDBX_cursor* cursor_ptr;
223
+ auto rc = mdbx_cursor_open(*txn_, dbi_, &cursor_ptr);
224
+ if (rc != MDBX_SUCCESS) {
225
+ throw Napi::Error::New(env, mdbx_strerror(rc));
226
+ }
227
+
228
+ try {
229
+ cursormou_managed cursor{ cursor_ptr };
230
+
231
+ // Парсим начальный ключ
232
+ keymou from_key = mdbx::is_ordinal(key_mode_) ?
233
+ keymou::from(info[0], env, id_buf_) :
234
+ keymou::from(info[0], env, key_buf_);
235
+
236
+ // Парсим cursor mode (если передан)
237
+ using move_operation = mdbx::cursor::move_operation;
238
+ auto cursor_mode = move_operation::key_greater_or_equal;
239
+ auto turn_mode = move_operation::next;
240
+
241
+ if (info.Length() == 3 && !info[1].IsUndefined()) {
242
+ cursor_mode = parse_cursor_mode(info[1]);
243
+
244
+ // Определяем направление сканирования на основе операции
245
+ switch (cursor_mode) {
246
+ case move_operation::key_lesser_than:
247
+ case move_operation::key_lesser_or_equal:
248
+ case move_operation::multi_exactkey_value_lesser_than:
249
+ case move_operation::multi_exactkey_value_lesser_or_equal:
250
+ turn_mode = move_operation::previous;
251
+ break;
252
+ case move_operation::key_equal:
253
+ case move_operation::multi_exactkey_value_equal:
254
+ // Для точного совпадения останавливаемся на первом найденном элементе
255
+ turn_mode = move_operation::next;
256
+ break;
257
+ default:
258
+ turn_mode = move_operation::next;
259
+ break;
260
+ }
261
+ }
262
+
263
+ std::size_t index{};
264
+ bool is_key_equal_mode = (cursor_mode == move_operation::key_equal ||
265
+ cursor_mode == move_operation::multi_exactkey_value_equal);
266
+ if (key_mode_.val & key_mode::ordinal) {
267
+ cursor.scan_from([&](const mdbx::pair& f) {
268
+ keymou key{f.key};
269
+ valuemou val{f.value};
270
+ if (is_key_equal_mode) {
271
+ if (id_buf_ != key.as_int64()) {
272
+ return true; // останавливаем сканирование
273
+ }
274
+ }
275
+
276
+ // Конвертируем ключ
277
+ Napi::Value rc_key = (key_flag_.val & base_flag::bigint) ?
278
+ key.to_bigint(env) : key.to_number(env);
279
+ // Конвертируем значение
280
+ Napi::Value rc_val = (value_flag_.val & base_flag::string) ?
281
+ val.to_string(env) : val.to_buffer(env);
282
+
283
+ Napi::Value result = fn.Call({ rc_key, rc_val,
284
+ Napi::Number::New(env, index) });
285
+
286
+ index++;
287
+
288
+ // true will stop the scan, false will continue
289
+ return result.IsBoolean() ? result.ToBoolean() : false;
290
+ }, from_key, cursor_mode, turn_mode);
291
+ } else {
292
+ cursor.scan_from([&](const mdbx::pair& f) {
293
+ keymou key{f.key};
294
+ valuemou val{f.value};
295
+ if (is_key_equal_mode) {
296
+ if (from_key != key) {
297
+ return true; // останавливаем сканирование
298
+ }
299
+ }
300
+
301
+ // Конвертируем ключ
302
+ Napi::Value rc_key = (key_flag_.val & base_flag::string) ?
303
+ key.to_string(env) : key.to_buffer(env);
304
+
305
+ // Конвертируем значение
306
+ Napi::Value rc_val = (value_flag_.val & base_flag::string) ?
307
+ val.to_string(env) : val.to_buffer(env);
308
+
309
+ Napi::Value result = fn.Call({ rc_key, rc_val,
310
+ Napi::Number::New(env, index) });
311
+
312
+ index++;
313
+
314
+ // true will stop the scan, false will continue
315
+ return result.IsBoolean() ? result.ToBoolean() : false;
316
+ }, from_key, cursor_mode, turn_mode);
317
+ }
318
+
319
+ return Napi::Number::New(env, index);
320
+ } catch (const std::exception& e) {
321
+ throw Napi::Error::New(env, std::string("forEach: ") + e.what());
322
+ }
323
+ }
324
+
325
+ Napi::Value dbimou::stat(const Napi::CallbackInfo& info) {
326
+ Napi::Env env = info.Env();
327
+
328
+ try {
329
+ auto stat = get_stat(*txn_, dbi_);
330
+
331
+ Napi::Object result = Napi::Object::New(env);
332
+
333
+ result.Set("pageSize", Napi::Number::New(env, stat.ms_psize));
334
+ result.Set("depth", Napi::Number::New(env, stat.ms_depth));
335
+ result.Set("branchPages", Napi::Number::New(env,
336
+ static_cast<double>(stat.ms_branch_pages)));
337
+ result.Set("leafPages", Napi::Number::New(env,
338
+ static_cast<double>(stat.ms_leaf_pages)));
339
+ result.Set("overflowPages", Napi::Number::New(env,
340
+ static_cast<double>(stat.ms_overflow_pages)));
341
+ result.Set("entries", Napi::Number::New(env,
342
+ static_cast<double>(stat.ms_entries)));
343
+ result.Set("modTxnId", Napi::Number::New(env,
344
+ static_cast<double>(stat.ms_mod_txnid)));
345
+ return result;
346
+ } catch (const std::exception& e) {
347
+ throw Napi::Error::New(env, std::string("stat: ") + e.what());
348
+ }
349
+
350
+ return env.Undefined();
351
+ }
352
+
353
+ Napi::Value dbimou::keys(const Napi::CallbackInfo& info) {
354
+ Napi::Env env = info.Env();
355
+
356
+ MDBX_cursor* cursor_ptr;
357
+ auto rc = mdbx_cursor_open(*txn_, dbi_, &cursor_ptr);
358
+ if (rc != MDBX_SUCCESS) {
359
+ throw Napi::Error::New(env, mdbx_strerror(rc));
360
+ }
361
+
362
+ try {
363
+ cursormou_managed cursor{ cursor_ptr };
364
+ auto stat = get_stat(*txn_, dbi_);
365
+
366
+ // Создаем массив для ключей
367
+ Napi::Array keys = Napi::Array::New(env, stat.ms_entries);
368
+ if (stat.ms_entries == 0) {
369
+ return keys;
370
+ }
371
+
372
+ std::size_t index{};
373
+ if (key_mode_.val & key_mode::ordinal) {
374
+ cursor.scan([&](const mdbx::pair& f) {
375
+ keymou key{f.key};
376
+ // Конвертируем ключ
377
+ Napi::Value rc_key = (key_flag_.val & base_flag::bigint) ?
378
+ key.to_bigint(env) : key.to_number(env);
379
+
380
+ keys.Set(index++, rc_key);
381
+ return false; // продолжаем сканирование
382
+ });
383
+ } else {
384
+ cursor.scan([&](const mdbx::pair& f) {
385
+ keymou key{f.key};
386
+ // Конвертируем ключ
387
+ Napi::Value rc_key = (key_flag_.val & base_flag::string) ?
388
+ key.to_string(env) : key.to_buffer(env);
389
+
390
+ keys.Set(index++, rc_key);
391
+ return false; // продолжаем сканирование
392
+ });
393
+ }
394
+
395
+ return keys;
396
+ } catch (const std::exception& e) {
397
+ throw Napi::Error::New(env, std::string("keys: ") + e.what());
398
+ }
399
+
400
+ return env.Undefined();
401
+ }
402
+
403
+ Napi::Value dbimou::keys_from(const Napi::CallbackInfo& info) {
404
+ Napi::Env env = info.Env();
405
+
406
+ if (info.Length() < 1) {
407
+ throw Napi::Error::New(env, "keysFrom: 'from' key required");
408
+ }
409
+
410
+ MDBX_cursor* cursor_ptr;
411
+ auto rc = mdbx_cursor_open(*txn_, dbi_, &cursor_ptr);
412
+ if (rc != MDBX_SUCCESS) {
413
+ throw Napi::Error::New(env, mdbx_strerror(rc));
414
+ }
415
+
416
+ try {
417
+ cursormou_managed cursor{ cursor_ptr };
418
+
419
+ // Парсим аргументы: from, limit, cursorMode
420
+ keymou from_key = mdbx::is_ordinal(key_mode_) ?
421
+ keymou::from(info[0], env, id_buf_) :
422
+ keymou::from(info[0], env, key_buf_);
423
+
424
+ std::size_t count = SIZE_MAX;
425
+ if (info.Length() > 1 && !info[1].IsUndefined()) {
426
+ count = info[1].As<Napi::Number>().Uint32Value();
427
+ }
428
+
429
+ using move_operation = mdbx::cursor::move_operation;
430
+ auto cursor_mode = move_operation::key_greater_or_equal;
431
+ auto turn_mode = move_operation::next;
432
+
433
+ if (info.Length() > 2 && !info[2].IsUndefined()) {
434
+ cursor_mode = parse_cursor_mode(info[2]);
435
+
436
+ // Определяем направление сканирования на основе операции
437
+ switch (cursor_mode) {
438
+ case move_operation::key_lesser_than:
439
+ case move_operation::key_lesser_or_equal:
440
+ case move_operation::multi_exactkey_value_lesser_than:
441
+ case move_operation::multi_exactkey_value_lesser_or_equal:
442
+ turn_mode = move_operation::previous;
443
+ break;
444
+ case move_operation::key_equal:
445
+ case move_operation::multi_exactkey_value_equal:
446
+ // Для точного совпадения останавливаемся на первом найденном элементе
447
+ turn_mode = move_operation::next;
448
+ break;
449
+ default:
450
+ turn_mode = move_operation::next;
451
+ break;
452
+ }
453
+ }
454
+
455
+ // Создаем массив для ключей
456
+ Napi::Array keys = Napi::Array::New(env);
457
+ std::size_t index{};
458
+ bool is_key_equal_mode = (cursor_mode == move_operation::key_equal ||
459
+ cursor_mode == move_operation::multi_exactkey_value_equal);
460
+
461
+ if (key_mode_.val & key_mode::ordinal) {
462
+ cursor.scan_from([&](const mdbx::pair& f) {
463
+ if (index >= count) {
464
+ return true; // останавливаем сканирование
465
+ }
466
+
467
+ keymou key{f.key};
468
+ if (is_key_equal_mode) {
469
+ if (id_buf_ != key.as_int64()) {
470
+ return true; // останавливаем сканирование
471
+ }
472
+ }
473
+
474
+ // Конвертируем ключ
475
+ Napi::Value rc_key = (key_flag_.val & base_flag::bigint) ?
476
+ key.to_bigint(env) : key.to_number(env);
477
+
478
+ keys.Set(index++, rc_key);
479
+
480
+ return false; // продолжаем сканирование
481
+ }, from_key, cursor_mode, turn_mode);
482
+ } else {
483
+ cursor.scan_from([&](const mdbx::pair& f) {
484
+ if (index >= count) {
485
+ return true; // останавливаем сканирование
486
+ }
487
+
488
+ keymou key{f.key};
489
+ if (is_key_equal_mode) {
490
+ if (from_key != key) {
491
+ return true; // останавливаем сканирование
492
+ }
493
+ }
494
+
495
+ // Конвертируем ключ
496
+ Napi::Value rc_key = (key_flag_.val & base_flag::string) ?
497
+ key.to_string(env) : key.to_buffer(env);
498
+
499
+ keys.Set(index++, rc_key);
500
+
501
+ return false; // продолжаем сканирование
502
+ }, from_key, cursor_mode, turn_mode);
503
+ }
504
+
505
+ return keys;
506
+ } catch (const std::exception& e) {
507
+ throw Napi::Error::New(env, std::string("keysFrom: ") + e.what());
508
+ }
509
+
510
+ return env.Undefined();
511
+ }
512
+
513
+ const env_arg0* dbimou::get_env_userctx(MDBX_env* e)
514
+ {
515
+ assert(e);
516
+ auto rc = static_cast<env_arg0*>(mdbx_env_get_userctx(e));
517
+ if (!rc)
518
+ throw std::runtime_error("env: userctx not set");
519
+ return rc;
520
+ }
521
+
522
+ } // namespace mdbxmou
package/src/dbimou.hpp ADDED
@@ -0,0 +1,82 @@
1
+ #pragma once
2
+
3
+ #include "valuemou.hpp"
4
+ #include "querymou.hpp"
5
+ #include "env_arg0.hpp"
6
+ #include <memory>
7
+
8
+ namespace mdbxmou {
9
+
10
+ class envmou;
11
+ class txnmou;
12
+ struct env_arg0;
13
+
14
+ class dbimou final
15
+ : public Napi::ObjectWrap<dbimou>
16
+ {
17
+ // мы должны отслеживать время жизни evn
18
+ envmou* env_{nullptr};
19
+ txnmou* txn_{nullptr};
20
+ MDBX_dbi dbi_{};
21
+ db_mode mode_{};
22
+ key_mode key_mode_{};
23
+ value_mode value_mode_{};
24
+ base_flag key_flag_{};
25
+ base_flag value_flag_{};
26
+ buffer_type key_buf_{};
27
+ buffer_type val_buf_{};
28
+ std::uint64_t id_buf_{};
29
+
30
+ public:
31
+ static inline MDBX_stat get_stat(MDBX_txn* txn, MDBX_dbi dbi)
32
+ {
33
+ MDBX_stat stat;
34
+ auto rc = mdbx_dbi_stat(txn, dbi, &stat, sizeof(stat));
35
+ if (rc != MDBX_SUCCESS) {
36
+ throw std::runtime_error(mdbx_strerror(rc));
37
+ }
38
+ return stat;
39
+ }
40
+
41
+ static Napi::FunctionReference ctor;
42
+
43
+ dbimou(const Napi::CallbackInfo& info)
44
+ : Napi::ObjectWrap<dbimou>(info)
45
+ { }
46
+
47
+ static void init(const char *class_name, Napi::Env env);
48
+
49
+ // Основные операции (только синхронные)
50
+ Napi::Value put(const Napi::CallbackInfo&);
51
+ Napi::Value get(const Napi::CallbackInfo&);
52
+ Napi::Value del(const Napi::CallbackInfo&);
53
+ Napi::Value has(const Napi::CallbackInfo&);
54
+ Napi::Value for_each(const Napi::CallbackInfo&);
55
+ Napi::Value stat(const Napi::CallbackInfo&);
56
+ Napi::Value keys(const Napi::CallbackInfo&);
57
+ Napi::Value keys_from(const Napi::CallbackInfo&);
58
+
59
+ private:
60
+ // Внутренний метод для forEach с начальным ключом
61
+ Napi::Value for_each_from(const Napi::CallbackInfo&);
62
+
63
+ public:
64
+
65
+ void attach(envmou* env, txnmou* txn, MDBX_dbi dbi,
66
+ db_mode mode, key_mode key_mode, value_mode value_mode,
67
+ base_flag key_flag, base_flag value_flag)
68
+ {
69
+ env_ = env;
70
+ txn_ = txn;
71
+ dbi_ = dbi;
72
+ mode_ = mode;
73
+ key_mode_ = key_mode;
74
+ value_mode_ = value_mode;
75
+ key_flag_ = key_flag;
76
+ value_flag_ = value_flag;
77
+ }
78
+
79
+ static const env_arg0* get_env_userctx(MDBX_env* env_ptr);
80
+ };
81
+
82
+ } // namespace mdbxmou
@@ -0,0 +1,24 @@
1
+ #pragma once
2
+
3
+ #include "valuemou.hpp"
4
+ // #include <sys/syscall.h>
5
+ // #include <unistd.h>
6
+
7
+ namespace mdbxmou {
8
+
9
+ struct env_arg0 {
10
+ std::string path;
11
+ MDBX_dbi max_dbi{32};
12
+ mdbx::env::geometry geom{};
13
+ env_flag flag{};
14
+ mode_t file_mode{0664};
15
+ std::uint32_t max_readers{128};
16
+ base_flag key_flag{};
17
+ base_flag value_flag{};
18
+ };
19
+
20
+ // static inline pid_t gettid() {
21
+ // return static_cast<pid_t>(syscall(SYS_gettid));
22
+ // }
23
+
24
+ } // namespace mdbxmou