@lix-js/sdk 0.6.0-preview.4 → 0.6.0-preview.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/README.md +1 -1
  2. package/SKILL.md +65 -64
  3. package/dist/engine-wasm/index.js +4 -4
  4. package/dist/engine-wasm/wasm/lix_engine.d.ts +5 -5
  5. package/dist/engine-wasm/wasm/lix_engine.js +130 -118
  6. package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
  7. package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +9 -8
  8. package/dist/generated/builtin-schemas.d.ts +69 -69
  9. package/dist/generated/builtin-schemas.js +94 -94
  10. package/dist/open-lix.d.ts +33 -26
  11. package/dist/open-lix.js +10 -10
  12. package/dist/sqlite/index.js +86 -30
  13. package/dist-engine-src/README.md +3 -3
  14. package/dist-engine-src/src/backend/capabilities.rs +67 -0
  15. package/dist-engine-src/src/backend/conformance/baseline.rs +1127 -0
  16. package/dist-engine-src/src/backend/conformance/factory.rs +93 -0
  17. package/dist-engine-src/src/backend/conformance/failure_tests.rs +608 -0
  18. package/dist-engine-src/src/backend/conformance/fixtures.rs +26 -0
  19. package/dist-engine-src/src/backend/conformance/mod.rs +75 -0
  20. package/dist-engine-src/src/backend/conformance/model.rs +28 -0
  21. package/dist-engine-src/src/backend/conformance/model_based.rs +257 -0
  22. package/dist-engine-src/src/backend/conformance/persistence.rs +204 -0
  23. package/dist-engine-src/src/backend/conformance/projection.rs +21 -0
  24. package/dist-engine-src/src/backend/conformance/pushdown.rs +24 -0
  25. package/dist-engine-src/src/backend/conformance/runner.rs +90 -0
  26. package/dist-engine-src/src/backend/conformance/scan.rs +24 -0
  27. package/dist-engine-src/src/backend/conformance/write.rs +16 -0
  28. package/dist-engine-src/src/backend/error.rs +94 -0
  29. package/dist-engine-src/src/backend/in_memory.rs +670 -0
  30. package/dist-engine-src/src/backend/mod.rs +36 -9
  31. package/dist-engine-src/src/backend/predicate.rs +80 -0
  32. package/dist-engine-src/src/backend/traits.rs +260 -0
  33. package/dist-engine-src/src/backend/types.rs +224 -81
  34. package/dist-engine-src/src/binary_cas/context.rs +8 -8
  35. package/dist-engine-src/src/binary_cas/kv.rs +234 -259
  36. package/dist-engine-src/src/{version → branch}/context.rs +12 -12
  37. package/dist-engine-src/src/branch/lifecycle.rs +221 -0
  38. package/dist-engine-src/src/branch/mod.rs +13 -0
  39. package/dist-engine-src/src/branch/refs.rs +321 -0
  40. package/dist-engine-src/src/branch/stage_rows.rs +67 -0
  41. package/dist-engine-src/src/branch/types.rs +21 -0
  42. package/dist-engine-src/src/catalog/context.rs +18 -18
  43. package/dist-engine-src/src/catalog/snapshot.rs +8 -8
  44. package/dist-engine-src/src/changelog/bench_support.rs +785 -0
  45. package/dist-engine-src/src/changelog/change.rs +1 -0
  46. package/dist-engine-src/src/changelog/codec.rs +497 -0
  47. package/dist-engine-src/src/changelog/commit.rs +1 -0
  48. package/dist-engine-src/src/changelog/context.rs +1614 -0
  49. package/dist-engine-src/src/changelog/mod.rs +29 -0
  50. package/dist-engine-src/src/changelog/store.rs +163 -0
  51. package/dist-engine-src/src/changelog/test_support.rs +54 -0
  52. package/dist-engine-src/src/changelog/types.rs +213 -0
  53. package/dist-engine-src/src/commit_graph/context.rs +317 -274
  54. package/dist-engine-src/src/commit_graph/mod.rs +2 -4
  55. package/dist-engine-src/src/commit_graph/types.rs +22 -42
  56. package/dist-engine-src/src/commit_graph/walker.rs +133 -103
  57. package/dist-engine-src/src/common/error.rs +52 -18
  58. package/dist-engine-src/src/common/identity.rs +2 -2
  59. package/dist-engine-src/src/common/mod.rs +1 -1
  60. package/dist-engine-src/src/domain.rs +42 -46
  61. package/dist-engine-src/src/engine.rs +74 -96
  62. package/dist-engine-src/src/{entity_identity.rs → entity_pk.rs} +89 -92
  63. package/dist-engine-src/src/functions/context.rs +56 -52
  64. package/dist-engine-src/src/functions/state.rs +51 -52
  65. package/dist-engine-src/src/init.rs +288 -154
  66. package/dist-engine-src/src/json_store/context.rs +15 -266
  67. package/dist-engine-src/src/json_store/mod.rs +26 -0
  68. package/dist-engine-src/src/json_store/store.rs +103 -718
  69. package/dist-engine-src/src/json_store/types.rs +4 -9
  70. package/dist-engine-src/src/lib.rs +49 -19
  71. package/dist-engine-src/src/live_state/context.rs +654 -790
  72. package/dist-engine-src/src/live_state/mod.rs +9 -3
  73. package/dist-engine-src/src/live_state/overlay.rs +4 -4
  74. package/dist-engine-src/src/live_state/types.rs +30 -21
  75. package/dist-engine-src/src/live_state/visibility.rs +514 -71
  76. package/dist-engine-src/src/plugin/install.rs +48 -48
  77. package/dist-engine-src/src/plugin/manifest.rs +7 -7
  78. package/dist-engine-src/src/plugin/materializer.rs +0 -275
  79. package/dist-engine-src/src/plugin/plugin_manifest.json +4 -3
  80. package/dist-engine-src/src/schema/builtin/lix_binary_blob_ref.json +2 -2
  81. package/dist-engine-src/src/schema/builtin/lix_branch_descriptor.json +34 -0
  82. package/dist-engine-src/src/schema/builtin/lix_branch_ref.json +48 -0
  83. package/dist-engine-src/src/schema/builtin/lix_change.json +3 -3
  84. package/dist-engine-src/src/schema/builtin/lix_commit.json +1 -1
  85. package/dist-engine-src/src/schema/builtin/lix_label_assignment.json +6 -6
  86. package/dist-engine-src/src/schema/builtin/mod.rs +18 -20
  87. package/dist-engine-src/src/schema/compatibility.rs +11 -11
  88. package/dist-engine-src/src/schema/definition.json +2 -2
  89. package/dist-engine-src/src/schema/definition.rs +5 -5
  90. package/dist-engine-src/src/schema/key.rs +3 -3
  91. package/dist-engine-src/src/schema/mod.rs +1 -1
  92. package/dist-engine-src/src/schema/tests.rs +18 -18
  93. package/dist-engine-src/src/session/context.rs +803 -148
  94. package/dist-engine-src/src/session/create_branch.rs +94 -0
  95. package/dist-engine-src/src/session/execute.rs +223 -83
  96. package/dist-engine-src/src/session/merge/analysis.rs +9 -3
  97. package/dist-engine-src/src/session/merge/{version.rs → branch.rs} +119 -129
  98. package/dist-engine-src/src/session/merge/conflicts.rs +2 -2
  99. package/dist-engine-src/src/session/merge/mod.rs +5 -6
  100. package/dist-engine-src/src/session/merge/stats.rs +7 -11
  101. package/dist-engine-src/src/session/mod.rs +15 -12
  102. package/dist-engine-src/src/session/switch_branch.rs +113 -0
  103. package/dist-engine-src/src/session/transaction.rs +495 -14
  104. package/dist-engine-src/src/sql2/{classify.rs → bind/classify.rs} +3 -75
  105. package/dist-engine-src/src/sql2/bind/error.rs +5 -0
  106. package/dist-engine-src/src/sql2/bind/expr.rs +29 -0
  107. package/dist-engine-src/src/sql2/bind/mod.rs +12 -0
  108. package/dist-engine-src/src/sql2/{udfs/public_call.rs → bind/public_udf.rs} +71 -3
  109. package/dist-engine-src/src/sql2/bind/read.rs +65 -0
  110. package/dist-engine-src/src/sql2/bind/statement.rs +2236 -0
  111. package/dist-engine-src/src/sql2/bind/table.rs +273 -0
  112. package/dist-engine-src/src/sql2/bind/write.rs +86 -0
  113. package/dist-engine-src/src/sql2/branch_scope.rs +436 -0
  114. package/dist-engine-src/src/sql2/catalog/capability.rs +20 -0
  115. package/dist-engine-src/src/sql2/catalog/entity_surface.rs +296 -0
  116. package/dist-engine-src/src/sql2/catalog/mod.rs +15 -0
  117. package/dist-engine-src/src/sql2/catalog/registry.rs +556 -0
  118. package/dist-engine-src/src/sql2/catalog/schema.rs +88 -0
  119. package/dist-engine-src/src/sql2/catalog/surface.rs +41 -0
  120. package/dist-engine-src/src/sql2/change_materialization.rs +122 -0
  121. package/dist-engine-src/src/sql2/context.rs +36 -30
  122. package/dist-engine-src/src/sql2/error.rs +1 -1
  123. package/dist-engine-src/src/sql2/exec/bound_public_write.rs +1593 -0
  124. package/dist-engine-src/src/sql2/exec/datafusion.rs +5266 -0
  125. package/dist-engine-src/src/sql2/exec/fast_write.rs +82 -0
  126. package/dist-engine-src/src/sql2/exec/mod.rs +24 -0
  127. package/dist-engine-src/src/sql2/exec/write.rs +661 -0
  128. package/dist-engine-src/src/sql2/filesystem_planner.rs +72 -77
  129. package/dist-engine-src/src/sql2/filesystem_visibility.rs +21 -21
  130. package/dist-engine-src/src/sql2/history_projection.rs +8 -8
  131. package/dist-engine-src/src/sql2/history_route.rs +35 -31
  132. package/dist-engine-src/src/sql2/mod.rs +28 -23
  133. package/dist-engine-src/src/sql2/optimize/datafusion.rs +1 -0
  134. package/dist-engine-src/src/sql2/optimize/mod.rs +2 -0
  135. package/dist-engine-src/src/sql2/optimize/simple_write.rs +116 -0
  136. package/dist-engine-src/src/sql2/parse/mod.rs +69 -0
  137. package/dist-engine-src/src/sql2/parse/normalize.rs +1 -0
  138. package/dist-engine-src/src/sql2/plan/branch_scope.rs +24 -0
  139. package/dist-engine-src/src/sql2/plan/mod.rs +5 -0
  140. package/dist-engine-src/src/sql2/plan/predicate.rs +22 -0
  141. package/dist-engine-src/src/sql2/plan/write.rs +147 -0
  142. package/dist-engine-src/src/sql2/predicate_typecheck.rs +258 -0
  143. package/dist-engine-src/src/sql2/{version_provider.rs → providers/branch.rs} +218 -214
  144. package/dist-engine-src/src/sql2/{change_provider.rs → providers/change.rs} +156 -42
  145. package/dist-engine-src/src/sql2/{directory_provider.rs → providers/directory.rs} +291 -322
  146. package/dist-engine-src/src/sql2/{directory_history_provider.rs → providers/directory_history.rs} +56 -42
  147. package/dist-engine-src/src/sql2/providers/entity.rs +1484 -0
  148. package/dist-engine-src/src/sql2/{entity_history_provider.rs → providers/entity_history.rs} +43 -31
  149. package/dist-engine-src/src/sql2/{file_provider.rs → providers/file.rs} +323 -316
  150. package/dist-engine-src/src/sql2/{file_history_provider.rs → providers/file_history.rs} +60 -46
  151. package/dist-engine-src/src/sql2/{history_provider.rs → providers/history.rs} +46 -32
  152. package/dist-engine-src/src/sql2/{lix_state_provider.rs → providers/lix_state.rs} +359 -329
  153. package/dist-engine-src/src/sql2/providers/mod.rs +508 -0
  154. package/dist-engine-src/src/sql2/read_only.rs +2 -2
  155. package/dist-engine-src/src/sql2/session.rs +47 -96
  156. package/dist-engine-src/src/sql2/storage/constraints.rs +1 -0
  157. package/dist-engine-src/src/sql2/storage/mod.rs +1 -0
  158. package/dist-engine-src/src/sql2/test_support/differential.rs +712 -0
  159. package/dist-engine-src/src/sql2/test_support/generators.rs +354 -0
  160. package/dist-engine-src/src/sql2/test_support/mod.rs +2 -0
  161. package/dist-engine-src/src/sql2/udfs/{lix_active_version_commit_id.rs → lix_active_branch_commit_id.rs} +7 -7
  162. package/dist-engine-src/src/sql2/udfs/mod.rs +3 -6
  163. package/dist-engine-src/src/sql2/write_normalization.rs +45 -22
  164. package/dist-engine-src/src/storage/conformance.rs +399 -0
  165. package/dist-engine-src/src/storage/context.rs +552 -288
  166. package/dist-engine-src/src/storage/mod.rs +48 -10
  167. package/dist-engine-src/src/storage/point.rs +440 -0
  168. package/dist-engine-src/src/storage/read_scope.rs +43 -64
  169. package/dist-engine-src/src/storage/reader.rs +867 -0
  170. package/dist-engine-src/src/storage/scan.rs +784 -0
  171. package/dist-engine-src/src/storage/spaces.rs +236 -0
  172. package/dist-engine-src/src/storage/stats.rs +80 -0
  173. package/dist-engine-src/src/storage/write_set.rs +962 -0
  174. package/dist-engine-src/src/storage_bench.rs +136 -4828
  175. package/dist-engine-src/src/test_support.rs +360 -138
  176. package/dist-engine-src/src/tracked_state/bench_support.rs +394 -0
  177. package/dist-engine-src/src/tracked_state/codec.rs +155 -1057
  178. package/dist-engine-src/src/tracked_state/commit_root_rebuild.rs +358 -0
  179. package/dist-engine-src/src/tracked_state/context.rs +1927 -993
  180. package/dist-engine-src/src/tracked_state/diff.rs +1715 -261
  181. package/dist-engine-src/src/tracked_state/merge.rs +74 -88
  182. package/dist-engine-src/src/tracked_state/mod.rs +19 -16
  183. package/dist-engine-src/src/tracked_state/{materialization.rs → row_materialization.rs} +50 -178
  184. package/dist-engine-src/src/tracked_state/storage.rs +243 -191
  185. package/dist-engine-src/src/tracked_state/tree.rs +247 -371
  186. package/dist-engine-src/src/tracked_state/types.rs +49 -42
  187. package/dist-engine-src/src/transaction/bench_support.rs +407 -0
  188. package/dist-engine-src/src/transaction/commit.rs +821 -713
  189. package/dist-engine-src/src/transaction/context.rs +705 -600
  190. package/dist-engine-src/src/transaction/mod.rs +13 -2
  191. package/dist-engine-src/src/transaction/normalization.rs +63 -76
  192. package/dist-engine-src/src/transaction/prep.rs +13 -13
  193. package/dist-engine-src/src/transaction/schema_resolver.rs +19 -5
  194. package/dist-engine-src/src/transaction/staging.rs +228 -434
  195. package/dist-engine-src/src/transaction/types.rs +41 -98
  196. package/dist-engine-src/src/transaction/validation.rs +382 -446
  197. package/dist-engine-src/src/untracked_state/codec.rs +337 -29
  198. package/dist-engine-src/src/untracked_state/context.rs +7 -7
  199. package/dist-engine-src/src/untracked_state/materialization.rs +2 -2
  200. package/dist-engine-src/src/untracked_state/mod.rs +1 -1
  201. package/dist-engine-src/src/untracked_state/storage.rs +659 -157
  202. package/dist-engine-src/src/untracked_state/types.rs +21 -21
  203. package/package.json +71 -68
  204. package/dist-engine-src/src/backend/kv.rs +0 -358
  205. package/dist-engine-src/src/backend/testing.rs +0 -658
  206. package/dist-engine-src/src/commit_store/codec.rs +0 -887
  207. package/dist-engine-src/src/commit_store/context.rs +0 -944
  208. package/dist-engine-src/src/commit_store/materialization.rs +0 -84
  209. package/dist-engine-src/src/commit_store/mod.rs +0 -16
  210. package/dist-engine-src/src/commit_store/storage.rs +0 -600
  211. package/dist-engine-src/src/commit_store/types.rs +0 -215
  212. package/dist-engine-src/src/schema/builtin/lix_version_descriptor.json +0 -34
  213. package/dist-engine-src/src/schema/builtin/lix_version_ref.json +0 -48
  214. package/dist-engine-src/src/session/create_version.rs +0 -88
  215. package/dist-engine-src/src/session/merge/apply.rs +0 -23
  216. package/dist-engine-src/src/session/optimization9_sql2_bench.rs +0 -100
  217. package/dist-engine-src/src/session/switch_version.rs +0 -110
  218. package/dist-engine-src/src/sql2/entity_provider.rs +0 -3211
  219. package/dist-engine-src/src/sql2/execute.rs +0 -3533
  220. package/dist-engine-src/src/sql2/public_bind/assignment.rs +0 -46
  221. package/dist-engine-src/src/sql2/public_bind/capability.rs +0 -41
  222. package/dist-engine-src/src/sql2/public_bind/dml.rs +0 -172
  223. package/dist-engine-src/src/sql2/public_bind/mod.rs +0 -26
  224. package/dist-engine-src/src/sql2/public_bind/table.rs +0 -168
  225. package/dist-engine-src/src/sql2/version_scope.rs +0 -394
  226. package/dist-engine-src/src/storage/types.rs +0 -501
  227. package/dist-engine-src/src/tracked_state/by_file_index.rs +0 -98
  228. package/dist-engine-src/src/tracked_state/materializer.rs +0 -488
  229. package/dist-engine-src/src/transaction/live_state_overlay.rs +0 -35
  230. package/dist-engine-src/src/version/lifecycle.rs +0 -221
  231. package/dist-engine-src/src/version/mod.rs +0 -13
  232. package/dist-engine-src/src/version/refs.rs +0 -330
  233. package/dist-engine-src/src/version/stage_rows.rs +0 -67
  234. package/dist-engine-src/src/version/types.rs +0 -21
