jsql-neo 6.3.3 → 6.3.5

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.
@@ -5,27 +5,110 @@ use jsql_neo_core::types::{FieldSchema, TableDefinition, schema_order_preserving
5
5
  use napi_derive::napi;
6
6
  use napi::JsBuffer;
7
7
 
8
+ /// 每个 JS `Database` 实例对应一个独立引擎句柄。
9
+ ///
10
+ /// 历史问题(≤6.3.3):整个进程只有一个 `thread_local! ENGINE`,
11
+ /// 于是 `new Database(dirA)` 之后再 `new Database(dirB)` 会把 dirA 的表
12
+ /// 全部 `clear()` 掉(见 `HybridEngine::open`),同进程无法并存两个库;
13
+ /// 且在引擎回调里重入调用会直接返回 "engine busy (reentrant call)"。
14
+ /// 对一个自称「嵌入式数据库」的库,这是硬伤。
15
+ ///
16
+ /// 现在改为「句柄注册表」:句柄 0 是为向后兼容保留的默认实例,
17
+ /// 新实例从 1 开始分配,各自持有独立的 HybridEngine,互不影响。
8
18
  thread_local! {
9
- static ENGINE: RefCell<HybridEngine> = RefCell::new(HybridEngine::new());
19
+ static ENGINES: RefCell<HashMap<u32, RefCell<HybridEngine>>> =
20
+ RefCell::new(HashMap::new());
21
+ static NEXT_HANDLE: RefCell<u32> = const { RefCell::new(1) };
22
+ }
23
+
24
+ /// 保留的默认句柄,维持既有 `jsql_*` 无句柄 API 的行为。
25
+ const DEFAULT_HANDLE: u32 = 0;
26
+
27
+ /// 确保默认实例存在。
28
+ ///
29
+ /// 旧版是 `thread_local! static ENGINE`,加载即有,因此无句柄 API 一直可用。
30
+ /// 改为注册表后必须显式创建句柄 0,否则 `jsqlOpen(...)` 这类旧调用会报
31
+ /// "no such database instance: 0" —— 那就是破坏性变更。
32
+ fn ensure_default_instance() {
33
+ ENGINES.with(|m| {
34
+ let mut map = m.borrow_mut();
35
+ map.entry(DEFAULT_HANDLE)
36
+ .or_insert_with(|| RefCell::new(HybridEngine::new()));
37
+ });
38
+ }
39
+
40
+ fn no_instance(handle: u32) -> String {
41
+ format!(r#"{{"ok":false,"error":"no such database instance: {}"}}"#, handle)
42
+ }
43
+
44
+ /// 创建一个新的独立引擎实例,返回其句柄。
45
+ #[napi]
46
+ pub fn jsql_instance_new() -> u32 {
47
+ NEXT_HANDLE.with(|h| {
48
+ let mut next = h.borrow_mut();
49
+ let handle = *next;
50
+ *next = next.wrapping_add(1);
51
+ if *next == DEFAULT_HANDLE {
52
+ *next = 1;
53
+ }
54
+ ENGINES.with(|m| {
55
+ m.borrow_mut()
56
+ .insert(handle, RefCell::new(HybridEngine::new()));
57
+ });
58
+ handle
59
+ })
60
+ }
61
+
62
+ /// 关闭并销毁一个实例,释放其占用的内存与文件句柄。
63
+ #[napi]
64
+ pub fn jsql_instance_free(handle: u32) -> String {
65
+ ENGINES.with(|m| {
66
+ let mut map = m.borrow_mut();
67
+ if let Some(cell) = map.remove(&handle) {
68
+ // 尽力刷盘,失败也不阻塞销毁
69
+ let _ = cell.borrow_mut().close();
70
+ r#"{"ok":true}"#.to_string()
71
+ } else {
72
+ no_instance(handle)
73
+ }
74
+ })
75
+ }
76
+
77
+ /// 当前显式创建的实例数(诊断用,不含为向后兼容保留的默认实例 0)。
78
+ #[napi]
79
+ pub fn jsql_instance_count() -> i32 {
80
+ ENGINES.with(|m| {
81
+ m.borrow()
82
+ .keys()
83
+ .filter(|h| **h != DEFAULT_HANDLE)
84
+ .count() as i32
85
+ })
10
86
  }
11
87
 
12
88
  fn with_engine_mut<F>(f: F) -> String
13
89
  where
14
90
  F: FnOnce(&mut HybridEngine) -> String,
15
91
  {
16
- ENGINE.with(|cell| match cell.try_borrow_mut() {
17
- Ok(mut eng) => f(&mut eng),
18
- Err(_) => r#"{"ok":false,"error":"engine busy (reentrant call)"}"#.to_string(),
19
- })
92
+ ensure_default_instance();
93
+ with_engine_handle_mut(DEFAULT_HANDLE, f)
20
94
  }
21
95
 
22
- fn with_engine_ro<F>(f: F) -> String
96
+ fn with_engine_handle_mut<F>(handle: u32, f: F) -> String
23
97
  where
24
- F: FnOnce(&HybridEngine) -> String,
98
+ F: FnOnce(&mut HybridEngine) -> String,
25
99
  {
26
- ENGINE.with(|cell| match cell.try_borrow() {
27
- Ok(eng) => f(&eng),
28
- Err(_) => r#"{"ok":false,"error":"engine busy (reentrant call)"}"#.to_string(),
100
+ ENGINES.with(|m| {
101
+ let map = m.borrow();
102
+ let cell = match map.get(&handle) {
103
+ Some(c) => c,
104
+ None => return no_instance(handle),
105
+ };
106
+ // 先取出结果再返回,确保 RefMut 在 map 之前被 drop
107
+ let out = match cell.try_borrow_mut() {
108
+ Ok(mut eng) => f(&mut eng),
109
+ Err(_) => r#"{"ok":false,"error":"engine busy (reentrant call)"}"#.to_string(),
110
+ };
111
+ out
29
112
  })
30
113
  }
31
114
 
@@ -36,114 +119,135 @@ fn safe_json_result(result: Result<String, String>) -> String {
36
119
  }
37
120
  }
38
121
 
122
+ /// 为每个操作生成「旧版无句柄」+「新版带句柄」两个入口。
123
+ /// 旧版走默认实例以保持向后兼容,新版按句柄路由到各自独立的引擎。
124
+ /// `$eng` 是引擎变量名,在 body 中直接引用。
125
+ macro_rules! napi_engine_fn {
126
+ ($plain:ident, $h:ident, ($($arg:ident : $ty:ty),*) => |$eng:ident| $body:block) => {
127
+ #[napi]
128
+ pub fn $plain($($arg : $ty),*) -> String {
129
+ with_engine_mut(|$eng: &mut HybridEngine| $body)
130
+ }
131
+
132
+ #[napi]
133
+ pub fn $h(handle: u32, $($arg : $ty),*) -> String {
134
+ with_engine_handle_mut(handle, |$eng: &mut HybridEngine| $body)
135
+ }
136
+ };
137
+ }
138
+
39
139
  #[napi]
40
140
  pub fn jsql_open(dir: String, mode: String) -> String {
41
- with_engine_mut(|eng| {
42
- let open_res = eng.open(&dir, &mode);
43
- match open_res {
44
- Ok(()) => {
45
- let names = eng.list_tables();
46
- let mut out = serde_json::Map::new();
47
- out.insert("ok".into(), serde_json::Value::Bool(true));
48
- out.insert("tables".into(), serde_json::Value::Array(
49
- names.iter().map(|n| serde_json::Value::String(n.clone())).collect()
50
- ));
51
- let mut schemas = serde_json::Map::new();
52
- for n in &names {
53
- if let Some(s) = eng.table_schema(n) {
54
- let mut v = serde_json::Map::new();
55
- for (k, fs) in &s {
56
- if let Ok(fv) = serde_json::to_value(fs) {
57
- v.insert(k.clone(), fv);
58
- }
141
+ with_engine_mut(|eng| do_open(eng, &dir, &mode))
142
+ }
143
+
144
+ #[napi]
145
+ pub fn jsql_open_h(handle: u32, dir: String, mode: String) -> String {
146
+ with_engine_handle_mut(handle, |eng| do_open(eng, &dir, &mode))
147
+ }
148
+
149
+ fn do_open(eng: &mut HybridEngine, dir: &str, mode: &str) -> String {
150
+ let open_res = eng.open(dir, mode);
151
+ match open_res {
152
+ Ok(()) => {
153
+ let names = eng.list_tables();
154
+ let mut out = serde_json::Map::new();
155
+ out.insert("ok".into(), serde_json::Value::Bool(true));
156
+ out.insert("tables".into(), serde_json::Value::Array(
157
+ names.iter().map(|n| serde_json::Value::String(n.clone())).collect()
158
+ ));
159
+ let mut schemas = serde_json::Map::new();
160
+ for n in &names {
161
+ if let Some(s) = eng.table_schema(n) {
162
+ let mut v = serde_json::Map::new();
163
+ for (k, fs) in &s {
164
+ if let Ok(fv) = serde_json::to_value(fs) {
165
+ v.insert(k.clone(), fv);
59
166
  }
60
- schemas.insert(n.clone(), serde_json::Value::Object(v));
61
167
  }
168
+ schemas.insert(n.clone(), serde_json::Value::Object(v));
62
169
  }
63
- out.insert("schemas".into(), serde_json::Value::Object(schemas));
64
- serde_json::to_string(&out).unwrap_or_else(|_| r#"{"ok":true}"#.to_string())
65
170
  }
66
- Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e.replace('"', r#"\""#)),
171
+ out.insert("schemas".into(), serde_json::Value::Object(schemas));
172
+ serde_json::to_string(&out).unwrap_or_else(|_| r#"{"ok":true}"#.to_string())
67
173
  }
68
- })
174
+ Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e.replace('"', r#"\""#)),
175
+ }
69
176
  }
70
177
 
71
- #[napi]
72
- pub fn jsql_flush_dirty() -> String {
73
- with_engine_mut(|eng| {
74
- match eng.flush_dirty() {
75
- Ok(n) => format!(r#"{{"ok":true,"flushed":{}}}"#, n),
76
- Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e.replace('"', r#"\""#)),
77
- }
78
- })
79
- }
178
+ napi_engine_fn!(jsql_flush_dirty, jsql_flush_dirty_h, () => |eng| {
179
+ match eng.flush_dirty() {
180
+ Ok(n) => format!(r#"{{"ok":true,"flushed":{}}}"#, n),
181
+ Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e.replace('"', r#"\""#)),
182
+ }
183
+ });
184
+
185
+ napi_engine_fn!(jsql_evict, jsql_evict_h, () => |eng| {
186
+ match eng.evict_one() {
187
+ Some(name) => format!(r#"{{"ok":true,"evicted":"{}","remaining":{}}}"#, name, eng.mem_count()),
188
+ None => r#"{"ok":true,"evicted":null,"remaining":0}"#.to_string(),
189
+ }
190
+ });
191
+
192
+ napi_engine_fn!(jsql_close, jsql_close_h, () => |eng| {
193
+ eng.close();
194
+ r#"{"ok":true}"#.to_string()
195
+ });
80
196
 
81
197
  #[napi]
82
- pub fn jsql_evict() -> String {
83
- with_engine_mut(|eng| {
84
- match eng.evict_one() {
85
- Some(name) => format!(r#"{{"ok":true,"evicted":"{}","remaining":{}}}"#, name, eng.mem_count()),
86
- None => r#"{"ok":true,"evicted":null,"remaining":0}"#.to_string(),
87
- }
88
- })
198
+ pub fn jsql_create_table(name: String, schema_json: String) -> String {
199
+ with_engine_mut(|eng| do_create_table(eng, &name, &schema_json))
89
200
  }
90
201
 
91
202
  #[napi]
92
- pub fn jsql_close() -> String {
93
- with_engine_mut(|eng| {
94
- eng.close();
95
- r#"{"ok":true}"#.to_string()
96
- })
203
+ pub fn jsql_create_table_h(handle: u32, name: String, schema_json: String) -> String {
204
+ with_engine_handle_mut(handle, |eng| do_create_table(eng, &name, &schema_json))
97
205
  }
98
206
 
99
- #[napi]
100
- pub fn jsql_create_table(name: String, schema_json: String) -> String {
207
+ fn do_create_table(eng: &mut HybridEngine, name: &str, schema_json: &str) -> String {
101
208
  use schema_order_preserving;
102
- let mut d = serde_json::Deserializer::from_str(&schema_json);
209
+ let mut d = serde_json::Deserializer::from_str(schema_json);
103
210
  let schema: Vec<(String, FieldSchema)> = match schema_order_preserving::deserialize(&mut d) {
104
211
  Ok(s) => s,
105
212
  Err(e) => return format!(r#"{{"ok":false,"error":"invalid schema: {}"}}"#, e),
106
213
  };
107
- let def = TableDefinition { name: name.clone(), schema };
108
- with_engine_mut(|eng| match eng.create_table(def) {
214
+ let def = TableDefinition { name: name.to_string(), schema };
215
+ match eng.create_table(def) {
109
216
  Ok(()) => r#"{"ok":true}"#.to_string(),
110
217
  Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
111
- })
218
+ }
112
219
  }
113
220
 
114
- #[napi]
115
- pub fn jsql_add_column(table: String, name: String, fs_json: String) -> String {
116
- let fs: FieldSchema = match serde_json::from_str(&fs_json) {
117
- Ok(f) => f,
118
- Err(e) => return format!(r#"{{"ok":false,"error":"invalid field schema: {}"}}"#, e),
119
- };
120
- with_engine_mut(|eng| match eng.add_column(&table, &name, fs) {
121
- Ok(()) => r#"{"ok":true}"#.to_string(),
122
- Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
123
- })
124
- }
221
+ napi_engine_fn!(jsql_add_column, jsql_add_column_h,
222
+ (table: String, name: String, fs_json: String) => |eng| {
223
+ let fs: FieldSchema = match serde_json::from_str(&fs_json) {
224
+ Ok(f) => f,
225
+ Err(e) => return format!(r#"{{"ok":false,"error":"invalid field schema: {}"}}"#, e),
226
+ };
227
+ match eng.add_column(&table, &name, fs) {
228
+ Ok(()) => r#"{"ok":true}"#.to_string(),
229
+ Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
230
+ }
231
+ }
232
+ );
125
233
 
126
- #[napi]
127
- pub fn jsql_drop_table(name: String) -> String {
128
- with_engine_mut(|eng| match eng.drop_table(&name) {
234
+ napi_engine_fn!(jsql_drop_table, jsql_drop_table_h, (name: String) => |eng| {
235
+ match eng.drop_table(&name) {
129
236
  Ok(()) => r#"{"ok":true}"#.to_string(),
130
237
  Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
131
- })
132
- }
238
+ }
239
+ });
133
240
 
134
- #[napi]
135
- pub fn jsql_insert(table: String, data_json: String) -> String {
136
- with_engine_mut(|eng| {
137
- let data: Vec<HashMap<String, serde_json::Value>> = match serde_json::from_str(&data_json) {
138
- Ok(d) => d,
139
- Err(e) => return format!(r#"{{"error":"invalid data: {}"}}"#, e),
140
- };
141
- match eng.insert(&table, data) {
142
- Ok(ids) => serde_json::to_string(&ids).unwrap_or_else(|_| "[]".to_string()),
143
- Err(e) => format!(r#"{{"error":"{}"}}"#, e),
144
- }
145
- })
146
- }
241
+ napi_engine_fn!(jsql_insert, jsql_insert_h, (table: String, data_json: String) => |eng| {
242
+ let data: Vec<HashMap<String, serde_json::Value>> = match serde_json::from_str(&data_json) {
243
+ Ok(d) => d,
244
+ Err(e) => return format!(r#"{{"error":"invalid data: {}"}}"#, e),
245
+ };
246
+ match eng.insert(&table, data) {
247
+ Ok(ids) => serde_json::to_string(&ids).unwrap_or_else(|_| "[]".to_string()),
248
+ Err(e) => format!(r#"{{"error":"{}"}}"#, e),
249
+ }
250
+ });
147
251
 
148
252
  #[napi]
149
253
  pub fn jsql_insert_buf(table: String, data: JsBuffer) -> String {
@@ -151,48 +255,53 @@ pub fn jsql_insert_buf(table: String, data: JsBuffer) -> String {
151
255
  Ok(v) => v,
152
256
  Err(_) => return r#"{"error":"invalid buffer"}"#.to_string(),
153
257
  };
154
- with_engine_mut(|eng| {
155
- let buf: &[u8] = buf_val.as_ref();
156
- let res = eng.insert_buf(&table, buf)
157
- .map(|ids| serde_json::to_string(&ids).unwrap_or_else(|_| "[]".to_string()));
158
- safe_json_result(res.map_err(|e| e))
159
- })
258
+ with_engine_mut(|eng| do_insert_buf(eng, &table, buf_val))
160
259
  }
161
260
 
162
261
  #[napi]
163
- pub fn jsql_find(table: String, filter_json: String, limit: i32, offset: i32) -> String {
164
- with_engine_ro(|eng| {
262
+ pub fn jsql_insert_buf_h(handle: u32, table: String, data: JsBuffer) -> String {
263
+ let buf_val = match data.into_value() {
264
+ Ok(v) => v,
265
+ Err(_) => return r#"{"error":"invalid buffer"}"#.to_string(),
266
+ };
267
+ with_engine_handle_mut(handle, |eng| do_insert_buf(eng, &table, buf_val))
268
+ }
269
+
270
+ fn do_insert_buf(eng: &mut HybridEngine, table: &str, buf_val: napi::JsBufferValue) -> String {
271
+ let buf: &[u8] = buf_val.as_ref();
272
+ let res = eng.insert_buf(table, buf)
273
+ .map(|ids| serde_json::to_string(&ids).unwrap_or_else(|_| "[]".to_string()));
274
+ safe_json_result(res)
275
+ }
276
+
277
+ napi_engine_fn!(jsql_find, jsql_find_h,
278
+ (table: String, filter_json: String, limit: i32, offset: i32) => |eng| {
165
279
  let filter: Option<HashMap<String, serde_json::Value>> =
166
280
  if filter_json.is_empty() { None } else { serde_json::from_str(&filter_json).ok() };
167
281
  match eng.find_json(&table, &filter, Some(limit as usize), Some(offset as usize), None, &None, &None) {
168
282
  Ok((json, _, _)) => json,
169
283
  Err(e) => format!(r#"{{"error":"{}"}}"#, e),
170
284
  }
171
- })
172
- }
285
+ }
286
+ );
173
287
 
174
- #[napi]
175
- pub fn jsql_find_by_id(table: String, id: i64) -> String {
176
- with_engine_ro(|eng| {
177
- match eng.find_by_id_json(&table, id as u64) {
178
- Ok(Some(s)) => s,
179
- Ok(None) => "null".to_string(),
180
- Err(e) => format!(r#"{{"error":"{}"}}"#, e),
181
- }
182
- })
183
- }
288
+ napi_engine_fn!(jsql_find_by_id, jsql_find_by_id_h, (table: String, id: i64) => |eng| {
289
+ match eng.find_by_id_json(&table, id as u64) {
290
+ Ok(Some(s)) => s,
291
+ Ok(None) => "null".to_string(),
292
+ Err(e) => format!(r#"{{"error":"{}"}}"#, e),
293
+ }
294
+ });
184
295
 
185
- #[napi]
186
- pub fn jsql_count(table: String) -> String {
187
- with_engine_ro(|eng| match eng.count(&table) {
296
+ napi_engine_fn!(jsql_count, jsql_count_h, (table: String) => |eng| {
297
+ match eng.count(&table) {
188
298
  Ok(c) => format!("{}", c),
189
299
  Err(e) => format!(r#"{{"error":"{}"}}"#, e),
190
- })
191
- }
300
+ }
301
+ });
192
302
 
193
- #[napi]
194
- pub fn jsql_update_by_id(table: String, id: i64, data_json: String) -> String {
195
- with_engine_mut(|eng| {
303
+ napi_engine_fn!(jsql_update_by_id, jsql_update_by_id_h,
304
+ (table: String, id: i64, data_json: String) => |eng| {
196
305
  let data: HashMap<String, serde_json::Value> = match serde_json::from_str(&data_json) {
197
306
  Ok(d) => d,
198
307
  Err(e) => return format!(r#"{{"ok":false,"error":"invalid data: {}"}}"#, e),
@@ -202,80 +311,67 @@ pub fn jsql_update_by_id(table: String, id: i64, data_json: String) -> String {
202
311
  Ok(false) => r#"{"ok":false,"error":"not found"}"#.to_string(),
203
312
  Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
204
313
  }
205
- })
206
- }
314
+ }
315
+ );
207
316
 
208
- #[napi]
209
- pub fn jsql_remove_by_id(table: String, id: i64) -> String {
210
- with_engine_mut(|eng| match eng.remove_by_id(&table, id as u64) {
317
+ napi_engine_fn!(jsql_remove_by_id, jsql_remove_by_id_h, (table: String, id: i64) => |eng| {
318
+ match eng.remove_by_id(&table, id as u64) {
211
319
  Ok(true) => r#"{"ok":true}"#.to_string(),
212
320
  Ok(false) => r#"{"ok":false,"error":"not found"}"#.to_string(),
213
321
  Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
214
- })
215
- }
322
+ }
323
+ });
216
324
 
217
- #[napi]
218
- pub fn jsql_remove_by_ids(table: String, ids_json: String) -> String {
219
- with_engine_mut(|eng| {
220
- let ids: Vec<u64> = match serde_json::from_str(&ids_json) {
221
- Ok(v) => v,
222
- Err(e) => return format!(r#"{{"error":"invalid ids: {}"}}"#, e),
223
- };
224
- match eng.remove_by_ids(&table, &ids) {
225
- Ok(n) => format!(r#"{{"ok":true,"count":{}}}"#, n),
226
- Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
227
- }
228
- })
229
- }
325
+ napi_engine_fn!(jsql_remove_by_ids, jsql_remove_by_ids_h, (table: String, ids_json: String) => |eng| {
326
+ let ids: Vec<u64> = match serde_json::from_str(&ids_json) {
327
+ Ok(v) => v,
328
+ Err(e) => return format!(r#"{{"error":"invalid ids: {}"}}"#, e),
329
+ };
330
+ match eng.remove_by_ids(&table, &ids) {
331
+ Ok(n) => format!(r#"{{"ok":true,"count":{}}}"#, n),
332
+ Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
333
+ }
334
+ });
230
335
 
231
- #[napi]
232
- pub fn jsql_update_by_ids(table: String, batch_json: String) -> String {
233
- with_engine_mut(|eng| {
234
- let batch: Vec<(u64, HashMap<String, serde_json::Value>)> = match serde_json::from_str(&batch_json) {
235
- Ok(v) => v,
236
- Err(e) => return format!(r#"{{"error":"invalid batch: {}"}}"#, e),
237
- };
238
- match eng.update_by_ids(&table, batch) {
239
- Ok(n) => format!(r#"{{"ok":true,"count":{}}}"#, n),
240
- Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
241
- }
242
- })
243
- }
336
+ napi_engine_fn!(jsql_update_by_ids, jsql_update_by_ids_h, (table: String, batch_json: String) => |eng| {
337
+ let batch: Vec<(u64, HashMap<String, serde_json::Value>)> = match serde_json::from_str(&batch_json) {
338
+ Ok(v) => v,
339
+ Err(e) => return format!(r#"{{"error":"invalid batch: {}"}}"#, e),
340
+ };
341
+ match eng.update_by_ids(&table, batch) {
342
+ Ok(n) => format!(r#"{{"ok":true,"count":{}}}"#, n),
343
+ Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
344
+ }
345
+ });
244
346
 
245
- #[napi]
246
- pub fn jsql_find_by_ids(table: String, ids_json: String) -> String {
247
- with_engine_ro(|eng| {
248
- let ids: Vec<u64> = match serde_json::from_str(&ids_json) {
249
- Ok(v) => v,
250
- Err(e) => return format!(r#"{{"error":"invalid ids: {}"}}"#, e),
251
- };
252
- match eng.find_by_ids_json(&table, &ids) {
253
- Ok(s) => s,
254
- Err(e) => format!(r#"{{"error":"{}"}}"#, e),
255
- }
256
- })
257
- }
347
+ napi_engine_fn!(jsql_find_by_ids, jsql_find_by_ids_h, (table: String, ids_json: String) => |eng| {
348
+ let ids: Vec<u64> = match serde_json::from_str(&ids_json) {
349
+ Ok(v) => v,
350
+ Err(e) => return format!(r#"{{"error":"invalid ids: {}"}}"#, e),
351
+ };
352
+ match eng.find_by_ids_json(&table, &ids) {
353
+ Ok(s) => s,
354
+ Err(e) => format!(r#"{{"error":"{}"}}"#, e),
355
+ }
356
+ });
258
357
 
259
- #[napi]
260
- pub fn jsql_begin_tx() -> String {
261
- with_engine_mut(|eng| match eng.begin_tx() {
358
+ napi_engine_fn!(jsql_begin_tx, jsql_begin_tx_h, () => |eng| {
359
+ match eng.begin_tx() {
262
360
  Ok(tx_id) => serde_json::json!({ "ok": true, "txId": tx_id }).to_string(),
263
361
  Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
264
- })
265
- }
362
+ }
363
+ });
266
364
 
267
- #[napi]
268
- pub fn jsql_commit_tx(tx_id: String) -> String {
269
- with_engine_mut(|eng| match eng.commit_tx(&tx_id) {
365
+ napi_engine_fn!(jsql_commit_tx, jsql_commit_tx_h, (tx_id: String) => |eng| {
366
+ match eng.commit_tx(&tx_id) {
270
367
  Ok(()) => r#"{"ok":true}"#.to_string(),
271
368
  Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
272
- })
273
- }
369
+ }
370
+ });
274
371
 
275
- #[napi]
276
- pub fn jsql_rollback_tx(tx_id: String) -> String {
277
- with_engine_mut(|eng| match eng.rollback_tx(&tx_id) {
372
+ napi_engine_fn!(jsql_rollback_tx, jsql_rollback_tx_h, (tx_id: String) => |eng| {
373
+ match eng.rollback_tx(&tx_id) {
278
374
  Ok(()) => r#"{"ok":true}"#.to_string(),
279
375
  Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
280
- })
281
- }
376
+ }
377
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsql-neo",
3
- "version": "6.3.3",
3
+ "version": "6.3.5",
4
4
  "description": "JSQL-NEO — Rust-powered embedded database with WASM, REST API, B-Tree indexes, WAL, crash recovery",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -46,14 +46,15 @@
46
46
  ],
47
47
  "scripts": {
48
48
  "postinstall": "node postinstall.js",
49
- "test": "node test/smoke.js && node test/sql-parser.test.js && node test/readme-audit.test.js && node test/query-opt.test.js",
49
+ "test": "node test/smoke.js && node test/sql-parser.test.js && node test/readme-audit.test.js && node test/query-opt.test.js && node test/wal-recovery.test.js && node test/mysql-compat-hijack.test.js",
50
50
  "test:parser": "node test/sql-parser.test.js",
51
51
  "test:btree": "node test/btree.test.js",
52
52
  "test:native": "node test/native.test.js",
53
53
  "test:regress": "node test/regress-5.1.0.js",
54
- "test:all": "node test/smoke.js && node test/sql-parser.test.js && node test/readme-audit.test.js && node test/native.test.js && node test/wasm.test.js && node test/coverage.js && node test/regress-5.1.0.js && node test/join.test.js && node test/btree.test.js",
55
- "test:coverage": "c8 --all --include='lib/**' --exclude='lib/mysql_server.js' --exclude='lib/native_client.js' --exclude='lib/wasm_client.js' --exclude='lib/mysql_compat.js' --exclude='lib/nedb_compat.js' --exclude='lib/plugin.js' --reporter=text --reporter=lcov node test/coverage.js",
56
- "test:orms": "node examples/orms/run-all.js"
54
+ "test:all": "node test/smoke.js && node test/sql-parser.test.js && node test/readme-audit.test.js && node test/native.test.js && node test/native-multi-instance.test.js && node test/wal-recovery.test.js && node test/mysql-compat-hijack.test.js && node test/wasm.test.js && node test/coverage.js && node test/regress-5.1.0.js && node test/join.test.js && node test/btree.test.js && node test/dml-constraints.test.js",
55
+ "test:coverage": "c8 --all --include='lib/**' --exclude='lib/web_ui.js' --reporter=text --reporter=lcov node test/coverage.js",
56
+ "test:orms": "node examples/orms/run-all.js",
57
+ "test:dml": "node test/dml-constraints.test.js"
57
58
  },
58
59
  "keywords": [
59
60
  "database",