jsql-neo 4.0.2 → 4.1.1
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/README.md +4 -1
- package/bin/jsql +69 -0
- package/bin/jsql-server +90 -0
- package/bin/jsql-server-control.js +177 -0
- package/lib/database.js +98 -9
- package/lib/errors.js +6 -0
- package/lib/jsql_format.js +33 -14
- package/lib/mod.js +43 -67
- package/lib/mysql_compat.js +134 -17
- package/lib/mysql_server.js +315 -22
- package/lib/native_client.js +95 -32
- package/lib/sql.js +646 -122
- package/lib/table.js +114 -12
- package/lib/wasm_client.js +59 -6
- package/native/jsql-neo-native.node +0 -0
- package/nativesrc/jsql-neo-core/Cargo.lock +455 -0
- package/nativesrc/jsql-neo-core/src/engine/hybrid.rs +12 -6
- package/nativesrc/jsql-neo-core/src/engine/memory.rs +28 -7
- package/nativesrc/jsql-neo-core/src/engine/mod.rs +22 -1
- package/nativesrc/jsql-neo-core/src/engine/table.rs +53 -23
- package/nativesrc/jsql-neo-core/src/storage/mod.rs +2 -1
- package/nativesrc/jsql-neo-core/src/storage/wal.rs +1 -0
- package/nativesrc/jsql-neo-native/build.rs +3 -0
- package/nativesrc/jsql-neo-native/jsql-neo-native.node +0 -0
- package/nativesrc/jsql-neo-native/src/lib.rs +75 -87
- package/nativesrc/jsql-neo-wasm/Cargo.lock +465 -0
- package/nativesrc/jsql-neo-wasm/Cargo.toml +15 -0
- package/nativesrc/jsql-neo-wasm/src/lib.rs +423 -0
- package/package.json +8 -1
- package/wasm/jsql_neo_wasm.d.ts +2 -0
- package/wasm/jsql_neo_wasm.js +5 -0
- package/wasm/jsql_neo_wasm_bg.wasm +0 -0
- package/wasm/jsql_neo_wasm_bg.wasm.d.ts +1 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
use jsql_neo_core::engine::{Engine, MemoryEngine, FieldValue, RowStore, default_value};
|
|
2
|
+
use jsql_neo_core::types::{schema_order_preserving, FieldSchema};
|
|
3
|
+
use std::cell::RefCell;
|
|
4
|
+
use wasm_bindgen::prelude::*;
|
|
5
|
+
|
|
6
|
+
thread_local! {
|
|
7
|
+
static ENGINE: RefCell<MemoryEngine> = RefCell::new(MemoryEngine::new());
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
#[wasm_bindgen]
|
|
11
|
+
pub fn jsql_reset() {
|
|
12
|
+
ENGINE.with(|eng| {
|
|
13
|
+
eng.borrow_mut().clear();
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#[wasm_bindgen]
|
|
18
|
+
pub fn jsql_create_table(name: &str, schema_json: &str) -> String {
|
|
19
|
+
ENGINE.with(|eng| {
|
|
20
|
+
let schema: Vec<(String, FieldSchema)> = match schema_order_preserving::deserialize(
|
|
21
|
+
&mut serde_json::Deserializer::from_str(schema_json),
|
|
22
|
+
) {
|
|
23
|
+
Ok(s) => s,
|
|
24
|
+
Err(e) => return format!(r#"{{"ok":false,"error":"invalid schema: {}"}}"#, e),
|
|
25
|
+
};
|
|
26
|
+
let def = jsql_neo_core::types::TableDefinition {
|
|
27
|
+
name: name.to_string(),
|
|
28
|
+
schema,
|
|
29
|
+
};
|
|
30
|
+
match eng.borrow_mut().create_table(def) {
|
|
31
|
+
Ok(()) => r#"{"ok":true}"#.to_string(),
|
|
32
|
+
Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#[wasm_bindgen]
|
|
38
|
+
pub fn jsql_drop_table(name: &str) -> String {
|
|
39
|
+
ENGINE.with(|eng| match eng.borrow_mut().drop_table(name) {
|
|
40
|
+
Ok(()) => r#"{"ok":true}"#.to_string(),
|
|
41
|
+
Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
#[wasm_bindgen]
|
|
46
|
+
pub fn jsql_insert(table: &str, data_json: &str) -> String {
|
|
47
|
+
ENGINE.with(|eng| {
|
|
48
|
+
let data: Vec<std::collections::HashMap<String, serde_json::Value>> =
|
|
49
|
+
match serde_json::from_str(data_json) {
|
|
50
|
+
Ok(d) => d,
|
|
51
|
+
Err(e) => return format!(r#"{{"error":"invalid data: {}"}}"#, e),
|
|
52
|
+
};
|
|
53
|
+
match eng.borrow_mut().insert(table, data) {
|
|
54
|
+
Ok(ids) => serde_json::to_string(&ids).unwrap_or_else(|_| "[]".to_string()),
|
|
55
|
+
Err(e) => format!(r#"{{"error":"{}"}}"#, e),
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#[wasm_bindgen]
|
|
61
|
+
pub fn jsql_insert_json(table: &str, json: &str) -> String {
|
|
62
|
+
ENGINE.with(|eng| {
|
|
63
|
+
let res = (|| -> Result<Vec<u64>, String> {
|
|
64
|
+
let mut eng = eng.borrow_mut();
|
|
65
|
+
let t = eng.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
|
|
66
|
+
|
|
67
|
+
let data: Vec<serde_json::Value> = serde_json::from_str(json)
|
|
68
|
+
.map_err(|e| format!("invalid JSON: {}", e))?;
|
|
69
|
+
let n = data.len();
|
|
70
|
+
if n == 0 { return Ok(Vec::new()); }
|
|
71
|
+
|
|
72
|
+
let first = data[0].as_object()
|
|
73
|
+
.ok_or_else(|| "expected array of objects".to_string())?;
|
|
74
|
+
let field_names: Vec<String> = first.keys().cloned().collect();
|
|
75
|
+
|
|
76
|
+
let remap: Vec<Option<usize>> = t.field_order.iter()
|
|
77
|
+
.map(|name| field_names.iter().position(|n| n == name))
|
|
78
|
+
.collect();
|
|
79
|
+
|
|
80
|
+
let pk_idx = t.pk_field.as_ref().and_then(|pk| {
|
|
81
|
+
t.schema.get(pk.as_str()).and_then(|fs| {
|
|
82
|
+
if fs.auto_increment { t.field_index.get(pk.as_str()).copied() } else { None }
|
|
83
|
+
})
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
let now = js_sys::Date::now() as u64;
|
|
87
|
+
let start_id = t.next_id;
|
|
88
|
+
t.next_id += n as u64;
|
|
89
|
+
t.pk_index.reserve(n);
|
|
90
|
+
t.rows.reserve(n);
|
|
91
|
+
t.values.reserve(t.field_order.len());
|
|
92
|
+
let start_ri = t.rows.len();
|
|
93
|
+
|
|
94
|
+
for (ri, row_val) in data.iter().enumerate() {
|
|
95
|
+
let auto_id = start_id + ri as u64;
|
|
96
|
+
let mut id = auto_id;
|
|
97
|
+
let obj = row_val.as_object()
|
|
98
|
+
.ok_or_else(|| "non-object in array".to_string())?;
|
|
99
|
+
|
|
100
|
+
let mut values = Vec::with_capacity(t.field_order.len());
|
|
101
|
+
for (i, rp) in remap.iter().enumerate() {
|
|
102
|
+
if let Some(fi) = rp {
|
|
103
|
+
let key = &field_names[*fi];
|
|
104
|
+
if let Some(jv) = obj.get(key) {
|
|
105
|
+
values.push(FieldValue::from_json(jv.clone()));
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
} else if let Some(pi) = pk_idx {
|
|
109
|
+
if pi == i {
|
|
110
|
+
values.push(FieldValue::Int(id as i64));
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if let Some(name) = t.field_order.get(i) {
|
|
115
|
+
if let Some(fs) = t.schema.get(name) {
|
|
116
|
+
if let Some(ref default) = fs.default {
|
|
117
|
+
values.push(FieldValue::from_json(default.clone()));
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if !fs.nullable {
|
|
121
|
+
values.push(default_value(&fs.field_type));
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
values.push(FieldValue::Null);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// auto-increment PK: keep explicit positive value, else fill with auto id
|
|
130
|
+
if let Some(pi) = pk_idx {
|
|
131
|
+
if let Some(v) = values.get_mut(pi) {
|
|
132
|
+
match v {
|
|
133
|
+
FieldValue::Null => *v = FieldValue::Int(id as i64),
|
|
134
|
+
FieldValue::Int(e) if *e > 0 => {
|
|
135
|
+
id = *e as u64;
|
|
136
|
+
t.next_id = t.next_id.max(id + 1);
|
|
137
|
+
}
|
|
138
|
+
_ => {}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
t.pk_index.insert(id, start_ri + ri);
|
|
144
|
+
let vs = t.values.len();
|
|
145
|
+
t.values.extend(values);
|
|
146
|
+
t.rows.push(RowStore { id, values_start: vs, num_values: t.field_order.len(), created_at: now, updated_at: now });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
let ids: Vec<u64> = (start_id..start_id + n as u64).collect();
|
|
150
|
+
Ok(ids)
|
|
151
|
+
})();
|
|
152
|
+
match res {
|
|
153
|
+
Ok(ids) => serde_json::to_string(&ids).unwrap_or_else(|_| "[]".to_string()),
|
|
154
|
+
Err(e) => format!(r#"{{"error":"{}"}}"#, e),
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
fn insert_buf_parse(eng: &mut MemoryEngine, table: &str, data: &[u8]) -> Result<Vec<u64>, String> {
|
|
160
|
+
let t = eng.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
|
|
161
|
+
|
|
162
|
+
let mut off = 0usize;
|
|
163
|
+
let n_fields = *data.get(off).ok_or_else(|| "truncated header".to_string())? as usize;
|
|
164
|
+
off += 1;
|
|
165
|
+
if n_fields == 0 {
|
|
166
|
+
return Err("invalid header".to_string());
|
|
167
|
+
}
|
|
168
|
+
let mut field_names = Vec::with_capacity(n_fields);
|
|
169
|
+
for _ in 0..n_fields {
|
|
170
|
+
let name_len = *data.get(off).ok_or_else(|| "truncated header".to_string())? as usize;
|
|
171
|
+
off += 1;
|
|
172
|
+
let name = std::str::from_utf8(
|
|
173
|
+
data.get(off..off + name_len).ok_or_else(|| "truncated header".to_string())?,
|
|
174
|
+
)
|
|
175
|
+
.map_err(|_| "invalid utf8 in header".to_string())?
|
|
176
|
+
.to_string();
|
|
177
|
+
off += name_len;
|
|
178
|
+
field_names.push(name);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let seg4 = data.get(off..off + 4).ok_or_else(|| "truncated".to_string())?;
|
|
182
|
+
let row_count = u32::from_le_bytes([seg4[0], seg4[1], seg4[2], seg4[3]]) as usize;
|
|
183
|
+
off += 4;
|
|
184
|
+
if row_count == 0 {
|
|
185
|
+
return Ok(Vec::new());
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
let pk_idx = t.pk_field.as_ref().and_then(|pk| {
|
|
189
|
+
t.schema.get(pk.as_str()).and_then(|fs| {
|
|
190
|
+
if fs.auto_increment { t.field_index.get(pk.as_str()).copied() } else { None }
|
|
191
|
+
})
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
let order_matches = field_names.len() == t.field_order.len()
|
|
195
|
+
&& field_names.iter().zip(&t.field_order).all(|(a, b)| a == b);
|
|
196
|
+
let remap: Vec<Option<usize>> = t.field_order.iter()
|
|
197
|
+
.map(|name| field_names.iter().position(|n| n == name))
|
|
198
|
+
.collect();
|
|
199
|
+
|
|
200
|
+
let start_id = t.next_id;
|
|
201
|
+
t.next_id += row_count as u64;
|
|
202
|
+
t.pk_index.reserve(row_count);
|
|
203
|
+
t.rows.reserve(row_count);
|
|
204
|
+
t.values.reserve(t.field_order.len() * row_count);
|
|
205
|
+
let now = js_sys::Date::now() as u64;
|
|
206
|
+
let start_ri = t.rows.len();
|
|
207
|
+
|
|
208
|
+
for ri in 0..row_count {
|
|
209
|
+
let auto_id = start_id + ri as u64;
|
|
210
|
+
let mut id = auto_id;
|
|
211
|
+
let mut row_vals = Vec::with_capacity(n_fields);
|
|
212
|
+
for _fi in 0..n_fields {
|
|
213
|
+
let tag = *data.get(off).ok_or_else(|| "truncated row data".to_string())?;
|
|
214
|
+
off += 1;
|
|
215
|
+
match tag {
|
|
216
|
+
0 => row_vals.push(FieldValue::Null),
|
|
217
|
+
1 => {
|
|
218
|
+
let b = data.get(off..off + 8).ok_or_else(|| "truncated row data".to_string())?;
|
|
219
|
+
off += 8;
|
|
220
|
+
row_vals.push(FieldValue::Int(i64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])));
|
|
221
|
+
}
|
|
222
|
+
2 => {
|
|
223
|
+
let b = data.get(off..off + 8).ok_or_else(|| "truncated row data".to_string())?;
|
|
224
|
+
off += 8;
|
|
225
|
+
row_vals.push(FieldValue::Float(f64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])));
|
|
226
|
+
}
|
|
227
|
+
3 => {
|
|
228
|
+
let seg = data.get(off..off + 4).ok_or_else(|| "truncated row data".to_string())?;
|
|
229
|
+
let len = u32::from_le_bytes([seg[0], seg[1], seg[2], seg[3]]) as usize;
|
|
230
|
+
off += 4;
|
|
231
|
+
let s = std::str::from_utf8(
|
|
232
|
+
data.get(off..off + len).ok_or_else(|| "truncated row data".to_string())?,
|
|
233
|
+
)
|
|
234
|
+
.map_err(|_| "invalid utf8 in row data".to_string())?
|
|
235
|
+
.to_string();
|
|
236
|
+
off += len;
|
|
237
|
+
row_vals.push(FieldValue::String(s));
|
|
238
|
+
}
|
|
239
|
+
4 => {
|
|
240
|
+
let b = *data.get(off).ok_or_else(|| "truncated row data".to_string())?;
|
|
241
|
+
off += 1;
|
|
242
|
+
row_vals.push(FieldValue::Bool(b != 0));
|
|
243
|
+
}
|
|
244
|
+
5 => {
|
|
245
|
+
let b = data.get(off..off + 4).ok_or_else(|| "truncated row data".to_string())?;
|
|
246
|
+
off += 4;
|
|
247
|
+
row_vals.push(FieldValue::Int(i32::from_le_bytes([b[0], b[1], b[2], b[3]]) as i64));
|
|
248
|
+
}
|
|
249
|
+
_ => row_vals.push(FieldValue::Null),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
let mut values = Vec::with_capacity(t.field_order.len());
|
|
254
|
+
if order_matches {
|
|
255
|
+
values = row_vals;
|
|
256
|
+
if values.len() < t.field_order.len() {
|
|
257
|
+
values.resize(t.field_order.len(), FieldValue::Null);
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
for (i, rp) in remap.iter().enumerate() {
|
|
261
|
+
if let Some(si) = rp {
|
|
262
|
+
if *si < row_vals.len() {
|
|
263
|
+
values.push(std::mem::take(&mut row_vals[*si]));
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if let Some(pi) = pk_idx {
|
|
268
|
+
if pi == i {
|
|
269
|
+
values.push(FieldValue::Int(id as i64));
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if let Some(name) = t.field_order.get(i) {
|
|
274
|
+
if let Some(fs) = t.schema.get(name) {
|
|
275
|
+
if let Some(ref default) = fs.default {
|
|
276
|
+
values.push(FieldValue::from_json(default.clone()));
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
values.push(FieldValue::Null);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// auto-increment PK: keep explicit positive value (row id = pk), else fill with auto id
|
|
286
|
+
if let Some(pi) = pk_idx {
|
|
287
|
+
if let Some(v) = values.get_mut(pi) {
|
|
288
|
+
match v {
|
|
289
|
+
FieldValue::Null => *v = FieldValue::Int(id as i64),
|
|
290
|
+
FieldValue::Int(e) if *e > 0 => {
|
|
291
|
+
id = *e as u64;
|
|
292
|
+
t.next_id = t.next_id.max(id + 1);
|
|
293
|
+
}
|
|
294
|
+
_ => {}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
t.pk_index.insert(id, start_ri + ri);
|
|
300
|
+
let vs = t.values.len();
|
|
301
|
+
t.values.extend(values);
|
|
302
|
+
t.rows.push(RowStore { id, values_start: vs, num_values: t.field_order.len(), created_at: now, updated_at: now });
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
Ok((start_id..start_id + row_count as u64).collect())
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
#[wasm_bindgen]
|
|
309
|
+
pub fn jsql_insert_buf(table: &str, data: &[u8]) -> String {
|
|
310
|
+
ENGINE.with(|eng| {
|
|
311
|
+
match insert_buf_parse(&mut eng.borrow_mut(), table, data) {
|
|
312
|
+
Ok(ids) => serde_json::to_string(&ids).unwrap_or_else(|_| "[]".to_string()),
|
|
313
|
+
Err(e) => format!(r#"{{"error":"{}"}}"#, e),
|
|
314
|
+
}
|
|
315
|
+
})
|
|
316
|
+
}
|
|
317
|
+
#[wasm_bindgen]
|
|
318
|
+
pub fn jsql_insert_buf_count(table: &str, data: &[u8]) -> String {
|
|
319
|
+
ENGINE.with(|eng| {
|
|
320
|
+
match insert_buf_parse(&mut eng.borrow_mut(), table, data) {
|
|
321
|
+
Ok(ids) => format!("{}", ids.len()),
|
|
322
|
+
Err(_) => "0".to_string(),
|
|
323
|
+
}
|
|
324
|
+
})
|
|
325
|
+
}
|
|
326
|
+
#[wasm_bindgen]
|
|
327
|
+
pub fn jsql_find(table: &str, filter_json: &str, limit: usize, offset: usize) -> String {
|
|
328
|
+
ENGINE.with(|eng| {
|
|
329
|
+
let filter: Option<std::collections::HashMap<String, serde_json::Value>> =
|
|
330
|
+
if filter_json.is_empty() { None } else { serde_json::from_str(filter_json).ok() };
|
|
331
|
+
match eng.borrow().find(table, &filter, Some(limit), Some(offset), None, &None, &None) {
|
|
332
|
+
Ok((rows, _, _)) => serde_json::to_string(&rows).unwrap_or_else(|_| "[]".to_string()),
|
|
333
|
+
Err(e) => format!(r#"{{"error":"{}"}}"#, e),
|
|
334
|
+
}
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
#[wasm_bindgen]
|
|
339
|
+
pub fn jsql_find_by_id(table: &str, id: u64) -> String {
|
|
340
|
+
ENGINE.with(|eng| {
|
|
341
|
+
match eng.borrow().find_by_id_json(table, id) {
|
|
342
|
+
Ok(Some(s)) => s,
|
|
343
|
+
Ok(None) => "null".to_string(),
|
|
344
|
+
Err(e) => format!(r#"{{"error":"{}"}}"#, e),
|
|
345
|
+
}
|
|
346
|
+
})
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
#[wasm_bindgen]
|
|
350
|
+
pub fn jsql_count(table: &str) -> String {
|
|
351
|
+
ENGINE.with(|eng| match eng.borrow().count(table) {
|
|
352
|
+
Ok(c) => format!("{}", c),
|
|
353
|
+
Err(e) => format!(r#"{{"error":"{}"}}"#, e),
|
|
354
|
+
})
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
#[wasm_bindgen]
|
|
358
|
+
pub fn jsql_update_by_id(table: &str, id: u64, data_json: &str) -> String {
|
|
359
|
+
ENGINE.with(|eng| {
|
|
360
|
+
let data: std::collections::HashMap<String, serde_json::Value> =
|
|
361
|
+
match serde_json::from_str(data_json) {
|
|
362
|
+
Ok(d) => d,
|
|
363
|
+
Err(e) => return format!(r#"{{"ok":false,"error":"invalid data: {}"}}"#, e),
|
|
364
|
+
};
|
|
365
|
+
match eng.borrow_mut().update_by_id(table, id, data) {
|
|
366
|
+
Ok(true) => r#"{"ok":true}"#.to_string(),
|
|
367
|
+
Ok(false) => r#"{"ok":false,"error":"not found"}"#.to_string(),
|
|
368
|
+
Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
|
|
369
|
+
}
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
#[wasm_bindgen]
|
|
374
|
+
pub fn jsql_remove_by_id(table: &str, id: u64) -> String {
|
|
375
|
+
ENGINE.with(|eng| match eng.borrow_mut().remove_by_id(table, id) {
|
|
376
|
+
Ok(true) => r#"{"ok":true}"#.to_string(),
|
|
377
|
+
Ok(false) => r#"{"ok":false,"error":"not found"}"#.to_string(),
|
|
378
|
+
Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
|
|
379
|
+
})
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
#[wasm_bindgen]
|
|
383
|
+
pub fn jsql_remove_by_ids(table: &str, ids_json: &str) -> String {
|
|
384
|
+
ENGINE.with(|eng| {
|
|
385
|
+
let ids: Vec<u64> = match serde_json::from_str(ids_json) {
|
|
386
|
+
Ok(v) => v,
|
|
387
|
+
Err(e) => return format!(r#"{{"error":"invalid ids: {}"}}"#, e),
|
|
388
|
+
};
|
|
389
|
+
match eng.borrow_mut().remove_by_ids(table, &ids) {
|
|
390
|
+
Ok(n) => format!(r#"{{"ok":true,"count":{}}}"#, n),
|
|
391
|
+
Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
|
|
392
|
+
}
|
|
393
|
+
})
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
#[wasm_bindgen]
|
|
397
|
+
pub fn jsql_update_by_ids(table: &str, batch_json: &str) -> String {
|
|
398
|
+
ENGINE.with(|eng| {
|
|
399
|
+
let batch: Vec<(u64, std::collections::HashMap<String, serde_json::Value>)> =
|
|
400
|
+
match serde_json::from_str(batch_json) {
|
|
401
|
+
Ok(v) => v,
|
|
402
|
+
Err(e) => return format!(r#"{{"error":"invalid batch: {}"}}"#, e),
|
|
403
|
+
};
|
|
404
|
+
match eng.borrow_mut().update_by_ids(table, batch) {
|
|
405
|
+
Ok(n) => format!(r#"{{"ok":true,"count":{}}}"#, n),
|
|
406
|
+
Err(e) => format!(r#"{{"ok":false,"error":"{}"}}"#, e),
|
|
407
|
+
}
|
|
408
|
+
})
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
#[wasm_bindgen]
|
|
412
|
+
pub fn jsql_find_by_ids(table: &str, ids_json: &str) -> String {
|
|
413
|
+
ENGINE.with(|eng| {
|
|
414
|
+
let ids: Vec<u64> = match serde_json::from_str(ids_json) {
|
|
415
|
+
Ok(v) => v,
|
|
416
|
+
Err(e) => return format!(r#"{{"error":"invalid ids: {}"}}"#, e),
|
|
417
|
+
};
|
|
418
|
+
match eng.borrow().find_by_ids_json(table, &ids) {
|
|
419
|
+
Ok(s) => s,
|
|
420
|
+
Err(e) => format!(r#"{{"error":"{}"}}"#, e),
|
|
421
|
+
}
|
|
422
|
+
})
|
|
423
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsql-neo",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.1",
|
|
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
|
"bin": {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"wasm/",
|
|
14
14
|
"native/",
|
|
15
15
|
"nativesrc/",
|
|
16
|
+
"!nativesrc/**/target/",
|
|
16
17
|
"postinstall.js",
|
|
17
18
|
"README.md",
|
|
18
19
|
"LICENSE"
|
|
@@ -35,6 +36,12 @@
|
|
|
35
36
|
],
|
|
36
37
|
"author": "Vexify",
|
|
37
38
|
"license": "Apache-2.0",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/vexify-org/JSQL-neo.git"
|
|
42
|
+
},
|
|
43
|
+
"bugs": "https://github.com/vexify-org/JSQL-neo/issues",
|
|
44
|
+
"homepage": "https://github.com/vexify-org/JSQL-neo#readme",
|
|
38
45
|
"engines": {
|
|
39
46
|
"node": ">=14.0.0"
|
|
40
47
|
},
|
package/wasm/jsql_neo_wasm.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export function jsql_remove_by_id(table: string, id: bigint): string;
|
|
|
25
25
|
|
|
26
26
|
export function jsql_remove_by_ids(table: string, ids_json: string): string;
|
|
27
27
|
|
|
28
|
+
export function jsql_reset(): void;
|
|
29
|
+
|
|
28
30
|
export function jsql_update_by_id(table: string, id: bigint, data_json: string): string;
|
|
29
31
|
|
|
30
32
|
export function jsql_update_by_ids(table: string, batch_json: string): string;
|
package/wasm/jsql_neo_wasm.js
CHANGED
|
@@ -268,6 +268,11 @@ function jsql_remove_by_ids(table, ids_json) {
|
|
|
268
268
|
}
|
|
269
269
|
exports.jsql_remove_by_ids = jsql_remove_by_ids;
|
|
270
270
|
|
|
271
|
+
function jsql_reset() {
|
|
272
|
+
wasm.jsql_reset();
|
|
273
|
+
}
|
|
274
|
+
exports.jsql_reset = jsql_reset;
|
|
275
|
+
|
|
271
276
|
/**
|
|
272
277
|
* @param {string} table
|
|
273
278
|
* @param {bigint} id
|
|
Binary file
|
|
@@ -15,6 +15,7 @@ export const jsql_remove_by_id: (a: number, b: number, c: bigint) => [number, nu
|
|
|
15
15
|
export const jsql_remove_by_ids: (a: number, b: number, c: number, d: number) => [number, number];
|
|
16
16
|
export const jsql_update_by_id: (a: number, b: number, c: bigint, d: number, e: number) => [number, number];
|
|
17
17
|
export const jsql_update_by_ids: (a: number, b: number, c: number, d: number) => [number, number];
|
|
18
|
+
export const jsql_reset: () => void;
|
|
18
19
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
19
20
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
20
21
|
export const __wbindgen_externrefs: WebAssembly.Table;
|