@lix-js/sdk 0.6.0-preview.1 → 0.6.0-preview.3

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 (205) hide show
  1. package/SKILL.md +304 -320
  2. package/dist/engine-wasm/wasm/lix_engine.d.ts +5 -0
  3. package/dist/engine-wasm/wasm/lix_engine.js +9 -13
  4. package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
  5. package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +1 -0
  6. package/dist/generated/builtin-schemas.d.ts +87 -162
  7. package/dist/generated/builtin-schemas.js +139 -236
  8. package/dist/open-lix.d.ts +103 -14
  9. package/dist/open-lix.js +3 -0
  10. package/dist/sqlite/index.js +99 -22
  11. package/dist-engine-src/README.md +18 -0
  12. package/dist-engine-src/src/backend/kv.rs +358 -0
  13. package/dist-engine-src/src/backend/mod.rs +12 -0
  14. package/dist-engine-src/src/backend/testing.rs +658 -0
  15. package/dist-engine-src/src/backend/types.rs +96 -0
  16. package/dist-engine-src/src/binary_cas/chunking.rs +31 -0
  17. package/dist-engine-src/src/binary_cas/codec.rs +346 -0
  18. package/dist-engine-src/src/binary_cas/context.rs +139 -0
  19. package/dist-engine-src/src/binary_cas/kv.rs +1063 -0
  20. package/dist-engine-src/src/binary_cas/mod.rs +11 -0
  21. package/dist-engine-src/src/binary_cas/types.rs +121 -0
  22. package/dist-engine-src/src/catalog/context.rs +412 -0
  23. package/dist-engine-src/src/catalog/mod.rs +10 -0
  24. package/dist-engine-src/src/catalog/schema.rs +4 -0
  25. package/dist-engine-src/src/catalog/snapshot.rs +1114 -0
  26. package/dist-engine-src/src/cel/context.rs +86 -0
  27. package/dist-engine-src/src/cel/error.rs +19 -0
  28. package/dist-engine-src/src/cel/mod.rs +8 -0
  29. package/dist-engine-src/src/cel/provider.rs +9 -0
  30. package/dist-engine-src/src/cel/runtime.rs +167 -0
  31. package/dist-engine-src/src/cel/value.rs +50 -0
  32. package/dist-engine-src/src/commit_graph/context.rs +901 -0
  33. package/dist-engine-src/src/commit_graph/mod.rs +11 -0
  34. package/dist-engine-src/src/commit_graph/types.rs +109 -0
  35. package/dist-engine-src/src/commit_graph/walker.rs +756 -0
  36. package/dist-engine-src/src/commit_store/codec.rs +887 -0
  37. package/dist-engine-src/src/commit_store/context.rs +944 -0
  38. package/dist-engine-src/src/commit_store/materialization.rs +84 -0
  39. package/dist-engine-src/src/commit_store/mod.rs +16 -0
  40. package/dist-engine-src/src/commit_store/storage.rs +600 -0
  41. package/dist-engine-src/src/commit_store/types.rs +215 -0
  42. package/dist-engine-src/src/common/error.rs +313 -0
  43. package/dist-engine-src/src/common/fingerprint.rs +3 -0
  44. package/dist-engine-src/src/common/fs_path.rs +1336 -0
  45. package/dist-engine-src/src/common/identity.rs +145 -0
  46. package/dist-engine-src/src/common/json_pointer.rs +67 -0
  47. package/dist-engine-src/src/common/metadata.rs +40 -0
  48. package/dist-engine-src/src/common/mod.rs +23 -0
  49. package/dist-engine-src/src/common/types.rs +105 -0
  50. package/dist-engine-src/src/common/wire.rs +222 -0
  51. package/dist-engine-src/src/domain.rs +324 -0
  52. package/dist-engine-src/src/engine.rs +225 -0
  53. package/dist-engine-src/src/entity_identity.rs +405 -0
  54. package/dist-engine-src/src/functions/context.rs +292 -0
  55. package/dist-engine-src/src/functions/deterministic.rs +113 -0
  56. package/dist-engine-src/src/functions/mod.rs +18 -0
  57. package/dist-engine-src/src/functions/provider.rs +130 -0
  58. package/dist-engine-src/src/functions/state.rs +336 -0
  59. package/dist-engine-src/src/functions/types.rs +37 -0
  60. package/dist-engine-src/src/init.rs +558 -0
  61. package/dist-engine-src/src/json_store/compression.rs +77 -0
  62. package/dist-engine-src/src/json_store/context.rs +423 -0
  63. package/dist-engine-src/src/json_store/encoded.rs +15 -0
  64. package/dist-engine-src/src/json_store/mod.rs +12 -0
  65. package/dist-engine-src/src/json_store/store.rs +1109 -0
  66. package/dist-engine-src/src/json_store/types.rs +217 -0
  67. package/dist-engine-src/src/lib.rs +62 -0
  68. package/dist-engine-src/src/live_state/context.rs +2019 -0
  69. package/dist-engine-src/src/live_state/mod.rs +15 -0
  70. package/dist-engine-src/src/live_state/overlay.rs +75 -0
  71. package/dist-engine-src/src/live_state/reader.rs +23 -0
  72. package/dist-engine-src/src/live_state/types.rs +222 -0
  73. package/dist-engine-src/src/live_state/visibility.rs +223 -0
  74. package/dist-engine-src/src/plugin/archive.rs +438 -0
  75. package/dist-engine-src/src/plugin/component.rs +183 -0
  76. package/dist-engine-src/src/plugin/install.rs +619 -0
  77. package/dist-engine-src/src/plugin/manifest.rs +516 -0
  78. package/dist-engine-src/src/plugin/materializer.rs +477 -0
  79. package/dist-engine-src/src/plugin/mod.rs +33 -0
  80. package/dist-engine-src/src/plugin/plugin_manifest.json +118 -0
  81. package/dist-engine-src/src/plugin/storage.rs +74 -0
  82. package/dist-engine-src/src/schema/annotations/defaults.rs +275 -0
  83. package/dist-engine-src/src/schema/annotations/mod.rs +1 -0
  84. package/dist-engine-src/src/schema/builtin/lix_account.json +21 -0
  85. package/dist-engine-src/src/schema/builtin/lix_active_account.json +29 -0
  86. package/dist-engine-src/src/schema/builtin/lix_binary_blob_ref.json +29 -0
  87. package/dist-engine-src/src/schema/builtin/lix_change.json +63 -0
  88. package/dist-engine-src/src/schema/builtin/lix_change_author.json +45 -0
  89. package/dist-engine-src/src/schema/builtin/lix_commit.json +24 -0
  90. package/dist-engine-src/src/schema/builtin/lix_commit_edge.json +53 -0
  91. package/dist-engine-src/src/schema/builtin/lix_directory_descriptor.json +52 -0
  92. package/dist-engine-src/src/schema/builtin/lix_file_descriptor.json +52 -0
  93. package/dist-engine-src/src/schema/builtin/lix_key_value.json +40 -0
  94. package/dist-engine-src/src/schema/builtin/lix_label.json +29 -0
  95. package/dist-engine-src/src/schema/builtin/lix_label_assignment.json +74 -0
  96. package/dist-engine-src/src/schema/builtin/lix_registered_schema.json +25 -0
  97. package/dist-engine-src/src/schema/builtin/lix_version_descriptor.json +34 -0
  98. package/dist-engine-src/src/schema/builtin/lix_version_ref.json +48 -0
  99. package/dist-engine-src/src/schema/builtin/mod.rs +222 -0
  100. package/dist-engine-src/src/schema/compatibility.rs +787 -0
  101. package/dist-engine-src/src/schema/definition.json +187 -0
  102. package/dist-engine-src/src/schema/definition.rs +742 -0
  103. package/dist-engine-src/src/schema/key.rs +138 -0
  104. package/dist-engine-src/src/schema/mod.rs +20 -0
  105. package/dist-engine-src/src/schema/seed.rs +14 -0
  106. package/dist-engine-src/src/schema/tests.rs +780 -0
  107. package/dist-engine-src/src/session/context.rs +364 -0
  108. package/dist-engine-src/src/session/create_version.rs +88 -0
  109. package/dist-engine-src/src/session/execute.rs +478 -0
  110. package/dist-engine-src/src/session/merge/analysis.rs +102 -0
  111. package/dist-engine-src/src/session/merge/apply.rs +23 -0
  112. package/dist-engine-src/src/session/merge/conflicts.rs +63 -0
  113. package/dist-engine-src/src/session/merge/mod.rs +11 -0
  114. package/dist-engine-src/src/session/merge/stats.rs +65 -0
  115. package/dist-engine-src/src/session/merge/version.rs +427 -0
  116. package/dist-engine-src/src/session/mod.rs +27 -0
  117. package/dist-engine-src/src/session/optimization9_sql2_bench.rs +100 -0
  118. package/dist-engine-src/src/session/switch_version.rs +109 -0
  119. package/dist-engine-src/src/sql2/change_provider.rs +331 -0
  120. package/dist-engine-src/src/sql2/classify.rs +182 -0
  121. package/dist-engine-src/src/sql2/context.rs +311 -0
  122. package/dist-engine-src/src/sql2/directory_history_provider.rs +631 -0
  123. package/dist-engine-src/src/sql2/directory_provider.rs +2453 -0
  124. package/dist-engine-src/src/sql2/dml.rs +148 -0
  125. package/dist-engine-src/src/sql2/entity_history_provider.rs +440 -0
  126. package/dist-engine-src/src/sql2/entity_provider.rs +3211 -0
  127. package/dist-engine-src/src/sql2/error.rs +216 -0
  128. package/dist-engine-src/src/sql2/execute.rs +3440 -0
  129. package/dist-engine-src/src/sql2/file_history_provider.rs +910 -0
  130. package/dist-engine-src/src/sql2/file_provider.rs +3679 -0
  131. package/dist-engine-src/src/sql2/filesystem_planner.rs +1490 -0
  132. package/dist-engine-src/src/sql2/filesystem_predicates.rs +159 -0
  133. package/dist-engine-src/src/sql2/filesystem_visibility.rs +383 -0
  134. package/dist-engine-src/src/sql2/history_projection.rs +56 -0
  135. package/dist-engine-src/src/sql2/history_provider.rs +412 -0
  136. package/dist-engine-src/src/sql2/history_route.rs +657 -0
  137. package/dist-engine-src/src/sql2/lix_state_provider.rs +2512 -0
  138. package/dist-engine-src/src/sql2/mod.rs +46 -0
  139. package/dist-engine-src/src/sql2/predicate_typecheck.rs +246 -0
  140. package/dist-engine-src/src/sql2/public_bind/assignment.rs +46 -0
  141. package/dist-engine-src/src/sql2/public_bind/capability.rs +41 -0
  142. package/dist-engine-src/src/sql2/public_bind/dml.rs +166 -0
  143. package/dist-engine-src/src/sql2/public_bind/mod.rs +25 -0
  144. package/dist-engine-src/src/sql2/public_bind/table.rs +168 -0
  145. package/dist-engine-src/src/sql2/read_only.rs +63 -0
  146. package/dist-engine-src/src/sql2/record_batch.rs +17 -0
  147. package/dist-engine-src/src/sql2/result_metadata.rs +29 -0
  148. package/dist-engine-src/src/sql2/runtime.rs +60 -0
  149. package/dist-engine-src/src/sql2/session.rs +132 -0
  150. package/dist-engine-src/src/sql2/udfs/common.rs +295 -0
  151. package/dist-engine-src/src/sql2/udfs/lix_active_version_commit_id.rs +53 -0
  152. package/dist-engine-src/src/sql2/udfs/lix_empty_blob.rs +47 -0
  153. package/dist-engine-src/src/sql2/udfs/lix_json.rs +100 -0
  154. package/dist-engine-src/src/sql2/udfs/lix_json_get.rs +99 -0
  155. package/dist-engine-src/src/sql2/udfs/lix_json_get_text.rs +99 -0
  156. package/dist-engine-src/src/sql2/udfs/lix_text_decode.rs +82 -0
  157. package/dist-engine-src/src/sql2/udfs/lix_text_encode.rs +85 -0
  158. package/dist-engine-src/src/sql2/udfs/lix_timestamp.rs +76 -0
  159. package/dist-engine-src/src/sql2/udfs/lix_uuid_v7.rs +76 -0
  160. package/dist-engine-src/src/sql2/udfs/mod.rs +89 -0
  161. package/dist-engine-src/src/sql2/udfs/public_call.rs +211 -0
  162. package/dist-engine-src/src/sql2/version_provider.rs +1202 -0
  163. package/dist-engine-src/src/sql2/version_scope.rs +394 -0
  164. package/dist-engine-src/src/sql2/write_normalization.rs +345 -0
  165. package/dist-engine-src/src/storage/context.rs +356 -0
  166. package/dist-engine-src/src/storage/mod.rs +14 -0
  167. package/dist-engine-src/src/storage/read_scope.rs +88 -0
  168. package/dist-engine-src/src/storage/types.rs +501 -0
  169. package/dist-engine-src/src/storage_bench.rs +4863 -0
  170. package/dist-engine-src/src/test_support.rs +228 -0
  171. package/dist-engine-src/src/tracked_state/by_file_index.rs +98 -0
  172. package/dist-engine-src/src/tracked_state/codec.rs +2085 -0
  173. package/dist-engine-src/src/tracked_state/context.rs +1867 -0
  174. package/dist-engine-src/src/tracked_state/diff.rs +686 -0
  175. package/dist-engine-src/src/tracked_state/materialization.rs +403 -0
  176. package/dist-engine-src/src/tracked_state/materializer.rs +488 -0
  177. package/dist-engine-src/src/tracked_state/merge.rs +492 -0
  178. package/dist-engine-src/src/tracked_state/mod.rs +32 -0
  179. package/dist-engine-src/src/tracked_state/storage.rs +375 -0
  180. package/dist-engine-src/src/tracked_state/tree.rs +3187 -0
  181. package/dist-engine-src/src/tracked_state/types.rs +231 -0
  182. package/dist-engine-src/src/transaction/commit.rs +1484 -0
  183. package/dist-engine-src/src/transaction/context.rs +1548 -0
  184. package/dist-engine-src/src/transaction/live_state_overlay.rs +35 -0
  185. package/dist-engine-src/src/transaction/mod.rs +13 -0
  186. package/dist-engine-src/src/transaction/normalization.rs +890 -0
  187. package/dist-engine-src/src/transaction/prep.rs +37 -0
  188. package/dist-engine-src/src/transaction/schema_resolver.rs +149 -0
  189. package/dist-engine-src/src/transaction/staging.rs +1731 -0
  190. package/dist-engine-src/src/transaction/types.rs +460 -0
  191. package/dist-engine-src/src/transaction/validation.rs +5830 -0
  192. package/dist-engine-src/src/untracked_state/codec.rs +307 -0
  193. package/dist-engine-src/src/untracked_state/context.rs +98 -0
  194. package/dist-engine-src/src/untracked_state/materialization.rs +63 -0
  195. package/dist-engine-src/src/untracked_state/mod.rs +15 -0
  196. package/dist-engine-src/src/untracked_state/storage.rs +396 -0
  197. package/dist-engine-src/src/untracked_state/types.rs +146 -0
  198. package/dist-engine-src/src/version/context.rs +40 -0
  199. package/dist-engine-src/src/version/lifecycle.rs +221 -0
  200. package/dist-engine-src/src/version/mod.rs +13 -0
  201. package/dist-engine-src/src/version/refs.rs +330 -0
  202. package/dist-engine-src/src/version/stage_rows.rs +67 -0
  203. package/dist-engine-src/src/version/types.rs +21 -0
  204. package/dist-engine-src/src/wasm/mod.rs +60 -0
  205. package/package.json +68 -64
