jsql-neo 5.4.2 → 5.5.0

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 (72) hide show
  1. package/LICENSE +202 -202
  2. package/README.md +8097 -7971
  3. package/bin/jsql +320 -320
  4. package/bin/jsql-server +90 -90
  5. package/bin/jsql-server-control.js +177 -177
  6. package/index.d.ts +385 -357
  7. package/index.js +124 -118
  8. package/lib/ast.js +214 -0
  9. package/lib/btree.js +413 -413
  10. package/lib/cache.js +328 -328
  11. package/lib/client.js +125 -125
  12. package/lib/database.js +1744 -1744
  13. package/lib/date-types.js +182 -182
  14. package/lib/errors.js +89 -89
  15. package/lib/jsql_format.js +497 -497
  16. package/lib/migrate.js +254 -254
  17. package/lib/mod.js +292 -292
  18. package/lib/mongo_server.js +607 -607
  19. package/lib/multiserver.js +140 -140
  20. package/lib/mysql_compat.js +413 -413
  21. package/lib/mysql_server.js +1237 -1237
  22. package/lib/native_client.js +732 -732
  23. package/lib/nedb_compat.js +506 -506
  24. package/lib/pg_server.js +864 -864
  25. package/lib/plugin.js +34 -34
  26. package/lib/query.js +815 -815
  27. package/lib/redis_server.js +571 -571
  28. package/lib/sql.js +3460 -2925
  29. package/lib/sqlite_compat.js +323 -323
  30. package/lib/sqlite_worker.js +264 -264
  31. package/lib/table.js +1304 -1304
  32. package/lib/tui.js +502 -502
  33. package/lib/wasm.js +1 -1
  34. package/lib/wasm_client.js +718 -718
  35. package/lib/web_ui.js +257 -257
  36. package/native/jsql-neo-native.node +0 -0
  37. package/nativesrc/jsql-neo-core/Cargo.lock +455 -455
  38. package/nativesrc/jsql-neo-core/Cargo.toml +24 -24
  39. package/nativesrc/jsql-neo-core/src/engine/hybrid.rs +455 -455
  40. package/nativesrc/jsql-neo-core/src/engine/memory.rs +168 -168
  41. package/nativesrc/jsql-neo-core/src/engine/mod.rs +62 -62
  42. package/nativesrc/jsql-neo-core/src/engine/table.rs +700 -700
  43. package/nativesrc/jsql-neo-core/src/lib.rs +2 -2
  44. package/nativesrc/jsql-neo-core/src/storage/mod.rs +2 -2
  45. package/nativesrc/jsql-neo-core/src/storage/persistent.rs +1 -1
  46. package/nativesrc/jsql-neo-core/src/storage/wal.rs +85 -85
  47. package/nativesrc/jsql-neo-core/src/types.rs +93 -93
  48. package/nativesrc/jsql-neo-native/Cargo.lock +606 -606
  49. package/nativesrc/jsql-neo-native/Cargo.toml +16 -16
  50. package/nativesrc/jsql-neo-native/build.rs +3 -3
  51. package/nativesrc/jsql-neo-native/package.json +7 -7
  52. package/nativesrc/jsql-neo-native/src/lib.rs +269 -269
  53. package/nativesrc/jsql-neo-wasm/Cargo.lock +465 -465
  54. package/nativesrc/jsql-neo-wasm/Cargo.toml +15 -15
  55. package/nativesrc/jsql-neo-wasm/src/lib.rs +447 -447
  56. package/package.json +87 -86
  57. package/postinstall.js +158 -158
  58. package/test/btree.test.js +128 -128
  59. package/test/coverage.js +187 -187
  60. package/test/join.test.js +110 -110
  61. package/test/native.test.js +158 -158
  62. package/test/regress-5.1.0.js +271 -271
  63. package/test/smoke.js +58 -58
  64. package/test/sql-parser.test.js +273 -0
  65. package/test/wasm.test.js +110 -110
  66. package/wasm/browser.d.ts +89 -89
  67. package/wasm/browser.mjs +569 -569
  68. package/wasm/browser_bg.mjs +597 -597
  69. package/wasm/jsql_neo_wasm.d.ts +38 -38
  70. package/wasm/jsql_neo_wasm.js +520 -520
  71. package/wasm/jsql_neo_wasm_bg.wasm.d.ts +26 -26
  72. package/wasm/package.json +11 -11
