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,168 +1,168 @@
1
- use std::collections::HashMap;
2
- use crate::engine::table::Table;
3
- use crate::engine::{validate_table_name, Engine};
4
- use crate::types::{Row, TableDefinition};
5
-
6
- pub struct MemoryEngine {
7
- pub tables: HashMap<String, Table>,
8
- txs: HashMap<String, HashMap<String, Table>>,
9
- next_tx_id: u64,
10
- }
11
-
12
- impl MemoryEngine {
13
- pub fn new() -> Self {
14
- Self { tables: HashMap::new(), txs: HashMap::new(), next_tx_id: 1 }
15
- }
16
-
17
- pub fn clear(&mut self) {
18
- self.tables.clear();
19
- self.txs.clear();
20
- self.next_tx_id = 1;
21
- }
22
-
23
- fn snapshot(&self) -> HashMap<String, Table> {
24
- self.tables.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
25
- }
26
- }
27
-
28
- impl Engine for MemoryEngine {
29
- fn create_table(&mut self, def: TableDefinition) -> Result<(), String> {
30
- validate_table_name(&def.name)?;
31
- if self.tables.contains_key(&def.name) {
32
- return Err(format!("table '{}' already exists", def.name));
33
- }
34
- self.tables.insert(def.name.clone(), Table::new(def.name, &def.schema));
35
- Ok(())
36
- }
37
-
38
- fn drop_table(&mut self, name: &str) -> Result<(), String> {
39
- self.tables.remove(name).map(|_| ()).ok_or_else(|| format!("table '{}' not found", name))
40
- }
41
-
42
- fn has_table(&self, name: &str) -> bool {
43
- self.tables.contains_key(name)
44
- }
45
-
46
- fn list_tables(&self) -> Vec<String> {
47
- self.tables.keys().cloned().collect()
48
- }
49
-
50
- fn insert(&mut self, table: &str, fields_batch: Vec<HashMap<String, serde_json::Value>>) -> Result<Vec<u64>, String> {
51
- let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
52
- Ok(t.add_rows(fields_batch))
53
- }
54
-
55
- fn find_by_id(&self, table: &str, id: u64) -> Result<Option<Row>, String> {
56
- let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
57
- Ok(t.get_row(id))
58
- }
59
-
60
- fn find_by_id_json(&self, table: &str, id: u64) -> Result<Option<String>, String> {
61
- let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
62
- Ok(t.get_row_json(id))
63
- }
64
-
65
- fn find_by_ids_json(&self, table: &str, ids: &[u64]) -> Result<String, String> {
66
- let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
67
- Ok(t.get_rows_json(ids))
68
- }
69
-
70
- fn find(&self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>,
71
- limit: Option<usize>, offset: Option<usize>,
72
- cursor: Option<String>,
73
- order_by: &Option<String>, order: &Option<String>) -> Result<(Vec<Row>, Option<String>, bool), String> {
74
- let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
75
- let off = cursor.as_deref().and_then(|c| c.strip_prefix('c')?.parse().ok()).or(offset);
76
- let off_val = off.unwrap_or(0);
77
- let probe_limit = limit.map(|l| l + 1);
78
- let all = t.find_rows(filter, probe_limit, off, order_by, order);
79
- let has_more = limit.map_or(false, |l| all.len() > l);
80
- let rows: Vec<Row> = all.into_iter().take(limit.unwrap_or(usize::MAX)).collect();
81
- let next_cursor = if has_more { Some(format!("c{}", off_val + limit.unwrap())) } else { None };
82
- Ok((rows, next_cursor, has_more))
83
- }
84
-
85
- fn count(&self, table: &str) -> Result<usize, String> {
86
- let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
87
- Ok(t.count())
88
- }
89
-
90
- fn update_by_id(&mut self, table: &str, id: u64, data: HashMap<String, serde_json::Value>) -> Result<bool, String> {
91
- let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
92
- Ok(t.update_row(id, data))
93
- }
94
-
95
- fn remove_by_id(&mut self, table: &str, id: u64) -> Result<bool, String> {
96
- let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
97
- Ok(t.remove_row(id))
98
- }
99
-
100
- fn remove_by_ids(&mut self, table: &str, ids: &[u64]) -> Result<usize, String> {
101
- let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
102
- Ok(t.remove_rows(ids))
103
- }
104
-
105
- fn update_by_ids(&mut self, table: &str, batch: Vec<(u64, HashMap<String, serde_json::Value>)>) -> Result<usize, String> {
106
- let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
107
- Ok(t.update_rows(batch))
108
- }
109
-
110
- fn update_by_filter(&mut self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>,
111
- data: HashMap<String, serde_json::Value>) -> Result<usize, String> {
112
- let ids: Vec<u64> = {
113
- let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
114
- t.rows.iter()
115
- .filter(|r| filter.as_ref().map_or(true, |f| t.row_matches(r, f)))
116
- .map(|r| r.id)
117
- .collect()
118
- };
119
- let count = ids.len();
120
- for id in &ids {
121
- let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
122
- t.update_row(*id, data.clone());
123
- }
124
- Ok(count)
125
- }
126
-
127
- fn remove_by_filter(&mut self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>) -> Result<usize, String> {
128
- let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
129
- let len_before = t.rows.len();
130
- if filter.is_none() {
131
- t.rows.clear();
132
- t.pk_index.clear();
133
- return Ok(len_before);
134
- }
135
- let f = filter.as_ref().unwrap();
136
- let mut to_remove = Vec::new();
137
- for (i, r) in t.rows.iter().enumerate() {
138
- let matches = f.iter().all(|(k, v)| {
139
- t.field_index.get(k).and_then(|&pos| t.get_row_values(r).get(pos)).map_or(false, |fv| fv.eq_json(v))
140
- });
141
- if matches { to_remove.push(i); }
142
- }
143
- for i in to_remove.into_iter().rev() {
144
- t.remove_row_by_idx(i);
145
- }
146
- Ok(len_before - t.rows.len())
147
- }
148
-
149
- fn begin_tx(&mut self) -> Result<String, String> {
150
- let tx_id = format!("tx{}", self.next_tx_id);
151
- self.next_tx_id += 1;
152
- self.txs.insert(tx_id.clone(), self.snapshot());
153
- Ok(tx_id)
154
- }
155
-
156
- fn commit_tx(&mut self, tx_id: &str) -> Result<(), String> {
157
- self.txs.remove(tx_id)
158
- .map(|_| ())
159
- .ok_or_else(|| format!("transaction '{}' not found", tx_id))
160
- }
161
-
162
- fn rollback_tx(&mut self, tx_id: &str) -> Result<(), String> {
163
- let snap = self.txs.remove(tx_id)
164
- .ok_or_else(|| format!("transaction '{}' not found", tx_id))?;
165
- self.tables = snap;
166
- Ok(())
167
- }
168
- }
1
+ use std::collections::HashMap;
2
+ use crate::engine::table::Table;
3
+ use crate::engine::{validate_table_name, Engine};
4
+ use crate::types::{Row, TableDefinition};
5
+
6
+ pub struct MemoryEngine {
7
+ pub tables: HashMap<String, Table>,
8
+ txs: HashMap<String, HashMap<String, Table>>,
9
+ next_tx_id: u64,
10
+ }
11
+
12
+ impl MemoryEngine {
13
+ pub fn new() -> Self {
14
+ Self { tables: HashMap::new(), txs: HashMap::new(), next_tx_id: 1 }
15
+ }
16
+
17
+ pub fn clear(&mut self) {
18
+ self.tables.clear();
19
+ self.txs.clear();
20
+ self.next_tx_id = 1;
21
+ }
22
+
23
+ fn snapshot(&self) -> HashMap<String, Table> {
24
+ self.tables.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
25
+ }
26
+ }
27
+
28
+ impl Engine for MemoryEngine {
29
+ fn create_table(&mut self, def: TableDefinition) -> Result<(), String> {
30
+ validate_table_name(&def.name)?;
31
+ if self.tables.contains_key(&def.name) {
32
+ return Err(format!("table '{}' already exists", def.name));
33
+ }
34
+ self.tables.insert(def.name.clone(), Table::new(def.name, &def.schema));
35
+ Ok(())
36
+ }
37
+
38
+ fn drop_table(&mut self, name: &str) -> Result<(), String> {
39
+ self.tables.remove(name).map(|_| ()).ok_or_else(|| format!("table '{}' not found", name))
40
+ }
41
+
42
+ fn has_table(&self, name: &str) -> bool {
43
+ self.tables.contains_key(name)
44
+ }
45
+
46
+ fn list_tables(&self) -> Vec<String> {
47
+ self.tables.keys().cloned().collect()
48
+ }
49
+
50
+ fn insert(&mut self, table: &str, fields_batch: Vec<HashMap<String, serde_json::Value>>) -> Result<Vec<u64>, String> {
51
+ let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
52
+ Ok(t.add_rows(fields_batch))
53
+ }
54
+
55
+ fn find_by_id(&self, table: &str, id: u64) -> Result<Option<Row>, String> {
56
+ let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
57
+ Ok(t.get_row(id))
58
+ }
59
+
60
+ fn find_by_id_json(&self, table: &str, id: u64) -> Result<Option<String>, String> {
61
+ let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
62
+ Ok(t.get_row_json(id))
63
+ }
64
+
65
+ fn find_by_ids_json(&self, table: &str, ids: &[u64]) -> Result<String, String> {
66
+ let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
67
+ Ok(t.get_rows_json(ids))
68
+ }
69
+
70
+ fn find(&self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>,
71
+ limit: Option<usize>, offset: Option<usize>,
72
+ cursor: Option<String>,
73
+ order_by: &Option<String>, order: &Option<String>) -> Result<(Vec<Row>, Option<String>, bool), String> {
74
+ let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
75
+ let off = cursor.as_deref().and_then(|c| c.strip_prefix('c')?.parse().ok()).or(offset);
76
+ let off_val = off.unwrap_or(0);
77
+ let probe_limit = limit.map(|l| l + 1);
78
+ let all = t.find_rows(filter, probe_limit, off, order_by, order);
79
+ let has_more = limit.map_or(false, |l| all.len() > l);
80
+ let rows: Vec<Row> = all.into_iter().take(limit.unwrap_or(usize::MAX)).collect();
81
+ let next_cursor = if has_more { Some(format!("c{}", off_val + limit.unwrap())) } else { None };
82
+ Ok((rows, next_cursor, has_more))
83
+ }
84
+
85
+ fn count(&self, table: &str) -> Result<usize, String> {
86
+ let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
87
+ Ok(t.count())
88
+ }
89
+
90
+ fn update_by_id(&mut self, table: &str, id: u64, data: HashMap<String, serde_json::Value>) -> Result<bool, String> {
91
+ let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
92
+ Ok(t.update_row(id, data))
93
+ }
94
+
95
+ fn remove_by_id(&mut self, table: &str, id: u64) -> Result<bool, String> {
96
+ let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
97
+ Ok(t.remove_row(id))
98
+ }
99
+
100
+ fn remove_by_ids(&mut self, table: &str, ids: &[u64]) -> Result<usize, String> {
101
+ let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
102
+ Ok(t.remove_rows(ids))
103
+ }
104
+
105
+ fn update_by_ids(&mut self, table: &str, batch: Vec<(u64, HashMap<String, serde_json::Value>)>) -> Result<usize, String> {
106
+ let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
107
+ Ok(t.update_rows(batch))
108
+ }
109
+
110
+ fn update_by_filter(&mut self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>,
111
+ data: HashMap<String, serde_json::Value>) -> Result<usize, String> {
112
+ let ids: Vec<u64> = {
113
+ let t = self.tables.get(table).ok_or_else(|| format!("table '{}' not found", table))?;
114
+ t.rows.iter()
115
+ .filter(|r| filter.as_ref().map_or(true, |f| t.row_matches(r, f)))
116
+ .map(|r| r.id)
117
+ .collect()
118
+ };
119
+ let count = ids.len();
120
+ for id in &ids {
121
+ let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
122
+ t.update_row(*id, data.clone());
123
+ }
124
+ Ok(count)
125
+ }
126
+
127
+ fn remove_by_filter(&mut self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>) -> Result<usize, String> {
128
+ let t = self.tables.get_mut(table).ok_or_else(|| format!("table '{}' not found", table))?;
129
+ let len_before = t.rows.len();
130
+ if filter.is_none() {
131
+ t.rows.clear();
132
+ t.pk_index.clear();
133
+ return Ok(len_before);
134
+ }
135
+ let f = filter.as_ref().unwrap();
136
+ let mut to_remove = Vec::new();
137
+ for (i, r) in t.rows.iter().enumerate() {
138
+ let matches = f.iter().all(|(k, v)| {
139
+ t.field_index.get(k).and_then(|&pos| t.get_row_values(r).get(pos)).map_or(false, |fv| fv.eq_json(v))
140
+ });
141
+ if matches { to_remove.push(i); }
142
+ }
143
+ for i in to_remove.into_iter().rev() {
144
+ t.remove_row_by_idx(i);
145
+ }
146
+ Ok(len_before - t.rows.len())
147
+ }
148
+
149
+ fn begin_tx(&mut self) -> Result<String, String> {
150
+ let tx_id = format!("tx{}", self.next_tx_id);
151
+ self.next_tx_id += 1;
152
+ self.txs.insert(tx_id.clone(), self.snapshot());
153
+ Ok(tx_id)
154
+ }
155
+
156
+ fn commit_tx(&mut self, tx_id: &str) -> Result<(), String> {
157
+ self.txs.remove(tx_id)
158
+ .map(|_| ())
159
+ .ok_or_else(|| format!("transaction '{}' not found", tx_id))
160
+ }
161
+
162
+ fn rollback_tx(&mut self, tx_id: &str) -> Result<(), String> {
163
+ let snap = self.txs.remove(tx_id)
164
+ .ok_or_else(|| format!("transaction '{}' not found", tx_id))?;
165
+ self.tables = snap;
166
+ Ok(())
167
+ }
168
+ }
@@ -1,62 +1,62 @@
1
- pub mod table;
2
- mod memory;
3
- #[cfg(not(feature = "wasm"))]
4
- pub mod hybrid;
5
-
6
- pub use memory::MemoryEngine;
7
- #[cfg(not(feature = "wasm"))]
8
- pub use hybrid::HybridEngine;
9
- pub use table::{Table, RowStore, FieldValue, default_value};
10
-
11
- pub fn validate_table_name(name: &str) -> Result<(), String> {
12
- if name.is_empty() {
13
- return Err("table name must not be empty".to_string());
14
- }
15
- if name.len() > 64 {
16
- return Err("table name too long (max 64 chars)".to_string());
17
- }
18
- if name == "." || name == ".." {
19
- return Err(format!("invalid table name '{}'", name));
20
- }
21
- for (i, c) in name.chars().enumerate() {
22
- if c.is_ascii_control() || c == '/' || c == '\\' {
23
- return Err(format!("invalid character in table name '{}'", name));
24
- }
25
- if c == '.' && (i > 0 && name.as_bytes()[i - 1] == b'.') {
26
- return Err(format!("invalid table name '{}' ('..' sequences are not allowed)", name));
27
- }
28
- }
29
- Ok(())
30
- }
31
-
32
- use std::collections::HashMap;
33
- use crate::types::{Row, TableDefinition};
34
-
35
- pub trait Engine {
36
- fn create_table(&mut self, def: TableDefinition) -> Result<(), String>;
37
- fn drop_table(&mut self, name: &str) -> Result<(), String>;
38
- fn has_table(&self, name: &str) -> bool;
39
- fn list_tables(&self) -> Vec<String>;
40
-
41
- fn insert(&mut self, table: &str, fields: Vec<HashMap<String, serde_json::Value>>) -> Result<Vec<u64>, String>;
42
- fn find_by_id(&self, table: &str, id: u64) -> Result<Option<Row>, String>;
43
- fn find_by_id_json(&self, table: &str, id: u64) -> Result<Option<String>, String>;
44
- fn find_by_ids_json(&self, table: &str, ids: &[u64]) -> Result<String, String>;
45
- fn find(&self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>,
46
- limit: Option<usize>, offset: Option<usize>,
47
- cursor: Option<String>,
48
- order_by: &Option<String>, order: &Option<String>) -> Result<(Vec<Row>, Option<String>, bool), String>;
49
- fn count(&self, table: &str) -> Result<usize, String>;
50
- fn update_by_id(&mut self, table: &str, id: u64, data: HashMap<String, serde_json::Value>) -> Result<bool, String>;
51
- fn update_by_ids(&mut self, table: &str, batch: Vec<(u64, HashMap<String, serde_json::Value>)>) -> Result<usize, String>;
52
- fn remove_by_id(&mut self, table: &str, id: u64) -> Result<bool, String>;
53
- fn remove_by_ids(&mut self, table: &str, ids: &[u64]) -> Result<usize, String>;
54
-
55
- fn update_by_filter(&mut self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>,
56
- data: HashMap<String, serde_json::Value>) -> Result<usize, String>;
57
- fn remove_by_filter(&mut self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>) -> Result<usize, String>;
58
-
59
- fn begin_tx(&mut self) -> Result<String, String>;
60
- fn commit_tx(&mut self, tx_id: &str) -> Result<(), String>;
61
- fn rollback_tx(&mut self, tx_id: &str) -> Result<(), String>;
62
- }
1
+ pub mod table;
2
+ mod memory;
3
+ #[cfg(not(feature = "wasm"))]
4
+ pub mod hybrid;
5
+
6
+ pub use memory::MemoryEngine;
7
+ #[cfg(not(feature = "wasm"))]
8
+ pub use hybrid::HybridEngine;
9
+ pub use table::{Table, RowStore, FieldValue, default_value};
10
+
11
+ pub fn validate_table_name(name: &str) -> Result<(), String> {
12
+ if name.is_empty() {
13
+ return Err("table name must not be empty".to_string());
14
+ }
15
+ if name.len() > 64 {
16
+ return Err("table name too long (max 64 chars)".to_string());
17
+ }
18
+ if name == "." || name == ".." {
19
+ return Err(format!("invalid table name '{}'", name));
20
+ }
21
+ for (i, c) in name.chars().enumerate() {
22
+ if c.is_ascii_control() || c == '/' || c == '\\' {
23
+ return Err(format!("invalid character in table name '{}'", name));
24
+ }
25
+ if c == '.' && (i > 0 && name.as_bytes()[i - 1] == b'.') {
26
+ return Err(format!("invalid table name '{}' ('..' sequences are not allowed)", name));
27
+ }
28
+ }
29
+ Ok(())
30
+ }
31
+
32
+ use std::collections::HashMap;
33
+ use crate::types::{Row, TableDefinition};
34
+
35
+ pub trait Engine {
36
+ fn create_table(&mut self, def: TableDefinition) -> Result<(), String>;
37
+ fn drop_table(&mut self, name: &str) -> Result<(), String>;
38
+ fn has_table(&self, name: &str) -> bool;
39
+ fn list_tables(&self) -> Vec<String>;
40
+
41
+ fn insert(&mut self, table: &str, fields: Vec<HashMap<String, serde_json::Value>>) -> Result<Vec<u64>, String>;
42
+ fn find_by_id(&self, table: &str, id: u64) -> Result<Option<Row>, String>;
43
+ fn find_by_id_json(&self, table: &str, id: u64) -> Result<Option<String>, String>;
44
+ fn find_by_ids_json(&self, table: &str, ids: &[u64]) -> Result<String, String>;
45
+ fn find(&self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>,
46
+ limit: Option<usize>, offset: Option<usize>,
47
+ cursor: Option<String>,
48
+ order_by: &Option<String>, order: &Option<String>) -> Result<(Vec<Row>, Option<String>, bool), String>;
49
+ fn count(&self, table: &str) -> Result<usize, String>;
50
+ fn update_by_id(&mut self, table: &str, id: u64, data: HashMap<String, serde_json::Value>) -> Result<bool, String>;
51
+ fn update_by_ids(&mut self, table: &str, batch: Vec<(u64, HashMap<String, serde_json::Value>)>) -> Result<usize, String>;
52
+ fn remove_by_id(&mut self, table: &str, id: u64) -> Result<bool, String>;
53
+ fn remove_by_ids(&mut self, table: &str, ids: &[u64]) -> Result<usize, String>;
54
+
55
+ fn update_by_filter(&mut self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>,
56
+ data: HashMap<String, serde_json::Value>) -> Result<usize, String>;
57
+ fn remove_by_filter(&mut self, table: &str, filter: &Option<HashMap<String, serde_json::Value>>) -> Result<usize, String>;
58
+
59
+ fn begin_tx(&mut self) -> Result<String, String>;
60
+ fn commit_tx(&mut self, tx_id: &str) -> Result<(), String>;
61
+ fn rollback_tx(&mut self, tx_id: &str) -> Result<(), String>;
62
+ }