@@ -0,0 +1,168 @@
1
+ use std::collections::{BTreeMap, BTreeSet};
2
+
3
+ use serde_json::Value as JsonValue;
4
+
5
+ use crate::schema::schema_key_from_definition;
6
+ use crate::LixError;
7
+
8
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
9
+ pub(crate) enum Capability {
10
+ Allowed,
11
+ ReadOnly(&'static str),
12
+ Unsupported(&'static str),
13
+ }
14
+
15
+ #[derive(Clone, Debug)]
16
+ pub(crate) struct ColumnContract {
17
+ pub(crate) writable: bool,
18
+ }
19
+
20
+ #[derive(Clone, Debug)]
21
+ pub(crate) struct TableContract {
22
+ pub(crate) insert: Capability,
23
+ pub(crate) update: Capability,
24
+ pub(crate) delete: Capability,
25
+ pub(crate) columns: BTreeMap<String, ColumnContract>,
26
+ }
27
+
28
+ impl TableContract {
29
+ pub(crate) fn operation(&self, operation: super::DmlOperation) -> Capability {
30
+ match operation {
31
+ super::DmlOperation::Insert => self.insert,
32
+ super::DmlOperation::Update => self.update,
33
+ super::DmlOperation::Delete => self.delete,
34
+ }
35
+ }
36
+
37
+ pub(crate) fn column(&self, column: &str) -> Option<&ColumnContract> {
38
+ self.columns.get(column)
39
+ }
40
+ }
41
+
42
+ #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
43
+ pub(crate) struct PublicSurface {
44
+ name: String,
45
+ }
46
+
47
+ impl PublicSurface {
48
+ pub(crate) fn named(name: impl Into<String>) -> Self {
49
+ Self {
50
+ name: name.into().to_ascii_lowercase(),
51
+ }
52
+ }
53
+
54
+ pub(crate) fn name(&self) -> &str {
55
+ &self.name
56
+ }
57
+ }
58
+
59
+ #[derive(Clone, Debug)]
60
+ pub(crate) struct PublicTableContracts {
61
+ contracts: BTreeMap<String, TableContract>,
62
+ }
63
+
64
+ impl PublicTableContracts {
65
+ pub(crate) fn new(visible_schemas: &[JsonValue]) -> Result<Self, LixError> {
66
+ let mut contracts = builtin_contracts();
67
+ for schema in visible_schemas {
68
+ let schema_key = schema_key_from_definition(schema)?.schema_key;
69
+ contracts.insert(
70
+ format!("{}_history", schema_key.to_ascii_lowercase()),
71
+ history_contract(),
72
+ );
73
+ }
74
+ Ok(Self { contracts })
75
+ }
76
+
77
+ pub(crate) fn get(&self, surface: &PublicSurface) -> Option<&TableContract> {
78
+ self.contracts.get(surface.name())
79
+ }
80
+ }
81
+
82
+ fn builtin_contracts() -> BTreeMap<String, TableContract> {
83
+ let mut contracts = BTreeMap::new();
84
+
85
+ for table in [
86
+ "lix_change",
87
+ "lix_commit",
88
+ "lix_commit_by_version",
89
+ "lix_commit_edge",
90
+ "lix_commit_edge_by_version",
91
+ "lix_change_set",
92
+ "lix_change_set_by_version",
93
+ "lix_change_set_element",
94
+ "lix_change_set_element_by_version",
95
+ ] {
96
+ contracts.insert(table.to_string(), commit_graph_contract());
97
+ }
98
+
99
+ for table in [
100
+ "lix_state_history",
101
+ "lix_file_history",
102
+ "lix_directory_history",
103
+ ] {
104
+ contracts.insert(table.to_string(), history_contract());
105
+ }
106
+
107
+ contracts.insert(
108
+ "lix_registered_schema".to_string(),
109
+ TableContract {
110
+ insert: Capability::Allowed,
111
+ update: Capability::Allowed,
112
+ delete: Capability::Unsupported(
113
+ "lix_registered_schema deletion is not supported; register an amended schema instead",
114
+ ),
115
+ columns: columns(&["value", "lixcol_metadata", "lixcol_global", "lixcol_untracked"]),
116
+ },
117
+ );
118
+
119
+ contracts.insert(
120
+ "lix_key_value".to_string(),
121
+ TableContract {
122
+ insert: Capability::Allowed,
123
+ update: Capability::Allowed,
124
+ delete: Capability::Allowed,
125
+ columns: columns(&["key", "value", "lixcol_metadata"]),
126
+ },
127
+ );
128
+
129
+ contracts
130
+ }
131
+
132
+ fn commit_graph_contract() -> TableContract {
133
+ TableContract {
134
+ insert: Capability::ReadOnly(
135
+ "Commit graph and changelog surfaces are read-only; Lix creates them when transactions commit.",
136
+ ),
137
+ update: Capability::ReadOnly(
138
+ "Commit graph and changelog surfaces are read-only; Lix creates them when transactions commit.",
139
+ ),
140
+ delete: Capability::ReadOnly(
141
+ "Commit graph and changelog surfaces are read-only; Lix creates them when transactions commit.",
142
+ ),
143
+ columns: BTreeMap::new(),
144
+ }
145
+ }
146
+
147
+ fn history_contract() -> TableContract {
148
+ TableContract {
149
+ insert: Capability::ReadOnly(
150
+ "History views are query-only; write to the live surface such as lix_state, lix_file, lix_directory, or the typed entity table.",
151
+ ),
152
+ update: Capability::ReadOnly(
153
+ "History views are query-only; write to the live surface such as lix_state, lix_file, lix_directory, or the typed entity table.",
154
+ ),
155
+ delete: Capability::ReadOnly(
156
+ "History views are query-only; write to the live surface such as lix_state, lix_file, lix_directory, or the typed entity table.",
157
+ ),
158
+ columns: BTreeMap::new(),
159
+ }
160
+ }
161
+
162
+ fn columns(writable: &[&str]) -> BTreeMap<String, ColumnContract> {
163
+ let writable = writable.iter().copied().collect::<BTreeSet<_>>();
164
+ writable
165
+ .into_iter()
166
+ .map(|column| (column.to_string(), ColumnContract { writable: true }))
167
+ .collect()
168
+ }
@@ -0,0 +1,63 @@
1
+ use datafusion::error::DataFusionError;
2
+
3
+ use crate::transaction::types::TransactionWriteRow;
4
+ use crate::LixError;
5
+
6
+ pub(crate) fn reject_read_only_entity_surface(
7
+ schema_key: &str,
8
+ action: &str,
9
+ ) -> Result<(), DataFusionError> {
10
+ if schema_key == "lix_directory_descriptor" {
11
+ return Err(read_only_error(
12
+ action,
13
+ schema_key,
14
+ "Use the writable lix_directory surface to create, update, or delete directories.",
15
+ ));
16
+ }
17
+ if let Some(message) = read_only_schema_message(schema_key) {
18
+ return Err(read_only_error(action, schema_key, message));
19
+ }
20
+ Ok(())
21
+ }
22
+
23
+ pub(crate) fn reject_read_only_stage_rows(
24
+ rows: &[TransactionWriteRow],
25
+ action: &str,
26
+ ) -> Result<(), DataFusionError> {
27
+ for row in rows {
28
+ if let Some(message) = read_only_schema_message(&row.schema_key) {
29
+ return Err(read_only_error(action, &row.schema_key, message));
30
+ }
31
+ }
32
+ Ok(())
33
+ }
34
+
35
+ fn read_only_error(action: &str, schema_key: &str, message: &'static str) -> DataFusionError {
36
+ super::error::lix_error_to_datafusion_error(
37
+ LixError::new(
38
+ LixError::CODE_READ_ONLY,
39
+ format!("{action} cannot write read-only surface '{schema_key}'"),
40
+ )
41
+ .with_hint(message),
42
+ )
43
+ }
44
+
45
+ fn read_only_schema_message(schema_key: &str) -> Option<&'static str> {
46
+ match schema_key {
47
+ "lix_version_descriptor" | "lix_version_ref" => {
48
+ Some("Use the writable lix_version surface to create, update, or delete versions.")
49
+ }
50
+ "lix_file_descriptor" => {
51
+ Some("Use the writable lix_file surface to create, update, or delete files.")
52
+ }
53
+ "lix_binary_blob_ref" => {
54
+ Some("Use the writable lix_file data column to create, update, or delete file contents.")
55
+ }
56
+ "lix_commit"
57
+ | "lix_commit_edge"
58
+ | "lix_change" => Some(
59
+ "Commit graph and changelog surfaces are read-only; Lix creates them when transactions commit.",
60
+ ),
61
+ _ => None,
62
+ }
63
+ }
@@ -0,0 +1,17 @@
1
+ use datafusion::arrow::array::ArrayRef;
2
+ use datafusion::arrow::datatypes::SchemaRef;
3
+ use datafusion::arrow::record_batch::{RecordBatch, RecordBatchOptions};
4
+ use datafusion::common::{DataFusionError, Result};
5
+
6
+ pub(crate) fn record_batch_with_row_count(
7
+ schema: SchemaRef,
8
+ columns: Vec<ArrayRef>,
9
+ row_count: usize,
10
+ ) -> Result<RecordBatch> {
11
+ if schema.fields().is_empty() {
12
+ let options = RecordBatchOptions::new().with_row_count(Some(row_count));
13
+ return RecordBatch::try_new_with_options(schema, columns, &options)
14
+ .map_err(DataFusionError::from);
15
+ }
16
+ RecordBatch::try_new(schema, columns).map_err(DataFusionError::from)
17
+ }
@@ -0,0 +1,29 @@
1
+ use std::collections::HashMap;
2
+
3
+ use datafusion::arrow::datatypes::Field;
4
+
5
+ pub(crate) const LIX_VALUE_TYPE_METADATA_KEY: &str = "lix.value_type";
6
+ pub(crate) const LIX_VALUE_TYPE_JSON: &str = "json";
7
+
8
+ pub(crate) fn json_field(name: impl Into<String>, nullable: bool) -> Field {
9
+ Field::new(name, datafusion::arrow::datatypes::DataType::Utf8, nullable)
10
+ .with_metadata(json_field_metadata_map())
11
+ }
12
+
13
+ pub(crate) fn mark_json_field(field: Field) -> Field {
14
+ field.with_metadata(json_field_metadata_map())
15
+ }
16
+
17
+ pub(crate) fn field_is_json(field: &Field) -> bool {
18
+ field
19
+ .metadata()
20
+ .get(LIX_VALUE_TYPE_METADATA_KEY)
21
+ .is_some_and(|value| value == LIX_VALUE_TYPE_JSON)
22
+ }
23
+
24
+ fn json_field_metadata_map() -> HashMap<String, String> {
25
+ HashMap::from([(
26
+ LIX_VALUE_TYPE_METADATA_KEY.to_string(),
27
+ LIX_VALUE_TYPE_JSON.to_string(),
28
+ )])
29
+ }
@@ -0,0 +1,60 @@
1
+ use std::sync::Arc;
2
+
3
+ use datafusion::arrow::record_batch::RecordBatch;
4
+ use datafusion::dataframe::DataFrame;
5
+ use datafusion::error::Result;
6
+ use datafusion::execution::TaskContext;
7
+ use datafusion::physical_plan::{ExecutionPlan, ExecutionPlanProperties};
8
+ use futures_util::TryStreamExt;
9
+
10
+ pub(crate) async fn collect_dataframe(dataframe: DataFrame) -> Result<Vec<RecordBatch>> {
11
+ let task_ctx = Arc::new(dataframe.task_ctx());
12
+ let plan = dataframe.create_physical_plan().await?;
13
+ collect_input_plan(plan, task_ctx).await
14
+ }
15
+
16
+ pub(crate) async fn collect_input_plan(
17
+ plan: Arc<dyn ExecutionPlan>,
18
+ task_ctx: Arc<TaskContext>,
19
+ ) -> Result<Vec<RecordBatch>> {
20
+ validate_physical_plan(&plan)?;
21
+ let partition_count = plan.output_partitioning().partition_count();
22
+ let mut batches = Vec::new();
23
+ for partition in 0..partition_count {
24
+ let partition_batches = plan
25
+ .execute(partition, Arc::clone(&task_ctx))?
26
+ .try_collect::<Vec<_>>()
27
+ .await?;
28
+ batches.extend(partition_batches);
29
+ }
30
+ Ok(batches)
31
+ }
32
+
33
+ #[cfg(not(target_arch = "wasm32"))]
34
+ fn validate_physical_plan(_plan: &Arc<dyn ExecutionPlan>) -> Result<()> {
35
+ Ok(())
36
+ }
37
+
38
+ #[cfg(target_arch = "wasm32")]
39
+ fn validate_physical_plan(plan: &Arc<dyn ExecutionPlan>) -> Result<()> {
40
+ let operator_name = plan.name();
41
+ if is_wasm_unsafe_operator(operator_name) {
42
+ return Err(datafusion::error::DataFusionError::Plan(format!(
43
+ "SQL physical operator '{operator_name}' is not supported by the WebAssembly runtime yet"
44
+ )));
45
+ }
46
+
47
+ for child in plan.children() {
48
+ validate_physical_plan(child)?;
49
+ }
50
+
51
+ Ok(())
52
+ }
53
+
54
+ #[cfg(target_arch = "wasm32")]
55
+ fn is_wasm_unsafe_operator(operator_name: &str) -> bool {
56
+ matches!(
57
+ operator_name,
58
+ "CoalescePartitionsExec" | "RepartitionExec" | "SortPreservingMergeExec"
59
+ )
60
+ }
@@ -0,0 +1,132 @@
1
+ use std::sync::Arc;
2
+
3
+ use datafusion::prelude::{SessionConfig, SessionContext};
4
+
5
+ use crate::LixError;
6
+
7
+ use super::change_provider::register_lix_change_provider;
8
+ use super::directory_history_provider::register_lix_directory_history_provider;
9
+ use super::directory_provider::{
10
+ register_lix_directory_providers, register_lix_directory_write_providers,
11
+ };
12
+ use super::entity_provider::{register_entity_providers, register_entity_write_providers};
13
+ use super::file_history_provider::register_lix_file_history_provider;
14
+ use super::file_provider::{register_lix_file_providers, register_lix_file_write_providers};
15
+ use super::history_provider::register_history_providers;
16
+ use super::lix_state_provider::{register_lix_state_providers, register_lix_state_write_providers};
17
+ use super::udfs::register_sql2_functions;
18
+ use super::version_provider::{register_lix_version_provider, register_lix_version_write_provider};
19
+ use super::{SqlExecutionContext, SqlWriteContext, SqlWriteExecutionContext};
20
+
21
+ pub(crate) async fn build_read_session(
22
+ ctx: &dyn SqlExecutionContext,
23
+ ) -> Result<SessionContext, LixError> {
24
+ let session = new_sql_session_context();
25
+ let version_ref = ctx.version_ref();
26
+ let active_version_commit_id = version_ref
27
+ .load_head(ctx.active_version_id())
28
+ .await?
29
+ .map(|head| head.commit_id);
30
+ register_sql2_functions(&session, ctx.functions(), active_version_commit_id);
31
+ register_lix_state_providers(
32
+ &session,
33
+ ctx.active_version_id(),
34
+ ctx.live_state(),
35
+ Arc::clone(&version_ref),
36
+ )
37
+ .await?;
38
+ register_lix_version_provider(&session, ctx.live_state(), Arc::clone(&version_ref)).await?;
39
+ let commit_store_query_source = ctx.commit_store_query_source();
40
+ register_lix_change_provider(&session, commit_store_query_source.clone()).await?;
41
+ let state_history_commit_graph = ctx.commit_graph();
42
+ register_history_providers(
43
+ &session,
44
+ state_history_commit_graph,
45
+ commit_store_query_source.clone(),
46
+ )
47
+ .await?;
48
+ let file_history_commit_graph = ctx.commit_graph();
49
+ register_lix_file_history_provider(
50
+ &session,
51
+ file_history_commit_graph,
52
+ commit_store_query_source.clone(),
53
+ ctx.blob_reader(),
54
+ )
55
+ .await?;
56
+ let directory_history_commit_graph = ctx.commit_graph();
57
+ register_lix_directory_history_provider(
58
+ &session,
59
+ directory_history_commit_graph,
60
+ commit_store_query_source.clone(),
61
+ )
62
+ .await?;
63
+ let entity_commit_graph = Arc::new(tokio::sync::Mutex::new(ctx.commit_graph()));
64
+ register_lix_directory_providers(
65
+ &session,
66
+ ctx.active_version_id(),
67
+ ctx.live_state(),
68
+ Arc::clone(&version_ref),
69
+ ctx.functions(),
70
+ )
71
+ .await?;
72
+ register_lix_file_providers(
73
+ &session,
74
+ ctx.active_version_id(),
75
+ ctx.live_state(),
76
+ Arc::clone(&version_ref),
77
+ ctx.blob_reader(),
78
+ ctx.functions(),
79
+ )
80
+ .await?;
81
+ register_entity_providers(
82
+ &session,
83
+ ctx.active_version_id(),
84
+ ctx.live_state(),
85
+ Arc::clone(&version_ref),
86
+ entity_commit_graph,
87
+ commit_store_query_source,
88
+ &ctx.list_visible_schemas()?,
89
+ )
90
+ .await?;
91
+
92
+ Ok(session)
93
+ }
94
+
95
+ pub(crate) async fn build_write_session(
96
+ ctx: &mut dyn SqlWriteExecutionContext,
97
+ ) -> Result<SessionContext, LixError> {
98
+ let session = new_sql_session_context();
99
+ let write_ctx = SqlWriteContext::new(ctx);
100
+ let active_version_commit_id = write_ctx
101
+ .load_version_head(&write_ctx.active_version_id())
102
+ .await?;
103
+ register_sql2_functions(&session, write_ctx.functions(), active_version_commit_id);
104
+
105
+ register_lix_state_write_providers(&session, write_ctx.clone()).await?;
106
+ register_lix_version_write_provider(&session, write_ctx.clone()).await?;
107
+
108
+ register_lix_directory_write_providers(&session, write_ctx.clone()).await?;
109
+ register_lix_file_write_providers(&session, write_ctx.clone()).await?;
110
+ register_entity_write_providers(
111
+ &session,
112
+ write_ctx.clone(),
113
+ &write_ctx.list_visible_schemas()?,
114
+ )
115
+ .await?;
116
+
117
+ Ok(session)
118
+ }
119
+
120
+ pub(crate) fn new_sql_session_context() -> SessionContext {
121
+ SessionContext::new_with_config(
122
+ SessionConfig::new()
123
+ .with_information_schema(true)
124
+ .with_target_partitions(1)
125
+ .set_bool("datafusion.optimizer.repartition_aggregations", false)
126
+ .set_bool("datafusion.optimizer.repartition_joins", false)
127
+ .set_bool("datafusion.optimizer.repartition_sorts", false)
128
+ .set_bool("datafusion.optimizer.repartition_windows", false)
129
+ .set_bool("datafusion.optimizer.repartition_file_scans", false)
130
+ .set_bool("datafusion.optimizer.enable_round_robin_repartition", false),
131
+ )
132
+ }