@@ -1,700 +1,700 @@
1
- use std::collections::HashMap;
2
- use rustc_hash::FxHashMap;
3
- use serde::Serialize;
4
- use crate::types::{Row, FieldSchema, FieldType};
5
- use std::fmt::Write;
6
-
7
- #[derive(Debug, Clone, PartialEq, Default)]
8
- pub enum FieldValue {
9
- #[default]
10
- Null,
11
- Bool(bool),
12
- Int(i64),
13
- Float(f64),
14
- String(String),
15
- }
16
-
17
- impl serde::Serialize for FieldValue {
18
- fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
19
- match self {
20
- FieldValue::Null => s.serialize_unit(),
21
- FieldValue::Bool(b) => s.serialize_bool(*b),
22
- FieldValue::Int(n) => s.serialize_i64(*n),
23
- FieldValue::Float(f) => s.serialize_f64(*f),
24
- FieldValue::String(st) => s.serialize_str(st),
25
- }
26
- }
27
- }
28
-
29
- impl FieldValue {
30
- pub fn from_json(jv: serde_json::Value) -> Self {
31
- match jv {
32
- serde_json::Value::Null => FieldValue::Null,
33
- serde_json::Value::Bool(b) => FieldValue::Bool(b),
34
- serde_json::Value::Number(n) => {
35
- n.as_i64().map(FieldValue::Int)
36
- .or_else(|| n.as_f64().map(FieldValue::Float))
37
- .unwrap_or(FieldValue::Null)
38
- }
39
- serde_json::Value::String(s) => FieldValue::String(s),
40
- _ => FieldValue::Null,
41
- }
42
- }
43
-
44
- fn to_json(&self) -> serde_json::Value {
45
- match self {
46
- FieldValue::Null => serde_json::Value::Null,
47
- FieldValue::Bool(b) => serde_json::Value::Bool(*b),
48
- FieldValue::Int(n) => serde_json::Value::Number((*n).into()),
49
- FieldValue::Float(f) => serde_json::Number::from_f64(*f)
50
- .map(serde_json::Value::Number)
51
- .unwrap_or(serde_json::Value::Null),
52
- FieldValue::String(s) => serde_json::Value::String(s.clone()),
53
- }
54
- }
55
-
56
- pub fn write_json(&self, out: &mut String) {
57
- match self {
58
- FieldValue::Null => out.push_str("null"),
59
- FieldValue::Bool(true) => out.push_str("true"),
60
- FieldValue::Bool(false) => out.push_str("false"),
61
- FieldValue::Int(n) => {
62
- out.push_str(itoa::Buffer::new().format(*n));
63
- }
64
- FieldValue::Float(f) => {
65
- out.push_str(ryu::Buffer::new().format_finite(*f));
66
- }
67
- FieldValue::String(s) => {
68
- write_json_string(out, s);
69
- }
70
- }
71
- }
72
-
73
- pub fn eq_json(&self, jv: &serde_json::Value) -> bool {
74
- match (self, jv) {
75
- (FieldValue::Null, serde_json::Value::Null) => true,
76
- (FieldValue::Bool(a), serde_json::Value::Bool(b)) => a == b,
77
- (FieldValue::Int(a), serde_json::Value::Number(n)) => n.as_i64() == Some(*a),
78
- (FieldValue::Float(a), serde_json::Value::Number(n)) => n.as_f64() == Some(*a),
79
- (FieldValue::String(a), serde_json::Value::String(b)) => a == b,
80
- _ => false,
81
- }
82
- }
83
- }
84
-
85
- #[derive(Debug, Clone)]
86
- pub struct RowStore {
87
- pub id: u64,
88
- pub values_start: usize,
89
- pub num_values: usize,
90
- pub created_at: u64,
91
- pub updated_at: u64,
92
- }
93
-
94
- #[derive(Debug, Clone)]
95
- pub struct Table {
96
- pub name: String,
97
- pub schema: HashMap<String, FieldSchema>,
98
- pub field_order: Vec<String>,
99
- pub field_index: HashMap<String, usize>,
100
- pub rows: Vec<RowStore>,
101
- pub values: Vec<FieldValue>,
102
- pub next_id: u64,
103
- pub pk_field: Option<String>,
104
- pub pk_index: FxHashMap<u64, usize>,
105
- }
106
-
107
- pub fn default_value(ft: &FieldType) -> FieldValue {
108
- match ft {
109
- FieldType::Integer => FieldValue::Int(0),
110
- FieldType::Float => FieldValue::Float(0.0),
111
- FieldType::String => FieldValue::String(String::new()),
112
- FieldType::Boolean => FieldValue::Bool(false),
113
- }
114
- }
115
-
116
- fn now_millis() -> u64 {
117
- #[cfg(feature = "wasm")]
118
- {
119
- js_sys::Date::now() as u64
120
- }
121
- #[cfg(not(feature = "wasm"))]
122
- {
123
- std::time::SystemTime::now()
124
- .duration_since(std::time::UNIX_EPOCH)
125
- .unwrap_or_default()
126
- .as_millis() as u64
127
- }
128
- }
129
-
130
- fn write_json_string(out: &mut String, s: &str) {
131
- out.push('"');
132
- for c in s.chars() {
133
- match c {
134
- '"' => out.push_str("\\\""),
135
- '\\' => out.push_str("\\\\"),
136
- '\n' => out.push_str("\\n"),
137
- '\r' => out.push_str("\\r"),
138
- '\t' => out.push_str("\\t"),
139
- c if c.is_control() => {
140
- write!(out, "\\u{:04x}", c as u32).unwrap();
141
- }
142
- c => out.push(c),
143
- }
144
- }
145
- out.push('"');
146
- }
147
-
148
- fn millis_to_string(ms: u64) -> String {
149
- #[cfg(feature = "wasm")]
150
- {
151
- let d = js_sys::Date::new(&wasm_bindgen::JsValue::from_f64(ms as f64));
152
- d.to_iso_string().as_string().unwrap_or_else(|| "2026-01-01T00:00:00Z".into())
153
- }
154
- #[cfg(not(feature = "wasm"))]
155
- {
156
- let secs = ms / 1000;
157
- let nanos = ((ms % 1000) * 1_000_000) as u32;
158
- let dt = chrono::DateTime::from_timestamp(secs as i64, nanos)
159
- .unwrap_or_default();
160
- dt.to_rfc3339()
161
- }
162
- }
163
-
164
- impl Table {
165
- pub fn new(name: String, schema: &[(String, FieldSchema)]) -> Self {
166
- let pk_field = schema.iter()
167
- .find(|(_, f)| f.primary_key)
168
- .map(|(name, _)| name.clone());
169
-
170
- let field_order: Vec<String> = schema.iter().map(|(n, _)| n.clone()).collect();
171
- let field_index: HashMap<String, usize> = field_order.iter()
172
- .enumerate().map(|(i, n)| (n.clone(), i)).collect();
173
- let schema: HashMap<String, FieldSchema> = schema.iter()
174
- .map(|(k, v)| (k.clone(), v.clone())).collect();
175
-
176
- Self {
177
- name, schema, field_order, field_index,
178
- rows: Vec::new(), values: Vec::new(), next_id: 1, pk_field,
179
- pk_index: FxHashMap::default(),
180
- }
181
- }
182
-
183
- pub fn to_row_map(&self, values: &[FieldValue]) -> HashMap<String, serde_json::Value> {
184
- let mut map = HashMap::with_capacity(self.field_order.len());
185
- for (i, name) in self.field_order.iter().enumerate() {
186
- if let Some(v) = values.get(i) {
187
- map.insert(name.clone(), v.to_json());
188
- }
189
- }
190
- map
191
- }
192
-
193
- pub fn push_row_values(&mut self, id: u64, values: Vec<FieldValue>, now: u64) {
194
- let num_values = values.len();
195
- let values_start = self.values.len();
196
- self.values.extend(values);
197
- self.rows.push(RowStore { id, values_start, num_values, created_at: now, updated_at: now });
198
- }
199
-
200
- pub fn get_row_values(&self, rs: &RowStore) -> &[FieldValue] {
201
- &self.values[rs.values_start..][..rs.num_values]
202
- }
203
-
204
- pub fn get_row_values_mut(&mut self, rs: &RowStore) -> &mut [FieldValue] {
205
- let start = rs.values_start;
206
- &mut self.values[start..][..rs.num_values]
207
- }
208
-
209
- fn to_row(&self, rs: &RowStore) -> Row {
210
- Row {
211
- id: rs.id,
212
- fields: self.to_row_map(self.get_row_values(rs)),
213
- created_at: Some(millis_to_string(rs.created_at)),
214
- updated_at: Some(millis_to_string(rs.updated_at)),
215
- }
216
- }
217
-
218
- pub fn add_rows(&mut self, fields_batch: Vec<HashMap<String, serde_json::Value>>) -> Vec<u64> {
219
- let now = now_millis();
220
- let batch_len = fields_batch.len();
221
- let mut ids = Vec::with_capacity(batch_len);
222
- self.pk_index.reserve(batch_len);
223
- self.rows.reserve(batch_len);
224
- self.values.reserve(batch_len * self.field_order.len());
225
-
226
- let pk_auto_key = self.pk_field.as_deref().and_then(|pk| {
227
- self.schema.get(pk).and_then(|fs| {
228
- if fs.auto_increment { Some(pk.to_string()) } else { None }
229
- })
230
- });
231
-
232
- for mut fields in fields_batch {
233
- let auto_id = self.next_id;
234
- self.next_id += 1;
235
- let mut id = auto_id;
236
-
237
- if let Some(ref pk_key) = pk_auto_key {
238
- match fields.get(pk_key) {
239
- Some(v) if v.is_null() => {
240
- fields.insert(pk_key.clone(), serde_json::Value::Number(auto_id.into()));
241
- }
242
- Some(v) => {
243
- if let Some(n) = v.as_i64() {
244
- if n > 0 {
245
- id = n as u64;
246
- self.next_id = self.next_id.max(id + 1);
247
- }
248
- }
249
- }
250
- None => {
251
- fields.insert(pk_key.clone(), serde_json::Value::Number(auto_id.into()));
252
- }
253
- }
254
- }
255
-
256
- let values_start = self.values.len();
257
- if fields.len() < self.schema.len() {
258
- for name in &self.field_order {
259
- if let Some(v) = fields.remove(name) {
260
- self.values.push(FieldValue::from_json(v));
261
- continue;
262
- }
263
- match self.schema.get(name).and_then(|fs| fs.default.clone()) {
264
- Some(dv) => self.values.push(FieldValue::from_json(dv)),
265
- None => {
266
- if let Some(fs) = self.schema.get(name) {
267
- if !fs.nullable {
268
- self.values.push(default_value(&fs.field_type));
269
- } else {
270
- self.values.push(FieldValue::Null);
271
- }
272
- } else {
273
- self.values.push(FieldValue::Null);
274
- }
275
- }
276
- }
277
- }
278
- } else {
279
- for name in &self.field_order {
280
- self.values.push(fields.remove(name).map(FieldValue::from_json).unwrap_or(FieldValue::Null));
281
- }
282
- }
283
-
284
- let idx = self.rows.len();
285
- self.pk_index.insert(id, idx);
286
- self.rows.push(RowStore { id, values_start, num_values: self.field_order.len(), created_at: now, updated_at: now });
287
- ids.push(id);
288
- }
289
- ids
290
- }
291
-
292
- pub fn add_rows_vec(&mut self, field_names: &[String], batch: Vec<Vec<serde_json::Value>>) -> Vec<u64> {
293
- let batch_fv: Vec<Vec<FieldValue>> = batch.into_iter()
294
- .map(|row| row.into_iter().map(FieldValue::from_json).collect())
295
- .collect();
296
- self.add_rows_vec_fv(field_names, batch_fv)
297
- }
298
-
299
- pub fn add_rows_vec_fv(&mut self, field_names: &[String], batch: Vec<Vec<FieldValue>>) -> Vec<u64> {
300
- let now = now_millis();
301
- let batch_len = batch.len();
302
- let mut ids = Vec::with_capacity(batch_len);
303
- self.pk_index.reserve(batch_len);
304
- self.rows.reserve(batch_len);
305
- self.values.reserve(batch_len * self.field_order.len());
306
-
307
- let pk_auto_key = self.pk_field.as_deref().and_then(|pk| {
308
- self.schema.get(pk).and_then(|fs| {
309
- if fs.auto_increment { Some(pk.to_string()) } else { None }
310
- })
311
- });
312
-
313
- // fast path: field_names match field_order
314
- if field_names.len() == self.field_order.len()
315
- && field_names.iter().zip(&self.field_order).all(|(a, b)| a == b)
316
- {
317
- let pk_idx = pk_auto_key.as_ref().and_then(|pk| self.field_index.get(pk.as_str()).copied());
318
- for mut row_vals in batch {
319
- let auto_id = self.next_id;
320
- self.next_id += 1;
321
- let mut id = auto_id;
322
- if row_vals.len() < self.field_order.len() {
323
- row_vals.resize(self.field_order.len(), FieldValue::Null);
324
- }
325
- if let Some(pi) = pk_idx {
326
- if pi < row_vals.len() {
327
- match row_vals[pi] {
328
- FieldValue::Null => row_vals[pi] = FieldValue::Int(auto_id as i64),
329
- FieldValue::Int(e) if e > 0 => {
330
- id = e as u64;
331
- self.next_id = self.next_id.max(id + 1);
332
- }
333
- _ => {}
334
- }
335
- }
336
- }
337
- let values_start = self.values.len();
338
- self.values.append(&mut row_vals);
339
- let idx = self.rows.len();
340
- self.pk_index.insert(id, idx);
341
- self.rows.push(RowStore { id, values_start, num_values: self.field_order.len(), created_at: now, updated_at: now });
342
- ids.push(id);
343
- }
344
- return ids;
345
- }
346
-
347
- // slow path: remap field names
348
- let remap: Vec<Option<usize>> = self.field_order.iter()
349
- .map(|name| field_names.iter().position(|fname| fname == name))
350
- .collect();
351
- let explicit_pk_si = pk_auto_key.as_ref()
352
- .and_then(|pk| field_names.iter().position(|n| n == pk));
353
- let pk_idx = pk_auto_key.as_ref().and_then(|pk| self.field_index.get(pk.as_str()).copied());
354
-
355
- for mut row_vals in batch {
356
- let auto_id = self.next_id;
357
- self.next_id += 1;
358
- let mut id = auto_id;
359
- if let Some(si) = explicit_pk_si {
360
- if let Some(FieldValue::Int(e)) = row_vals.get(si) {
361
- if *e > 0 {
362
- id = *e as u64;
363
- self.next_id = self.next_id.max(id + 1);
364
- }
365
- }
366
- }
367
- let values_start = self.values.len();
368
- for (i, remapped_si) in remap.iter().enumerate() {
369
- if let Some(si) = *remapped_si {
370
- if si < row_vals.len() {
371
- self.values.push(std::mem::take(&mut row_vals[si]));
372
- continue;
373
- }
374
- }
375
- if let Some(ref pk_key) = pk_auto_key {
376
- if self.field_order[i] == *pk_key {
377
- self.values.push(FieldValue::Int(id as i64));
378
- continue;
379
- }
380
- }
381
- if let Some(name) = self.field_order.get(i) {
382
- if let Some(fs) = self.schema.get(name) {
383
- if let Some(ref default) = fs.default {
384
- self.values.push(FieldValue::from_json(default.clone()));
385
- } else if !fs.nullable {
386
- self.values.push(default_value(&fs.field_type));
387
- } else {
388
- self.values.push(FieldValue::Null);
389
- }
390
- } else {
391
- self.values.push(FieldValue::Null);
392
- }
393
- }
394
- }
395
- // 显式传入 null 的主键:回填自动 id,保证 pk 值与行 id 一致
396
- if let Some(pi) = pk_idx {
397
- if let Some(v) = self.values.get_mut(values_start + pi) {
398
- if *v == FieldValue::Null {
399
- *v = FieldValue::Int(id as i64);
400
- }
401
- }
402
- }
403
- let idx = self.rows.len();
404
- self.pk_index.insert(id, idx);
405
- self.rows.push(RowStore { id, values_start, num_values: self.field_order.len(), created_at: now, updated_at: now });
406
- ids.push(id);
407
- }
408
- ids
409
- }
410
-
411
- pub fn row_matches(&self, r: &RowStore, filter: &HashMap<String, serde_json::Value>) -> bool {
412
- let vals = self.get_row_values(r);
413
- filter.iter().all(|(k, v)| {
414
- self.field_index.get(k)
415
- .and_then(|&pos| vals.get(pos))
416
- .map_or(false, |fv| fv.eq_json(v))
417
- })
418
- }
419
-
420
- pub fn get_row(&self, id: u64) -> Option<Row> {
421
- let idx = *self.pk_index.get(&id)?;
422
- self.rows.get(idx).map(|r| self.to_row(r))
423
- }
424
-
425
- pub fn get_row_json(&self, id: u64) -> Option<String> {
426
- let idx = *self.pk_index.get(&id)?;
427
- self.rows.get(idx).map(|r| self.to_row_json_string(r))
428
- }
429
-
430
- pub fn get_rows_json(&self, ids: &[u64]) -> String {
431
- let mut out = String::with_capacity(ids.len() * 128);
432
- out.push('[');
433
- let mut first = true;
434
- for &id in ids {
435
- if let Some(&idx) = self.pk_index.get(&id) {
436
- if let Some(rs) = self.rows.get(idx) {
437
- if !first { out.push(','); }
438
- first = false;
439
- out.push_str(&self.to_row_json_string(rs));
440
- }
441
- }
442
- }
443
- out.push(']');
444
- out
445
- }
446
-
447
- fn to_row_json_compact(&self, rs: &RowStore) -> String {
448
- let vals = self.get_row_values(rs);
449
- let mut out = String::with_capacity(64);
450
- out.push('[');
451
- out.push_str(itoa::Buffer::new().format(rs.id));
452
- for v in vals {
453
- out.push(',');
454
- v.write_json(&mut out);
455
- }
456
- out.push(']');
457
- out
458
- }
459
-
460
- fn to_row_json_string(&self, rs: &RowStore) -> String {
461
- let vals = self.get_row_values(rs);
462
- let mut out = String::with_capacity(160);
463
- out.push_str(r#"{"id":"#);
464
- out.push_str(itoa::Buffer::new().format(rs.id));
465
- out.push_str(r#","fields":{"#);
466
- for (i, name) in self.field_order.iter().enumerate() {
467
- if i > 0 { out.push(','); }
468
- write_json_string(&mut out, name);
469
- out.push(':');
470
- if let Some(v) = vals.get(i) {
471
- v.write_json(&mut out);
472
- } else {
473
- out.push_str("null");
474
- }
475
- }
476
- out.push_str(r#"},"created_at":"#);
477
- write_json_string(&mut out, &millis_to_string(rs.created_at));
478
- out.push_str(r#","updated_at":"#);
479
- write_json_string(&mut out, &millis_to_string(rs.updated_at));
480
- out.push_str("}");
481
- out
482
- }
483
-
484
- pub fn update_row(&mut self, id: u64, data: HashMap<String, serde_json::Value>) -> bool {
485
- let idx = match self.pk_index.get(&id) {
486
- Some(i) => *i,
487
- None => return false,
488
- };
489
- // Use raw index access to update values without borrow conflicts
490
- if idx < self.rows.len() {
491
- let row = &mut self.rows[idx];
492
- let nv = row.num_values;
493
- let s = row.values_start;
494
- for (k, v) in data {
495
- if let Some(&pos) = self.field_index.get(&k) {
496
- if pos < nv {
497
- self.values[s + pos] = FieldValue::from_json(v);
498
- }
499
- }
500
- }
501
- self.rows[idx].updated_at = now_millis();
502
- true
503
- } else {
504
- false
505
- }
506
- }
507
-
508
- pub fn update_rows(&mut self, batch: Vec<(u64, HashMap<String, serde_json::Value>)>) -> usize {
509
- let mut count = 0;
510
- let now = now_millis();
511
- for (id, data) in batch {
512
- if let Some(&idx) = self.pk_index.get(&id) {
513
- if idx < self.rows.len() {
514
- let row = &mut self.rows[idx];
515
- let nv = row.num_values;
516
- let s = row.values_start;
517
- for (k, v) in data {
518
- if let Some(&pos) = self.field_index.get(&k) {
519
- if pos < nv {
520
- self.values[s + pos] = FieldValue::from_json(v);
521
- }
522
- }
523
- }
524
- self.rows[idx].updated_at = now;
525
- count += 1;
526
- }
527
- }
528
- }
529
- count
530
- }
531
-
532
- pub fn remove_row(&mut self, id: u64) -> bool {
533
- let idx = match self.pk_index.get(&id) {
534
- Some(i) => *i,
535
- None => return false,
536
- };
537
- self.pk_index.remove(&id);
538
- let last = self.rows.len() - 1;
539
- if idx != last {
540
- self.pk_index.insert(self.rows[last].id, idx);
541
- }
542
- self.rows.swap_remove(idx);
543
- true
544
- }
545
-
546
- pub fn remove_rows(&mut self, ids: &[u64]) -> usize {
547
- let mut count = 0;
548
- let mut indices: Vec<(usize, u64)> = Vec::with_capacity(ids.len());
549
- for &id in ids {
550
- if let Some(&idx) = self.pk_index.get(&id) {
551
- indices.push((idx, id));
552
- count += 1;
553
- }
554
- }
555
- indices.sort_unstable_by(|a, b| b.0.cmp(&a.0));
556
- for (idx, id) in indices {
557
- self.pk_index.remove(&id);
558
- let last = self.rows.len() - 1;
559
- if idx != last {
560
- self.pk_index.insert(self.rows[last].id, idx);
561
- }
562
- self.rows.swap_remove(idx);
563
- }
564
- count
565
- }
566
-
567
- pub fn remove_row_by_idx(&mut self, idx: usize) {
568
- let last = self.rows.len() - 1;
569
- if idx < last {
570
- let swapped_id = self.rows[last].id;
571
- self.pk_index.insert(swapped_id, idx);
572
- }
573
- self.pk_index.remove(&self.rows[idx].id);
574
- self.rows.swap_remove(idx);
575
- }
576
-
577
- pub fn count(&self) -> usize {
578
- self.rows.len()
579
- }
580
-
581
- // ============================================================
582
- // 磁盘持久化导出 / 导入(供 HybridEngine 使用)
583
- // ============================================================
584
-
585
- pub fn export_all(&self) -> String {
586
- let mut out = String::with_capacity(64 + self.rows.len() * 96);
587
- out.push_str(r#"{"next_id":"#);
588
- out.push_str(itoa::Buffer::new().format(self.next_id));
589
- out.push_str(r#","rows":["#);
590
- for (i, rs) in self.rows.iter().enumerate() {
591
- if i > 0 { out.push(','); }
592
- out.push_str(r#"{"id":"#);
593
- out.push_str(itoa::Buffer::new().format(rs.id));
594
- out.push_str(r#","created_at":"#);
595
- out.push_str(itoa::Buffer::new().format(rs.created_at));
596
- out.push_str(r#","updated_at":"#);
597
- out.push_str(itoa::Buffer::new().format(rs.updated_at));
598
- out.push_str(r#","fields":{"#);
599
- let vals = self.get_row_values(rs);
600
- for (fi, name) in self.field_order.iter().enumerate() {
601
- if fi > 0 { out.push(','); }
602
- write_json_string(&mut out, name);
603
- out.push(':');
604
- if let Some(v) = vals.get(fi) {
605
- v.write_json(&mut out);
606
- } else {
607
- out.push_str("null");
608
- }
609
- }
610
- out.push_str("}}");
611
- }
612
- out.push_str("]}");
613
- out
614
- }
615
-
616
- pub fn import_from_json(&mut self, json: &str) -> Result<(), String> {
617
- let parsed: serde_json::Value = serde_json::from_str(json)
618
- .map_err(|e| format!("invalid table file: {}", e))?;
619
- let next_id = parsed.get("next_id").and_then(|v| v.as_u64()).unwrap_or(1);
620
- self.next_id = next_id;
621
- let rows = parsed.get("rows").and_then(|v| v.as_array()).ok_or("table file missing rows")?;
622
- let pk_auto_key = self.pk_field.as_deref().and_then(|pk| {
623
- self.schema.get(pk).and_then(|fs| if fs.auto_increment { Some(pk.to_string()) } else { None })
624
- });
625
- self.rows.reserve(rows.len());
626
- self.values.reserve(rows.len() * self.field_order.len());
627
- self.pk_index.reserve(rows.len());
628
- for rv in rows {
629
- let id = rv.get("id").and_then(|v| v.as_u64()).ok_or("row missing id")?;
630
- let created_at = rv.get("created_at").and_then(|v| v.as_u64()).unwrap_or_else(now_millis);
631
- let updated_at = rv.get("updated_at").and_then(|v| v.as_u64()).unwrap_or(created_at);
632
- let fields = rv.get("fields").and_then(|v| v.as_object()).ok_or("row missing fields")?;
633
- let values_start = self.values.len();
634
- for name in &self.field_order {
635
- if let Some(jv) = fields.get(name) {
636
- self.values.push(FieldValue::from_json(jv.clone()));
637
- } else if let Some(ref pk_key) = pk_auto_key {
638
- if *pk_key == *name {
639
- self.values.push(FieldValue::Int(id as i64));
640
- } else {
641
- self.values.push(FieldValue::Null);
642
- }
643
- } else {
644
- self.values.push(FieldValue::Null);
645
- }
646
- }
647
- let idx = self.rows.len();
648
- self.pk_index.insert(id, idx);
649
- self.rows.push(RowStore { id, values_start, num_values: self.field_order.len(), created_at, updated_at });
650
- }
651
- Ok(())
652
- }
653
-
654
- pub fn find_rows(&self, filter: &Option<HashMap<String, serde_json::Value>>,
655
- limit: Option<usize>, offset: Option<usize>,
656
- order_by: &Option<String>, order: &Option<String>) -> Vec<Row> {
657
- let mut results: Vec<&RowStore> = self.rows.iter().collect();
658
-
659
- if let Some(ref f) = filter {
660
- let filter_indices: Vec<(usize, &serde_json::Value)> = f.iter()
661
- .filter_map(|(k, v)| self.field_index.get(k).map(|&pos| (pos, v)))
662
- .collect();
663
- results.retain(|r| {
664
- let vals = self.get_row_values(r);
665
- filter_indices.iter().all(|(pos, v)| {
666
- vals.get(*pos).map_or(false, |fv| fv.eq_json(v))
667
- })
668
- });
669
- }
670
-
671
- if let Some(ref field) = order_by {
672
- let desc = order.as_deref() == Some("desc");
673
- if let Some(&pos) = self.field_index.get(field) {
674
- results.sort_by(|a, b| {
675
- let vals_a = self.get_row_values(a);
676
- let vals_b = self.get_row_values(b);
677
- let cmp = cmp_field_values(vals_a.get(pos), vals_b.get(pos));
678
- if desc { cmp.reverse() } else { cmp }
679
- });
680
- }
681
- }
682
-
683
- let o = offset.unwrap_or(0);
684
- let l = limit.unwrap_or(usize::MAX);
685
- results.into_iter().skip(o).take(l).map(|r| self.to_row(r)).collect()
686
- }
687
- }
688
-
689
- fn cmp_field_values(a: Option<&FieldValue>, b: Option<&FieldValue>) -> std::cmp::Ordering {
690
- match (a, b) {
691
- (Some(FieldValue::Int(na)), Some(FieldValue::Int(nb))) => na.cmp(nb),
692
- (Some(FieldValue::Float(na)), Some(FieldValue::Float(nb))) => na.partial_cmp(nb).unwrap_or(std::cmp::Ordering::Equal),
693
- (Some(FieldValue::String(sa)), Some(FieldValue::String(sb))) => sa.cmp(sb),
694
- (Some(FieldValue::Bool(ba)), Some(FieldValue::Bool(bb))) => ba.cmp(bb),
695
- (Some(a), Some(b)) => format!("{:?}", a).cmp(&format!("{:?}", b)),
696
- (Some(_), None) => std::cmp::Ordering::Greater,
697
- (None, Some(_)) => std::cmp::Ordering::Less,
698
- (None, None) => std::cmp::Ordering::Equal,
699
- }
700
- }
1
+ use std::collections::HashMap;
2
+ use rustc_hash::FxHashMap;
3
+ use serde::Serialize;
4
+ use crate::types::{Row, FieldSchema, FieldType};
5
+ use std::fmt::Write;
6
+
7
+ #[derive(Debug, Clone, PartialEq, Default)]
8
+ pub enum FieldValue {
9
+ #[default]
10
+ Null,
11
+ Bool(bool),
12
+ Int(i64),
13
+ Float(f64),
14
+ String(String),
15
+ }
16
+
17
+ impl serde::Serialize for FieldValue {
18
+ fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
19
+ match self {
20
+ FieldValue::Null => s.serialize_unit(),
21
+ FieldValue::Bool(b) => s.serialize_bool(*b),
22
+ FieldValue::Int(n) => s.serialize_i64(*n),
23
+ FieldValue::Float(f) => s.serialize_f64(*f),
24
+ FieldValue::String(st) => s.serialize_str(st),
25
+ }
26
+ }
27
+ }
28
+
29
+ impl FieldValue {
30
+ pub fn from_json(jv: serde_json::Value) -> Self {
31
+ match jv {
32
+ serde_json::Value::Null => FieldValue::Null,
33
+ serde_json::Value::Bool(b) => FieldValue::Bool(b),
34
+ serde_json::Value::Number(n) => {
35
+ n.as_i64().map(FieldValue::Int)
36
+ .or_else(|| n.as_f64().map(FieldValue::Float))
37
+ .unwrap_or(FieldValue::Null)
38
+ }
39
+ serde_json::Value::String(s) => FieldValue::String(s),
40
+ _ => FieldValue::Null,
41
+ }
42
+ }
43
+
44
+ fn to_json(&self) -> serde_json::Value {
45
+ match self {
46
+ FieldValue::Null => serde_json::Value::Null,
47
+ FieldValue::Bool(b) => serde_json::Value::Bool(*b),
48
+ FieldValue::Int(n) => serde_json::Value::Number((*n).into()),
49
+ FieldValue::Float(f) => serde_json::Number::from_f64(*f)
50
+ .map(serde_json::Value::Number)
51
+ .unwrap_or(serde_json::Value::Null),
52
+ FieldValue::String(s) => serde_json::Value::String(s.clone()),
53
+ }
54
+ }
55
+
56
+ pub fn write_json(&self, out: &mut String) {
57
+ match self {
58
+ FieldValue::Null => out.push_str("null"),
59
+ FieldValue::Bool(true) => out.push_str("true"),
60
+ FieldValue::Bool(false) => out.push_str("false"),
61
+ FieldValue::Int(n) => {
62
+ out.push_str(itoa::Buffer::new().format(*n));
63
+ }
64
+ FieldValue::Float(f) => {
65
+ out.push_str(ryu::Buffer::new().format_finite(*f));
66
+ }
67
+ FieldValue::String(s) => {
68
+ write_json_string(out, s);
69
+ }
70
+ }
71
+ }
72
+
73
+ pub fn eq_json(&self, jv: &serde_json::Value) -> bool {
74
+ match (self, jv) {
75
+ (FieldValue::Null, serde_json::Value::Null) => true,
76
+ (FieldValue::Bool(a), serde_json::Value::Bool(b)) => a == b,
77
+ (FieldValue::Int(a), serde_json::Value::Number(n)) => n.as_i64() == Some(*a),
78
+ (FieldValue::Float(a), serde_json::Value::Number(n)) => n.as_f64() == Some(*a),
79
+ (FieldValue::String(a), serde_json::Value::String(b)) => a == b,
80
+ _ => false,
81
+ }
82
+ }
83
+ }
84
+
85
+ #[derive(Debug, Clone)]
86
+ pub struct RowStore {
87
+ pub id: u64,
88
+ pub values_start: usize,
89
+ pub num_values: usize,
90
+ pub created_at: u64,
91
+ pub updated_at: u64,
92
+ }
93
+
94
+ #[derive(Debug, Clone)]
95
+ pub struct Table {
96
+ pub name: String,
97
+ pub schema: HashMap<String, FieldSchema>,
98
+ pub field_order: Vec<String>,
99
+ pub field_index: HashMap<String, usize>,
100
+ pub rows: Vec<RowStore>,
101
+ pub values: Vec<FieldValue>,
102
+ pub next_id: u64,
103
+ pub pk_field: Option<String>,
104
+ pub pk_index: FxHashMap<u64, usize>,
105
+ }
106
+
107
+ pub fn default_value(ft: &FieldType) -> FieldValue {
108
+ match ft {
109
+ FieldType::Integer => FieldValue::Int(0),
110
+ FieldType::Float => FieldValue::Float(0.0),
111
+ FieldType::String => FieldValue::String(String::new()),
112
+ FieldType::Boolean => FieldValue::Bool(false),
113
+ }
114
+ }
115
+
116
+ fn now_millis() -> u64 {
117
+ #[cfg(feature = "wasm")]
118
+ {
119
+ js_sys::Date::now() as u64
120
+ }
121
+ #[cfg(not(feature = "wasm"))]
122
+ {
123
+ std::time::SystemTime::now()
124
+ .duration_since(std::time::UNIX_EPOCH)
125
+ .unwrap_or_default()
126
+ .as_millis() as u64
127
+ }
128
+ }
129
+
130
+ fn write_json_string(out: &mut String, s: &str) {
131
+ out.push('"');
132
+ for c in s.chars() {
133
+ match c {
134
+ '"' => out.push_str("\\\""),
135
+ '\\' => out.push_str("\\\\"),
136
+ '\n' => out.push_str("\\n"),
137
+ '\r' => out.push_str("\\r"),
138
+ '\t' => out.push_str("\\t"),
139
+ c if c.is_control() => {
140
+ write!(out, "\\u{:04x}", c as u32).unwrap();
141
+ }
142
+ c => out.push(c),
143
+ }
144
+ }
145
+ out.push('"');
146
+ }
147
+
148
+ fn millis_to_string(ms: u64) -> String {
149
+ #[cfg(feature = "wasm")]
150
+ {
151
+ let d = js_sys::Date::new(&wasm_bindgen::JsValue::from_f64(ms as f64));
152
+ d.to_iso_string().as_string().unwrap_or_else(|| "2026-01-01T00:00:00Z".into())
153
+ }
154
+ #[cfg(not(feature = "wasm"))]
155
+ {
156
+ let secs = ms / 1000;
157
+ let nanos = ((ms % 1000) * 1_000_000) as u32;
158
+ let dt = chrono::DateTime::from_timestamp(secs as i64, nanos)
159
+ .unwrap_or_default();
160
+ dt.to_rfc3339()
161
+ }
162
+ }
163
+
164
+ impl Table {
165
+ pub fn new(name: String, schema: &[(String, FieldSchema)]) -> Self {
166
+ let pk_field = schema.iter()
167
+ .find(|(_, f)| f.primary_key)
168
+ .map(|(name, _)| name.clone());
169
+
170
+ let field_order: Vec<String> = schema.iter().map(|(n, _)| n.clone()).collect();
171
+ let field_index: HashMap<String, usize> = field_order.iter()
172
+ .enumerate().map(|(i, n)| (n.clone(), i)).collect();
173
+ let schema: HashMap<String, FieldSchema> = schema.iter()
174
+ .map(|(k, v)| (k.clone(), v.clone())).collect();
175
+
176
+ Self {
177
+ name, schema, field_order, field_index,
178
+ rows: Vec::new(), values: Vec::new(), next_id: 1, pk_field,
179
+ pk_index: FxHashMap::default(),
180
+ }
181
+ }
182
+
183
+ pub fn to_row_map(&self, values: &[FieldValue]) -> HashMap<String, serde_json::Value> {
184
+ let mut map = HashMap::with_capacity(self.field_order.len());
185
+ for (i, name) in self.field_order.iter().enumerate() {
186
+ if let Some(v) = values.get(i) {
187
+ map.insert(name.clone(), v.to_json());
188
+ }
189
+ }
190
+ map
191
+ }
192
+
193
+ pub fn push_row_values(&mut self, id: u64, values: Vec<FieldValue>, now: u64) {
194
+ let num_values = values.len();
195
+ let values_start = self.values.len();
196
+ self.values.extend(values);
197
+ self.rows.push(RowStore { id, values_start, num_values, created_at: now, updated_at: now });
198
+ }
199
+
200
+ pub fn get_row_values(&self, rs: &RowStore) -> &[FieldValue] {
201
+ &self.values[rs.values_start..][..rs.num_values]
202
+ }
203
+
204
+ pub fn get_row_values_mut(&mut self, rs: &RowStore) -> &mut [FieldValue] {
205
+ let start = rs.values_start;
206
+ &mut self.values[start..][..rs.num_values]
207
+ }
208
+
209
+ fn to_row(&self, rs: &RowStore) -> Row {
210
+ Row {
211
+ id: rs.id,
212
+ fields: self.to_row_map(self.get_row_values(rs)),
213
+ created_at: Some(millis_to_string(rs.created_at)),
214
+ updated_at: Some(millis_to_string(rs.updated_at)),
215
+ }
216
+ }
217
+
218
+ pub fn add_rows(&mut self, fields_batch: Vec<HashMap<String, serde_json::Value>>) -> Vec<u64> {
219
+ let now = now_millis();
220
+ let batch_len = fields_batch.len();
221
+ let mut ids = Vec::with_capacity(batch_len);
222
+ self.pk_index.reserve(batch_len);
223
+ self.rows.reserve(batch_len);
224
+ self.values.reserve(batch_len * self.field_order.len());
225
+
226
+ let pk_auto_key = self.pk_field.as_deref().and_then(|pk| {
227
+ self.schema.get(pk).and_then(|fs| {
228
+ if fs.auto_increment { Some(pk.to_string()) } else { None }
229
+ })
230
+ });
231
+
232
+ for mut fields in fields_batch {
233
+ let auto_id = self.next_id;
234
+ self.next_id += 1;
235
+ let mut id = auto_id;
236
+
237
+ if let Some(ref pk_key) = pk_auto_key {
238
+ match fields.get(pk_key) {
239
+ Some(v) if v.is_null() => {
240
+ fields.insert(pk_key.clone(), serde_json::Value::Number(auto_id.into()));
241
+ }
242
+ Some(v) => {
243
+ if let Some(n) = v.as_i64() {
244
+ if n > 0 {
245
+ id = n as u64;
246
+ self.next_id = self.next_id.max(id + 1);
247
+ }
248
+ }
249
+ }
250
+ None => {
251
+ fields.insert(pk_key.clone(), serde_json::Value::Number(auto_id.into()));
252
+ }
253
+ }
254
+ }
255
+
256
+ let values_start = self.values.len();
257
+ if fields.len() < self.schema.len() {
258
+ for name in &self.field_order {
259
+ if let Some(v) = fields.remove(name) {
260
+ self.values.push(FieldValue::from_json(v));
261
+ continue;
262
+ }
263
+ match self.schema.get(name).and_then(|fs| fs.default.clone()) {
264
+ Some(dv) => self.values.push(FieldValue::from_json(dv)),
265
+ None => {
266
+ if let Some(fs) = self.schema.get(name) {
267
+ if !fs.nullable {
268
+ self.values.push(default_value(&fs.field_type));
269
+ } else {
270
+ self.values.push(FieldValue::Null);
271
+ }
272
+ } else {
273
+ self.values.push(FieldValue::Null);
274
+ }
275
+ }
276
+ }
277
+ }
278
+ } else {
279
+ for name in &self.field_order {
280
+ self.values.push(fields.remove(name).map(FieldValue::from_json).unwrap_or(FieldValue::Null));
281
+ }
282
+ }
283
+
284
+ let idx = self.rows.len();
285
+ self.pk_index.insert(id, idx);
286
+ self.rows.push(RowStore { id, values_start, num_values: self.field_order.len(), created_at: now, updated_at: now });
287
+ ids.push(id);
288
+ }
289
+ ids
290
+ }
291
+
292
+ pub fn add_rows_vec(&mut self, field_names: &[String], batch: Vec<Vec<serde_json::Value>>) -> Vec<u64> {
293
+ let batch_fv: Vec<Vec<FieldValue>> = batch.into_iter()
294
+ .map(|row| row.into_iter().map(FieldValue::from_json).collect())
295
+ .collect();
296
+ self.add_rows_vec_fv(field_names, batch_fv)
297
+ }
298
+
299
+ pub fn add_rows_vec_fv(&mut self, field_names: &[String], batch: Vec<Vec<FieldValue>>) -> Vec<u64> {
300
+ let now = now_millis();
301
+ let batch_len = batch.len();
302
+ let mut ids = Vec::with_capacity(batch_len);
303
+ self.pk_index.reserve(batch_len);
304
+ self.rows.reserve(batch_len);
305
+ self.values.reserve(batch_len * self.field_order.len());
306
+
307
+ let pk_auto_key = self.pk_field.as_deref().and_then(|pk| {
308
+ self.schema.get(pk).and_then(|fs| {
309
+ if fs.auto_increment { Some(pk.to_string()) } else { None }
310
+ })
311
+ });
312
+
313
+ // fast path: field_names match field_order
314
+ if field_names.len() == self.field_order.len()
315
+ && field_names.iter().zip(&self.field_order).all(|(a, b)| a == b)
316
+ {
317
+ let pk_idx = pk_auto_key.as_ref().and_then(|pk| self.field_index.get(pk.as_str()).copied());
318
+ for mut row_vals in batch {
319
+ let auto_id = self.next_id;
320
+ self.next_id += 1;
321
+ let mut id = auto_id;
322
+ if row_vals.len() < self.field_order.len() {
323
+ row_vals.resize(self.field_order.len(), FieldValue::Null);
324
+ }
325
+ if let Some(pi) = pk_idx {
326
+ if pi < row_vals.len() {
327
+ match row_vals[pi] {
328
+ FieldValue::Null => row_vals[pi] = FieldValue::Int(auto_id as i64),
329
+ FieldValue::Int(e) if e > 0 => {
330
+ id = e as u64;
331
+ self.next_id = self.next_id.max(id + 1);
332
+ }
333
+ _ => {}
334
+ }
335
+ }
336
+ }
337
+ let values_start = self.values.len();
338
+ self.values.append(&mut row_vals);
339
+ let idx = self.rows.len();
340
+ self.pk_index.insert(id, idx);
341
+ self.rows.push(RowStore { id, values_start, num_values: self.field_order.len(), created_at: now, updated_at: now });
342
+ ids.push(id);
343
+ }
344
+ return ids;
345
+ }
346
+
347
+ // slow path: remap field names
348
+ let remap: Vec<Option<usize>> = self.field_order.iter()
349
+ .map(|name| field_names.iter().position(|fname| fname == name))
350
+ .collect();
351
+ let explicit_pk_si = pk_auto_key.as_ref()
352
+ .and_then(|pk| field_names.iter().position(|n| n == pk));
353
+ let pk_idx = pk_auto_key.as_ref().and_then(|pk| self.field_index.get(pk.as_str()).copied());
354
+
355
+ for mut row_vals in batch {
356
+ let auto_id = self.next_id;
357
+ self.next_id += 1;
358
+ let mut id = auto_id;
359
+ if let Some(si) = explicit_pk_si {
360
+ if let Some(FieldValue::Int(e)) = row_vals.get(si) {
361
+ if *e > 0 {
362
+ id = *e as u64;
363
+ self.next_id = self.next_id.max(id + 1);
364
+ }
365
+ }
366
+ }
367
+ let values_start = self.values.len();
368
+ for (i, remapped_si) in remap.iter().enumerate() {
369
+ if let Some(si) = *remapped_si {
370
+ if si < row_vals.len() {
371
+ self.values.push(std::mem::take(&mut row_vals[si]));
372
+ continue;
373
+ }
374
+ }
375
+ if let Some(ref pk_key) = pk_auto_key {
376
+ if self.field_order[i] == *pk_key {
377
+ self.values.push(FieldValue::Int(id as i64));
378
+ continue;
379
+ }
380
+ }
381
+ if let Some(name) = self.field_order.get(i) {
382
+ if let Some(fs) = self.schema.get(name) {
383
+ if let Some(ref default) = fs.default {
384
+ self.values.push(FieldValue::from_json(default.clone()));
385
+ } else if !fs.nullable {
386
+ self.values.push(default_value(&fs.field_type));
387
+ } else {
388
+ self.values.push(FieldValue::Null);
389
+ }
390
+ } else {
391
+ self.values.push(FieldValue::Null);
392
+ }
393
+ }
394
+ }
395
+ // 显式传入 null 的主键:回填自动 id,保证 pk 值与行 id 一致
396
+ if let Some(pi) = pk_idx {
397
+ if let Some(v) = self.values.get_mut(values_start + pi) {
398
+ if *v == FieldValue::Null {
399
+ *v = FieldValue::Int(id as i64);
400
+ }
401
+ }
402
+ }
403
+ let idx = self.rows.len();
404
+ self.pk_index.insert(id, idx);
405
+ self.rows.push(RowStore { id, values_start, num_values: self.field_order.len(), created_at: now, updated_at: now });
406
+ ids.push(id);
407
+ }
408
+ ids
409
+ }
410
+
411
+ pub fn row_matches(&self, r: &RowStore, filter: &HashMap<String, serde_json::Value>) -> bool {
412
+ let vals = self.get_row_values(r);
413
+ filter.iter().all(|(k, v)| {
414
+ self.field_index.get(k)
415
+ .and_then(|&pos| vals.get(pos))
416
+ .map_or(false, |fv| fv.eq_json(v))
417
+ })
418
+ }
419
+
420
+ pub fn get_row(&self, id: u64) -> Option<Row> {
421
+ let idx = *self.pk_index.get(&id)?;
422
+ self.rows.get(idx).map(|r| self.to_row(r))
423
+ }
424
+
425
+ pub fn get_row_json(&self, id: u64) -> Option<String> {
426
+ let idx = *self.pk_index.get(&id)?;
427
+ self.rows.get(idx).map(|r| self.to_row_json_string(r))
428
+ }
429
+
430
+ pub fn get_rows_json(&self, ids: &[u64]) -> String {
431
+ let mut out = String::with_capacity(ids.len() * 128);
432
+ out.push('[');
433
+ let mut first = true;
434
+ for &id in ids {
435
+ if let Some(&idx) = self.pk_index.get(&id) {
436
+ if let Some(rs) = self.rows.get(idx) {
437
+ if !first { out.push(','); }
438
+ first = false;
439
+ out.push_str(&self.to_row_json_string(rs));
440
+ }
441
+ }
442
+ }
443
+ out.push(']');
444
+ out
445
+ }
446
+
447
+ fn to_row_json_compact(&self, rs: &RowStore) -> String {
448
+ let vals = self.get_row_values(rs);
449
+ let mut out = String::with_capacity(64);
450
+ out.push('[');
451
+ out.push_str(itoa::Buffer::new().format(rs.id));
452
+ for v in vals {
453
+ out.push(',');
454
+ v.write_json(&mut out);
455
+ }
456
+ out.push(']');
457
+ out
458
+ }
459
+
460
+ fn to_row_json_string(&self, rs: &RowStore) -> String {
461
+ let vals = self.get_row_values(rs);
462
+ let mut out = String::with_capacity(160);
463
+ out.push_str(r#"{"id":"#);
464
+ out.push_str(itoa::Buffer::new().format(rs.id));
465
+ out.push_str(r#","fields":{"#);
466
+ for (i, name) in self.field_order.iter().enumerate() {
467
+ if i > 0 { out.push(','); }
468
+ write_json_string(&mut out, name);
469
+ out.push(':');
470
+ if let Some(v) = vals.get(i) {
471
+ v.write_json(&mut out);
472
+ } else {
473
+ out.push_str("null");
474
+ }
475
+ }
476
+ out.push_str(r#"},"created_at":"#);
477
+ write_json_string(&mut out, &millis_to_string(rs.created_at));
478
+ out.push_str(r#","updated_at":"#);
479
+ write_json_string(&mut out, &millis_to_string(rs.updated_at));
480
+ out.push_str("}");
481
+ out
482
+ }
483
+
484
+ pub fn update_row(&mut self, id: u64, data: HashMap<String, serde_json::Value>) -> bool {
485
+ let idx = match self.pk_index.get(&id) {
486
+ Some(i) => *i,
487
+ None => return false,
488
+ };
489
+ // Use raw index access to update values without borrow conflicts
490
+ if idx < self.rows.len() {
491
+ let row = &mut self.rows[idx];
492
+ let nv = row.num_values;
493
+ let s = row.values_start;
494
+ for (k, v) in data {
495
+ if let Some(&pos) = self.field_index.get(&k) {
496
+ if pos < nv {
497
+ self.values[s + pos] = FieldValue::from_json(v);
498
+ }
499
+ }
500
+ }
501
+ self.rows[idx].updated_at = now_millis();
502
+ true
503
+ } else {
504
+ false
505
+ }
506
+ }
507
+
508
+ pub fn update_rows(&mut self, batch: Vec<(u64, HashMap<String, serde_json::Value>)>) -> usize {
509
+ let mut count = 0;
510
+ let now = now_millis();
511
+ for (id, data) in batch {
512
+ if let Some(&idx) = self.pk_index.get(&id) {
513
+ if idx < self.rows.len() {
514
+ let row = &mut self.rows[idx];
515
+ let nv = row.num_values;
516
+ let s = row.values_start;
517
+ for (k, v) in data {
518
+ if let Some(&pos) = self.field_index.get(&k) {
519
+ if pos < nv {
520
+ self.values[s + pos] = FieldValue::from_json(v);
521
+ }
522
+ }
523
+ }
524
+ self.rows[idx].updated_at = now;
525
+ count += 1;
526
+ }
527
+ }
528
+ }
529
+ count
530
+ }
531
+
532
+ pub fn remove_row(&mut self, id: u64) -> bool {
533
+ let idx = match self.pk_index.get(&id) {
534
+ Some(i) => *i,
535
+ None => return false,
536
+ };
537
+ self.pk_index.remove(&id);
538
+ let last = self.rows.len() - 1;
539
+ if idx != last {
540
+ self.pk_index.insert(self.rows[last].id, idx);
541
+ }
542
+ self.rows.swap_remove(idx);
543
+ true
544
+ }
545
+
546
+ pub fn remove_rows(&mut self, ids: &[u64]) -> usize {
547
+ let mut count = 0;
548
+ let mut indices: Vec<(usize, u64)> = Vec::with_capacity(ids.len());
549
+ for &id in ids {
550
+ if let Some(&idx) = self.pk_index.get(&id) {
551
+ indices.push((idx, id));
552
+ count += 1;
553
+ }
554
+ }
555
+ indices.sort_unstable_by(|a, b| b.0.cmp(&a.0));
556
+ for (idx, id) in indices {
557
+ self.pk_index.remove(&id);
558
+ let last = self.rows.len() - 1;
559
+ if idx != last {
560
+ self.pk_index.insert(self.rows[last].id, idx);
561
+ }
562
+ self.rows.swap_remove(idx);
563
+ }
564
+ count
565
+ }
566
+
567
+ pub fn remove_row_by_idx(&mut self, idx: usize) {
568
+ let last = self.rows.len() - 1;
569
+ if idx < last {
570
+ let swapped_id = self.rows[last].id;
571
+ self.pk_index.insert(swapped_id, idx);
572
+ }
573
+ self.pk_index.remove(&self.rows[idx].id);
574
+ self.rows.swap_remove(idx);
575
+ }
576
+
577
+ pub fn count(&self) -> usize {
578
+ self.rows.len()
579
+ }
580
+
581
+ // ============================================================
582
+ // 磁盘持久化导出 / 导入(供 HybridEngine 使用)
583
+ // ============================================================
584
+
585
+ pub fn export_all(&self) -> String {
586
+ let mut out = String::with_capacity(64 + self.rows.len() * 96);
587
+ out.push_str(r#"{"next_id":"#);
588
+ out.push_str(itoa::Buffer::new().format(self.next_id));
589
+ out.push_str(r#","rows":["#);
590
+ for (i, rs) in self.rows.iter().enumerate() {
591
+ if i > 0 { out.push(','); }
592
+ out.push_str(r#"{"id":"#);
593
+ out.push_str(itoa::Buffer::new().format(rs.id));
594
+ out.push_str(r#","created_at":"#);
595
+ out.push_str(itoa::Buffer::new().format(rs.created_at));
596
+ out.push_str(r#","updated_at":"#);
597
+ out.push_str(itoa::Buffer::new().format(rs.updated_at));
598
+ out.push_str(r#","fields":{"#);
599
+ let vals = self.get_row_values(rs);
600
+ for (fi, name) in self.field_order.iter().enumerate() {
601
+ if fi > 0 { out.push(','); }
602
+ write_json_string(&mut out, name);
603
+ out.push(':');
604
+ if let Some(v) = vals.get(fi) {
605
+ v.write_json(&mut out);
606
+ } else {
607
+ out.push_str("null");
608
+ }
609
+ }
610
+ out.push_str("}}");
611
+ }
612
+ out.push_str("]}");
613
+ out
614
+ }
615
+
616
+ pub fn import_from_json(&mut self, json: &str) -> Result<(), String> {
617
+ let parsed: serde_json::Value = serde_json::from_str(json)
618
+ .map_err(|e| format!("invalid table file: {}", e))?;
619
+ let next_id = parsed.get("next_id").and_then(|v| v.as_u64()).unwrap_or(1);
620
+ self.next_id = next_id;
621
+ let rows = parsed.get("rows").and_then(|v| v.as_array()).ok_or("table file missing rows")?;
622
+ let pk_auto_key = self.pk_field.as_deref().and_then(|pk| {
623
+ self.schema.get(pk).and_then(|fs| if fs.auto_increment { Some(pk.to_string()) } else { None })
624
+ });
625
+ self.rows.reserve(rows.len());
626
+ self.values.reserve(rows.len() * self.field_order.len());
627
+ self.pk_index.reserve(rows.len());
628
+ for rv in rows {
629
+ let id = rv.get("id").and_then(|v| v.as_u64()).ok_or("row missing id")?;
630
+ let created_at = rv.get("created_at").and_then(|v| v.as_u64()).unwrap_or_else(now_millis);
631
+ let updated_at = rv.get("updated_at").and_then(|v| v.as_u64()).unwrap_or(created_at);
632
+ let fields = rv.get("fields").and_then(|v| v.as_object()).ok_or("row missing fields")?;
633
+ let values_start = self.values.len();
634
+ for name in &self.field_order {
635
+ if let Some(jv) = fields.get(name) {
636
+ self.values.push(FieldValue::from_json(jv.clone()));
637
+ } else if let Some(ref pk_key) = pk_auto_key {
638
+ if *pk_key == *name {
639
+ self.values.push(FieldValue::Int(id as i64));
640
+ } else {
641
+ self.values.push(FieldValue::Null);
642
+ }
643
+ } else {
644
+ self.values.push(FieldValue::Null);
645
+ }
646
+ }
647
+ let idx = self.rows.len();
648
+ self.pk_index.insert(id, idx);
649
+ self.rows.push(RowStore { id, values_start, num_values: self.field_order.len(), created_at, updated_at });
650
+ }
651
+ Ok(())
652
+ }
653
+
654
+ pub fn find_rows(&self, filter: &Option<HashMap<String, serde_json::Value>>,
655
+ limit: Option<usize>, offset: Option<usize>,
656
+ order_by: &Option<String>, order: &Option<String>) -> Vec<Row> {
657
+ let mut results: Vec<&RowStore> = self.rows.iter().collect();
658
+
659
+ if let Some(ref f) = filter {
660
+ let filter_indices: Vec<(usize, &serde_json::Value)> = f.iter()
661
+ .filter_map(|(k, v)| self.field_index.get(k).map(|&pos| (pos, v)))
662
+ .collect();
663
+ results.retain(|r| {
664
+ let vals = self.get_row_values(r);
665
+ filter_indices.iter().all(|(pos, v)| {
666
+ vals.get(*pos).map_or(false, |fv| fv.eq_json(v))
667
+ })
668
+ });
669
+ }
670
+
671
+ if let Some(ref field) = order_by {
672
+ let desc = order.as_deref() == Some("desc");
673
+ if let Some(&pos) = self.field_index.get(field) {
674
+ results.sort_by(|a, b| {
675
+ let vals_a = self.get_row_values(a);
676
+ let vals_b = self.get_row_values(b);
677
+ let cmp = cmp_field_values(vals_a.get(pos), vals_b.get(pos));
678
+ if desc { cmp.reverse() } else { cmp }
679
+ });
680
+ }
681
+ }
682
+
683
+ let o = offset.unwrap_or(0);
684
+ let l = limit.unwrap_or(usize::MAX);
685
+ results.into_iter().skip(o).take(l).map(|r| self.to_row(r)).collect()
686
+ }
687
+ }
688
+
689
+ fn cmp_field_values(a: Option<&FieldValue>, b: Option<&FieldValue>) -> std::cmp::Ordering {
690
+ match (a, b) {
691
+ (Some(FieldValue::Int(na)), Some(FieldValue::Int(nb))) => na.cmp(nb),
692
+ (Some(FieldValue::Float(na)), Some(FieldValue::Float(nb))) => na.partial_cmp(nb).unwrap_or(std::cmp::Ordering::Equal),
693
+ (Some(FieldValue::String(sa)), Some(FieldValue::String(sb))) => sa.cmp(sb),
694
+ (Some(FieldValue::Bool(ba)), Some(FieldValue::Bool(bb))) => ba.cmp(bb),
695
+ (Some(a), Some(b)) => format!("{:?}", a).cmp(&format!("{:?}", b)),
696
+ (Some(_), None) => std::cmp::Ordering::Greater,
697
+ (None, Some(_)) => std::cmp::Ordering::Less,
698
+ (None, None) => std::cmp::Ordering::Equal,
699
+ }
700
+ }