@@ -0,0 +1,556 @@
1
+ use std::collections::BTreeMap;
2
+ #[cfg(test)]
3
+ use std::sync::Arc;
4
+
5
+ #[cfg(test)]
6
+ use datafusion::arrow::datatypes::{DataType, Field, Schema, SchemaRef};
7
+ use serde_json::Value as JsonValue;
8
+
9
+ use crate::LixError;
10
+
11
+ use super::{PublicColumn, PublicSurfaceContract, PublicSurfaceKind, SurfaceCapabilities};
12
+ #[cfg(test)]
13
+ use crate::sql2::catalog::entity_surface_schema;
14
+ use crate::sql2::catalog::{
15
+ derive_entity_surface_spec_from_schema, entity_system_fields,
16
+ schema_exposed_as_entity_history_surface, schema_exposed_as_entity_surface, EntitySurfaceShape,
17
+ EntitySurfaceSpec,
18
+ };
19
+ use crate::sql2::history_route::{
20
+ HISTORY_COL_CHANGE_ID, HISTORY_COL_COMMIT_CREATED_AT, HISTORY_COL_DEPTH, HISTORY_COL_ENTITY_PK,
21
+ HISTORY_COL_FILE_ID, HISTORY_COL_METADATA, HISTORY_COL_OBSERVED_COMMIT_ID,
22
+ HISTORY_COL_SCHEMA_KEY, HISTORY_COL_SNAPSHOT_CONTENT, HISTORY_COL_START_COMMIT_ID,
23
+ };
24
+ #[cfg(test)]
25
+ use crate::sql2::result_metadata::json_field;
26
+
27
+ #[derive(Clone, Debug, Default)]
28
+ pub(crate) struct PublicCatalog {
29
+ surfaces: BTreeMap<String, PublicSurfaceContract>,
30
+ entity_specs: BTreeMap<String, EntitySurfaceSpec>,
31
+ }
32
+
33
+ impl PublicCatalog {
34
+ pub(crate) fn from_visible_schemas(schema_definitions: &[JsonValue]) -> Result<Self, LixError> {
35
+ let mut catalog = Self::default();
36
+ catalog.insert_system_surfaces()?;
37
+ for schema in schema_definitions {
38
+ catalog.insert_entity_surfaces_from_schema(schema)?;
39
+ }
40
+ Ok(catalog)
41
+ }
42
+
43
+ pub(crate) fn insert(&mut self, surface: PublicSurfaceContract) -> Result<(), LixError> {
44
+ if self.surfaces.contains_key(&surface.name) {
45
+ return Err(LixError::new(
46
+ LixError::CODE_SCHEMA_DEFINITION,
47
+ format!("duplicate public SQL surface '{}'", surface.name),
48
+ ));
49
+ }
50
+ self.surfaces.insert(surface.name.clone(), surface);
51
+ Ok(())
52
+ }
53
+
54
+ pub(crate) fn surface(&self, table_name: &str) -> Option<&PublicSurfaceContract> {
55
+ self.surfaces.get(table_name)
56
+ }
57
+
58
+ pub(crate) fn surfaces(&self) -> impl Iterator<Item = &PublicSurfaceContract> {
59
+ self.surfaces.values()
60
+ }
61
+
62
+ pub(crate) fn entity_spec(&self, schema_key: &str) -> Option<&EntitySurfaceSpec> {
63
+ self.entity_specs.get(schema_key)
64
+ }
65
+
66
+ #[cfg(test)]
67
+ pub(crate) fn surface_schema(&self, table_name: &str) -> Option<SchemaRef> {
68
+ let surface = self.surface(table_name)?;
69
+ Some(match &surface.kind {
70
+ PublicSurfaceKind::LixState => lix_state_schema(false),
71
+ PublicSurfaceKind::LixStateByBranch => lix_state_schema(true),
72
+ PublicSurfaceKind::File => filesystem_schema(false, true),
73
+ PublicSurfaceKind::FileByBranch => filesystem_schema(true, true),
74
+ PublicSurfaceKind::Directory => filesystem_schema(false, false),
75
+ PublicSurfaceKind::DirectoryByBranch => filesystem_schema(true, false),
76
+ PublicSurfaceKind::Branch => Arc::new(Schema::new(vec![
77
+ Field::new("id", DataType::Utf8, false),
78
+ Field::new("name", DataType::Utf8, false),
79
+ Field::new("hidden", DataType::Boolean, false),
80
+ Field::new("commit_id", DataType::Utf8, false),
81
+ ])),
82
+ PublicSurfaceKind::Change => Arc::new(Schema::new(vec![
83
+ Field::new("id", DataType::Utf8, false),
84
+ json_field("entity_pk", false),
85
+ Field::new("schema_key", DataType::Utf8, false),
86
+ Field::new("file_id", DataType::Utf8, true),
87
+ json_field("metadata", true),
88
+ Field::new("created_at", DataType::Utf8, false),
89
+ json_field("snapshot_content", true),
90
+ ])),
91
+ PublicSurfaceKind::History => Arc::new(Schema::new(vec![
92
+ json_field("entity_pk", false),
93
+ Field::new("schema_key", DataType::Utf8, false),
94
+ Field::new("file_id", DataType::Utf8, true),
95
+ json_field("snapshot_content", true),
96
+ json_field("metadata", true),
97
+ Field::new("change_id", DataType::Utf8, false),
98
+ Field::new("observed_commit_id", DataType::Utf8, false),
99
+ Field::new("commit_created_at", DataType::Utf8, false),
100
+ Field::new("start_commit_id", DataType::Utf8, false),
101
+ Field::new("depth", DataType::Int64, false),
102
+ ])),
103
+ PublicSurfaceKind::FileHistory => history_filesystem_schema(true),
104
+ PublicSurfaceKind::DirectoryHistory => history_filesystem_schema(false),
105
+ PublicSurfaceKind::EntityBase { schema_key } => {
106
+ entity_surface_schema(self.entity_spec(schema_key)?, EntitySurfaceShape::Active)
107
+ }
108
+ PublicSurfaceKind::EntityByBranch { schema_key } => {
109
+ entity_surface_schema(self.entity_spec(schema_key)?, EntitySurfaceShape::ByBranch)
110
+ }
111
+ PublicSurfaceKind::EntityHistory { schema_key } => {
112
+ entity_surface_schema(self.entity_spec(schema_key)?, EntitySurfaceShape::History)
113
+ }
114
+ })
115
+ }
116
+
117
+ pub(crate) fn require_surface(
118
+ &self,
119
+ table_name: &str,
120
+ ) -> Result<&PublicSurfaceContract, LixError> {
121
+ self.surface(table_name).ok_or_else(|| {
122
+ LixError::new(
123
+ LixError::CODE_UNSUPPORTED_SQL,
124
+ format!("unknown SQL table '{table_name}'"),
125
+ )
126
+ })
127
+ }
128
+
129
+ fn insert_system_surfaces(&mut self) -> Result<(), LixError> {
130
+ self.insert(surface(
131
+ "lix_state",
132
+ PublicSurfaceKind::LixState,
133
+ lix_state_columns(false),
134
+ SurfaceCapabilities::read_write(),
135
+ ))?;
136
+ self.insert(surface(
137
+ "lix_state_by_branch",
138
+ PublicSurfaceKind::LixStateByBranch,
139
+ lix_state_columns(true),
140
+ SurfaceCapabilities::read_write(),
141
+ ))?;
142
+ self.insert(surface(
143
+ "lix_file",
144
+ PublicSurfaceKind::File,
145
+ filesystem_columns(false),
146
+ SurfaceCapabilities::read_write(),
147
+ ))?;
148
+ self.insert(surface(
149
+ "lix_file_by_branch",
150
+ PublicSurfaceKind::FileByBranch,
151
+ filesystem_columns(true),
152
+ SurfaceCapabilities::read_write(),
153
+ ))?;
154
+ self.insert(surface(
155
+ "lix_directory",
156
+ PublicSurfaceKind::Directory,
157
+ directory_columns(false),
158
+ SurfaceCapabilities::read_write(),
159
+ ))?;
160
+ self.insert(surface(
161
+ "lix_directory_by_branch",
162
+ PublicSurfaceKind::DirectoryByBranch,
163
+ directory_columns(true),
164
+ SurfaceCapabilities::read_write(),
165
+ ))?;
166
+ self.insert(surface(
167
+ "lix_branch",
168
+ PublicSurfaceKind::Branch,
169
+ vec![
170
+ PublicColumn::public_insert_only("id"),
171
+ PublicColumn::public("name"),
172
+ PublicColumn::public("hidden"),
173
+ PublicColumn::public("commit_id"),
174
+ ],
175
+ SurfaceCapabilities::read_write(),
176
+ ))?;
177
+ self.insert(surface(
178
+ "lix_change",
179
+ PublicSurfaceKind::Change,
180
+ public_columns([
181
+ "id",
182
+ "entity_pk",
183
+ "schema_key",
184
+ "file_id",
185
+ "metadata",
186
+ "created_at",
187
+ "snapshot_content",
188
+ ]),
189
+ SurfaceCapabilities::read_only(),
190
+ ))?;
191
+ self.insert(surface(
192
+ "lix_state_history",
193
+ PublicSurfaceKind::History,
194
+ state_history_columns(),
195
+ SurfaceCapabilities::read_only(),
196
+ ))?;
197
+ self.insert(surface(
198
+ "lix_file_history",
199
+ PublicSurfaceKind::FileHistory,
200
+ file_history_columns(),
201
+ SurfaceCapabilities::read_only(),
202
+ ))?;
203
+ self.insert(surface(
204
+ "lix_directory_history",
205
+ PublicSurfaceKind::DirectoryHistory,
206
+ directory_history_columns(),
207
+ SurfaceCapabilities::read_only(),
208
+ ))?;
209
+ Ok(())
210
+ }
211
+
212
+ fn insert_entity_surfaces_from_schema(&mut self, schema: &JsonValue) -> Result<(), LixError> {
213
+ let spec = match derive_entity_surface_spec_from_schema(schema) {
214
+ Ok(spec) => spec,
215
+ Err(_) => return Ok(()),
216
+ };
217
+
218
+ if !schema_exposed_as_entity_surface(&spec.schema_key) {
219
+ return Ok(());
220
+ };
221
+
222
+ let mut columns = entity_columns(&spec);
223
+ columns.extend(entity_hidden_columns(false));
224
+
225
+ self.insert(surface(
226
+ &spec.schema_key,
227
+ PublicSurfaceKind::EntityBase {
228
+ schema_key: spec.schema_key.clone(),
229
+ },
230
+ columns,
231
+ SurfaceCapabilities::read_write(),
232
+ ))?;
233
+
234
+ let mut by_branch_columns = entity_columns(&spec);
235
+ by_branch_columns.extend(entity_hidden_columns(true));
236
+
237
+ self.insert(surface(
238
+ format!("{}_by_branch", spec.schema_key),
239
+ PublicSurfaceKind::EntityByBranch {
240
+ schema_key: spec.schema_key.clone(),
241
+ },
242
+ by_branch_columns,
243
+ SurfaceCapabilities::read_write(),
244
+ ))?;
245
+
246
+ if schema_exposed_as_entity_history_surface(&spec.schema_key) {
247
+ let mut history_columns = spec
248
+ .columns
249
+ .iter()
250
+ .map(|column| PublicColumn::public(column.name.as_str()))
251
+ .collect::<Vec<_>>();
252
+ history_columns.extend(entity_system_columns(EntitySurfaceShape::History));
253
+
254
+ self.insert(surface(
255
+ format!("{}_history", spec.schema_key),
256
+ PublicSurfaceKind::EntityHistory {
257
+ schema_key: spec.schema_key.clone(),
258
+ },
259
+ history_columns,
260
+ SurfaceCapabilities::read_only(),
261
+ ))?;
262
+ }
263
+
264
+ self.entity_specs.insert(spec.schema_key.clone(), spec);
265
+ Ok(())
266
+ }
267
+ }
268
+
269
+ #[cfg(test)]
270
+ fn lix_state_schema(by_branch: bool) -> SchemaRef {
271
+ let mut fields = vec![
272
+ json_field("entity_pk", false),
273
+ Field::new("schema_key", DataType::Utf8, false),
274
+ Field::new("file_id", DataType::Utf8, true),
275
+ json_field("snapshot_content", true),
276
+ json_field("metadata", true),
277
+ Field::new("created_at", DataType::Utf8, true),
278
+ Field::new("updated_at", DataType::Utf8, true),
279
+ Field::new("global", DataType::Boolean, true),
280
+ Field::new("change_id", DataType::Utf8, true),
281
+ Field::new("commit_id", DataType::Utf8, true),
282
+ Field::new("untracked", DataType::Boolean, true),
283
+ ];
284
+ if by_branch {
285
+ fields.push(Field::new("branch_id", DataType::Utf8, false));
286
+ }
287
+ Arc::new(Schema::new(fields))
288
+ }
289
+
290
+ #[cfg(test)]
291
+ fn filesystem_schema(by_branch: bool, include_data: bool) -> SchemaRef {
292
+ let mut fields = if include_data {
293
+ vec![
294
+ Field::new("id", DataType::Utf8, true),
295
+ Field::new("path", DataType::Utf8, false),
296
+ Field::new("directory_id", DataType::Utf8, true),
297
+ Field::new("name", DataType::Utf8, false),
298
+ Field::new("hidden", DataType::Boolean, true),
299
+ Field::new("data", DataType::Binary, true),
300
+ ]
301
+ } else {
302
+ vec![
303
+ Field::new("id", DataType::Utf8, true),
304
+ Field::new("path", DataType::Utf8, true),
305
+ Field::new("parent_id", DataType::Utf8, true),
306
+ Field::new("name", DataType::Utf8, false),
307
+ Field::new("hidden", DataType::Boolean, true),
308
+ ]
309
+ };
310
+ fields.extend([
311
+ json_field("lixcol_entity_pk", false),
312
+ Field::new("lixcol_schema_key", DataType::Utf8, false),
313
+ Field::new("lixcol_file_id", DataType::Utf8, true),
314
+ Field::new("lixcol_global", DataType::Boolean, true),
315
+ Field::new("lixcol_change_id", DataType::Utf8, true),
316
+ Field::new("lixcol_created_at", DataType::Utf8, true),
317
+ Field::new("lixcol_updated_at", DataType::Utf8, true),
318
+ Field::new("lixcol_commit_id", DataType::Utf8, true),
319
+ Field::new("lixcol_untracked", DataType::Boolean, true),
320
+ json_field("lixcol_metadata", true),
321
+ ]);
322
+ if by_branch {
323
+ fields.push(Field::new("lixcol_branch_id", DataType::Utf8, false));
324
+ }
325
+ Arc::new(Schema::new(fields))
326
+ }
327
+
328
+ #[cfg(test)]
329
+ fn history_filesystem_schema(include_data: bool) -> SchemaRef {
330
+ let mut fields = if include_data {
331
+ vec![
332
+ Field::new("id", DataType::Utf8, false),
333
+ Field::new("path", DataType::Utf8, true),
334
+ Field::new("directory_id", DataType::Utf8, true),
335
+ Field::new("name", DataType::Utf8, true),
336
+ Field::new("hidden", DataType::Boolean, true),
337
+ Field::new("data", DataType::Binary, true),
338
+ ]
339
+ } else {
340
+ vec![
341
+ Field::new("id", DataType::Utf8, false),
342
+ Field::new("path", DataType::Utf8, true),
343
+ Field::new("parent_id", DataType::Utf8, true),
344
+ Field::new("name", DataType::Utf8, true),
345
+ Field::new("hidden", DataType::Boolean, true),
346
+ ]
347
+ };
348
+ fields.extend([
349
+ json_field(HISTORY_COL_ENTITY_PK, false),
350
+ Field::new(HISTORY_COL_SCHEMA_KEY, DataType::Utf8, false),
351
+ Field::new(HISTORY_COL_FILE_ID, DataType::Utf8, true),
352
+ json_field(HISTORY_COL_SNAPSHOT_CONTENT, true),
353
+ Field::new(HISTORY_COL_CHANGE_ID, DataType::Utf8, false),
354
+ json_field(HISTORY_COL_METADATA, true),
355
+ Field::new(HISTORY_COL_OBSERVED_COMMIT_ID, DataType::Utf8, false),
356
+ Field::new(HISTORY_COL_COMMIT_CREATED_AT, DataType::Utf8, false),
357
+ Field::new(HISTORY_COL_START_COMMIT_ID, DataType::Utf8, false),
358
+ Field::new(HISTORY_COL_DEPTH, DataType::Int64, false),
359
+ ]);
360
+ Arc::new(Schema::new(fields))
361
+ }
362
+
363
+ fn surface(
364
+ name: impl Into<String>,
365
+ kind: PublicSurfaceKind,
366
+ columns: Vec<PublicColumn>,
367
+ capabilities: SurfaceCapabilities,
368
+ ) -> PublicSurfaceContract {
369
+ let columns = columns
370
+ .into_iter()
371
+ .enumerate()
372
+ .map(|(id, column)| column.with_id(id))
373
+ .collect();
374
+ PublicSurfaceContract {
375
+ name: name.into(),
376
+ kind,
377
+ columns,
378
+ capabilities,
379
+ }
380
+ }
381
+
382
+ fn public_columns<const N: usize>(names: [&str; N]) -> Vec<PublicColumn> {
383
+ names.into_iter().map(PublicColumn::public).collect()
384
+ }
385
+
386
+ fn entity_columns(spec: &EntitySurfaceSpec) -> Vec<PublicColumn> {
387
+ let primary_key_roots = spec
388
+ .primary_key_paths
389
+ .iter()
390
+ .filter_map(|path| path.first())
391
+ .collect::<std::collections::BTreeSet<_>>();
392
+ spec.columns
393
+ .iter()
394
+ .map(|column| {
395
+ if spec.schema_key == "lix_registered_schema" && column.name == "value" {
396
+ PublicColumn::public(column.name.as_str())
397
+ } else if primary_key_roots.contains(&column.name) {
398
+ PublicColumn::public_insert_only(column.name.as_str())
399
+ } else {
400
+ PublicColumn::public(column.name.as_str())
401
+ }
402
+ })
403
+ .collect()
404
+ }
405
+
406
+ fn lix_state_columns(by_branch: bool) -> Vec<PublicColumn> {
407
+ let mut columns = vec![
408
+ PublicColumn::public_insert_only("entity_pk"),
409
+ PublicColumn::public_insert_only("schema_key"),
410
+ PublicColumn::public_insert_only("file_id"),
411
+ PublicColumn::public("snapshot_content"),
412
+ PublicColumn::public("metadata"),
413
+ PublicColumn::public_insert_only("created_at"),
414
+ PublicColumn::public_insert_only("updated_at"),
415
+ PublicColumn::public_insert_only("global"),
416
+ PublicColumn::public_insert_only("change_id"),
417
+ PublicColumn::public_insert_only("commit_id"),
418
+ PublicColumn::public_insert_only("untracked"),
419
+ ];
420
+ if by_branch {
421
+ columns.push(PublicColumn::public_insert_only("branch_id"));
422
+ }
423
+ columns
424
+ }
425
+
426
+ fn filesystem_columns(by_branch: bool) -> Vec<PublicColumn> {
427
+ let mut columns = vec![
428
+ PublicColumn::public_insert_only("id"),
429
+ PublicColumn::public("path"),
430
+ PublicColumn::public("directory_id"),
431
+ PublicColumn::public("name"),
432
+ PublicColumn::public("hidden"),
433
+ PublicColumn::public("data"),
434
+ ];
435
+ columns.extend(filesystem_hidden_columns(by_branch));
436
+ columns
437
+ }
438
+
439
+ fn directory_columns(by_branch: bool) -> Vec<PublicColumn> {
440
+ let mut columns = vec![
441
+ PublicColumn::public_insert_only("id"),
442
+ PublicColumn::public_insert_only("path"),
443
+ PublicColumn::public("parent_id"),
444
+ PublicColumn::public("name"),
445
+ PublicColumn::public("hidden"),
446
+ ];
447
+ columns.extend(filesystem_hidden_columns(by_branch));
448
+ columns
449
+ }
450
+
451
+ fn entity_hidden_columns(by_branch: bool) -> Vec<PublicColumn> {
452
+ entity_system_columns(if by_branch {
453
+ EntitySurfaceShape::ByBranch
454
+ } else {
455
+ EntitySurfaceShape::Active
456
+ })
457
+ }
458
+
459
+ fn filesystem_hidden_columns(by_branch: bool) -> Vec<PublicColumn> {
460
+ let mut columns = vec![
461
+ PublicColumn::hidden("lixcol_entity_pk"),
462
+ PublicColumn::hidden("lixcol_schema_key"),
463
+ PublicColumn::hidden("lixcol_file_id"),
464
+ PublicColumn::public_insert_only("lixcol_global"),
465
+ PublicColumn::hidden("lixcol_change_id"),
466
+ PublicColumn::hidden("lixcol_created_at"),
467
+ PublicColumn::hidden("lixcol_updated_at"),
468
+ PublicColumn::hidden("lixcol_commit_id"),
469
+ PublicColumn::public_insert_only("lixcol_untracked"),
470
+ PublicColumn::public("lixcol_metadata"),
471
+ ];
472
+ if by_branch {
473
+ columns.push(PublicColumn::public_insert_only("lixcol_branch_id"));
474
+ }
475
+ columns
476
+ }
477
+
478
+ fn entity_system_columns(variant: EntitySurfaceShape) -> Vec<PublicColumn> {
479
+ if variant == EntitySurfaceShape::History {
480
+ return entity_system_fields(variant)
481
+ .into_iter()
482
+ .map(|field| PublicColumn::public(field.name().as_str()))
483
+ .collect();
484
+ }
485
+
486
+ entity_system_fields(variant)
487
+ .into_iter()
488
+ .map(|field| match field.name().as_str() {
489
+ "lixcol_schema_key" | "lixcol_change_id" | "lixcol_created_at"
490
+ | "lixcol_updated_at" | "lixcol_commit_id" => {
491
+ PublicColumn::public_read_only(field.name().as_str())
492
+ }
493
+ "lixcol_entity_pk" | "lixcol_global" | "lixcol_untracked" | "lixcol_branch_id" => {
494
+ PublicColumn::public_insert_only(field.name().as_str())
495
+ }
496
+ "lixcol_metadata" => PublicColumn::public(field.name().as_str()),
497
+ _ => PublicColumn::hidden(field.name().as_str()),
498
+ })
499
+ .collect()
500
+ }
501
+
502
+ fn state_history_columns() -> Vec<PublicColumn> {
503
+ public_columns([
504
+ "entity_pk",
505
+ "schema_key",
506
+ "file_id",
507
+ "snapshot_content",
508
+ "metadata",
509
+ "change_id",
510
+ "observed_commit_id",
511
+ "commit_created_at",
512
+ "start_commit_id",
513
+ "depth",
514
+ ])
515
+ }
516
+
517
+ fn file_history_columns() -> Vec<PublicColumn> {
518
+ public_columns([
519
+ "id",
520
+ "path",
521
+ "directory_id",
522
+ "name",
523
+ "hidden",
524
+ "data",
525
+ HISTORY_COL_ENTITY_PK,
526
+ HISTORY_COL_SCHEMA_KEY,
527
+ HISTORY_COL_FILE_ID,
528
+ HISTORY_COL_SNAPSHOT_CONTENT,
529
+ HISTORY_COL_CHANGE_ID,
530
+ HISTORY_COL_METADATA,
531
+ HISTORY_COL_OBSERVED_COMMIT_ID,
532
+ HISTORY_COL_COMMIT_CREATED_AT,
533
+ HISTORY_COL_START_COMMIT_ID,
534
+ HISTORY_COL_DEPTH,
535
+ ])
536
+ }
537
+
538
+ fn directory_history_columns() -> Vec<PublicColumn> {
539
+ public_columns([
540
+ "id",
541
+ "path",
542
+ "parent_id",
543
+ "name",
544
+ "hidden",
545
+ HISTORY_COL_ENTITY_PK,
546
+ HISTORY_COL_SCHEMA_KEY,
547
+ HISTORY_COL_FILE_ID,
548
+ HISTORY_COL_SNAPSHOT_CONTENT,
549
+ HISTORY_COL_CHANGE_ID,
550
+ HISTORY_COL_METADATA,
551
+ HISTORY_COL_OBSERVED_COMMIT_ID,
552
+ HISTORY_COL_COMMIT_CREATED_AT,
553
+ HISTORY_COL_START_COMMIT_ID,
554
+ HISTORY_COL_DEPTH,
555
+ ])
556
+ }
@@ -0,0 +1,88 @@
1
+ #[derive(Clone, Debug, Eq, PartialEq)]
2
+ pub(crate) struct PublicColumn {
3
+ pub(crate) id: usize,
4
+ pub(crate) name: String,
5
+ pub(crate) role: PublicColumnRole,
6
+ pub(crate) write: PublicColumnWrite,
7
+ }
8
+
9
+ impl PublicColumn {
10
+ pub(crate) fn public(name: impl Into<String>) -> Self {
11
+ Self {
12
+ id: 0,
13
+ name: name.into(),
14
+ role: PublicColumnRole::Public,
15
+ write: PublicColumnWrite::READ_WRITE,
16
+ }
17
+ }
18
+
19
+ pub(crate) fn public_insert_only(name: impl Into<String>) -> Self {
20
+ Self {
21
+ id: 0,
22
+ name: name.into(),
23
+ role: PublicColumnRole::Public,
24
+ write: PublicColumnWrite {
25
+ insert: true,
26
+ update: false,
27
+ },
28
+ }
29
+ }
30
+
31
+ pub(crate) fn public_read_only(name: impl Into<String>) -> Self {
32
+ Self {
33
+ id: 0,
34
+ name: name.into(),
35
+ role: PublicColumnRole::Public,
36
+ write: PublicColumnWrite::READ_ONLY,
37
+ }
38
+ }
39
+
40
+ pub(crate) fn hidden(name: impl Into<String>) -> Self {
41
+ Self {
42
+ id: 0,
43
+ name: name.into(),
44
+ role: PublicColumnRole::Hidden,
45
+ write: PublicColumnWrite::READ_ONLY,
46
+ }
47
+ }
48
+
49
+ pub(crate) fn is_public(&self) -> bool {
50
+ self.role == PublicColumnRole::Public
51
+ }
52
+
53
+ pub(crate) fn with_id(mut self, id: usize) -> Self {
54
+ self.id = id;
55
+ self
56
+ }
57
+
58
+ pub(crate) fn is_insertable(&self) -> bool {
59
+ self.write.insert
60
+ }
61
+
62
+ pub(crate) fn is_updatable(&self) -> bool {
63
+ self.write.update
64
+ }
65
+ }
66
+
67
+ #[derive(Clone, Debug, Eq, PartialEq)]
68
+ pub(crate) enum PublicColumnRole {
69
+ Public,
70
+ Hidden,
71
+ }
72
+
73
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
74
+ pub(crate) struct PublicColumnWrite {
75
+ insert: bool,
76
+ update: bool,
77
+ }
78
+
79
+ impl PublicColumnWrite {
80
+ const READ_WRITE: Self = Self {
81
+ insert: true,
82
+ update: true,
83
+ };
84
+ const READ_ONLY: Self = Self {
85
+ insert: false,
86
+ update: false,
87
+ };
88
+ }
@@ -0,0 +1,41 @@
1
+ use super::{PublicColumn, SurfaceCapabilities};
2
+
3
+ #[derive(Clone, Debug, Eq, PartialEq)]
4
+ pub(crate) struct PublicSurfaceContract {
5
+ pub(crate) name: String,
6
+ pub(crate) kind: PublicSurfaceKind,
7
+ pub(crate) columns: Vec<PublicColumn>,
8
+ pub(crate) capabilities: SurfaceCapabilities,
9
+ }
10
+
11
+ impl PublicSurfaceContract {
12
+ pub(crate) fn public_column(&self, column_name: &str) -> Option<&PublicColumn> {
13
+ self.columns
14
+ .iter()
15
+ .find(|column| column.name == column_name && column.is_public())
16
+ }
17
+
18
+ pub(crate) fn column(&self, column_name: &str) -> Option<&PublicColumn> {
19
+ self.columns
20
+ .iter()
21
+ .find(|column| column.name == column_name)
22
+ }
23
+ }
24
+
25
+ #[derive(Clone, Debug, Eq, PartialEq)]
26
+ pub(crate) enum PublicSurfaceKind {
27
+ LixState,
28
+ LixStateByBranch,
29
+ EntityBase { schema_key: String },
30
+ EntityByBranch { schema_key: String },
31
+ EntityHistory { schema_key: String },
32
+ File,
33
+ FileByBranch,
34
+ FileHistory,
35
+ Directory,
36
+ DirectoryByBranch,
37
+ DirectoryHistory,
38
+ Branch,
39
+ Change,
40
+ History,
41
+ }