@lix-js/sdk 0.6.0-preview.4 → 0.6.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 (223) hide show
  1. package/README.md +76 -4
  2. package/dist/errors.d.ts +7 -0
  3. package/dist/errors.js +19 -0
  4. package/dist/index.d.ts +4 -5
  5. package/dist/index.js +3 -3
  6. package/dist/native.d.ts +1 -0
  7. package/dist/native.js +47 -0
  8. package/dist/open-lix.d.ts +39 -201
  9. package/dist/open-lix.js +59 -284
  10. package/dist/result.d.ts +18 -0
  11. package/dist/result.js +48 -0
  12. package/dist/types.d.ts +114 -1
  13. package/dist/value.d.ts +28 -0
  14. package/dist/value.js +245 -0
  15. package/package.json +20 -50
  16. package/SKILL.md +0 -506
  17. package/dist/builtin-schemas.d.ts +0 -1
  18. package/dist/builtin-schemas.js +0 -1
  19. package/dist/engine-wasm/index.d.ts +0 -87
  20. package/dist/engine-wasm/index.js +0 -339
  21. package/dist/engine-wasm/wasm/lix_engine.d.ts +0 -79
  22. package/dist/engine-wasm/wasm/lix_engine.js +0 -821
  23. package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
  24. package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +0 -26
  25. package/dist/generated/builtin-schemas.d.ts +0 -427
  26. package/dist/generated/builtin-schemas.js +0 -643
  27. package/dist/sqlite/index.d.ts +0 -12
  28. package/dist/sqlite/index.js +0 -303
  29. package/dist-engine-src/README.md +0 -18
  30. package/dist-engine-src/src/backend/kv.rs +0 -358
  31. package/dist-engine-src/src/backend/mod.rs +0 -12
  32. package/dist-engine-src/src/backend/testing.rs +0 -658
  33. package/dist-engine-src/src/backend/types.rs +0 -96
  34. package/dist-engine-src/src/binary_cas/chunking.rs +0 -31
  35. package/dist-engine-src/src/binary_cas/codec.rs +0 -346
  36. package/dist-engine-src/src/binary_cas/context.rs +0 -139
  37. package/dist-engine-src/src/binary_cas/kv.rs +0 -1063
  38. package/dist-engine-src/src/binary_cas/mod.rs +0 -11
  39. package/dist-engine-src/src/binary_cas/types.rs +0 -121
  40. package/dist-engine-src/src/catalog/context.rs +0 -412
  41. package/dist-engine-src/src/catalog/mod.rs +0 -10
  42. package/dist-engine-src/src/catalog/schema.rs +0 -4
  43. package/dist-engine-src/src/catalog/snapshot.rs +0 -1114
  44. package/dist-engine-src/src/cel/context.rs +0 -86
  45. package/dist-engine-src/src/cel/error.rs +0 -19
  46. package/dist-engine-src/src/cel/mod.rs +0 -8
  47. package/dist-engine-src/src/cel/provider.rs +0 -9
  48. package/dist-engine-src/src/cel/runtime.rs +0 -167
  49. package/dist-engine-src/src/cel/value.rs +0 -50
  50. package/dist-engine-src/src/commit_graph/context.rs +0 -901
  51. package/dist-engine-src/src/commit_graph/mod.rs +0 -11
  52. package/dist-engine-src/src/commit_graph/types.rs +0 -109
  53. package/dist-engine-src/src/commit_graph/walker.rs +0 -756
  54. package/dist-engine-src/src/commit_store/codec.rs +0 -887
  55. package/dist-engine-src/src/commit_store/context.rs +0 -944
  56. package/dist-engine-src/src/commit_store/materialization.rs +0 -84
  57. package/dist-engine-src/src/commit_store/mod.rs +0 -16
  58. package/dist-engine-src/src/commit_store/storage.rs +0 -600
  59. package/dist-engine-src/src/commit_store/types.rs +0 -215
  60. package/dist-engine-src/src/common/error.rs +0 -313
  61. package/dist-engine-src/src/common/fingerprint.rs +0 -3
  62. package/dist-engine-src/src/common/fs_path.rs +0 -1336
  63. package/dist-engine-src/src/common/identity.rs +0 -145
  64. package/dist-engine-src/src/common/json_pointer.rs +0 -67
  65. package/dist-engine-src/src/common/metadata.rs +0 -40
  66. package/dist-engine-src/src/common/mod.rs +0 -23
  67. package/dist-engine-src/src/common/types.rs +0 -105
  68. package/dist-engine-src/src/common/wire.rs +0 -222
  69. package/dist-engine-src/src/domain.rs +0 -324
  70. package/dist-engine-src/src/engine.rs +0 -225
  71. package/dist-engine-src/src/entity_identity.rs +0 -405
  72. package/dist-engine-src/src/functions/context.rs +0 -292
  73. package/dist-engine-src/src/functions/deterministic.rs +0 -113
  74. package/dist-engine-src/src/functions/mod.rs +0 -18
  75. package/dist-engine-src/src/functions/provider.rs +0 -130
  76. package/dist-engine-src/src/functions/state.rs +0 -336
  77. package/dist-engine-src/src/functions/types.rs +0 -37
  78. package/dist-engine-src/src/init.rs +0 -558
  79. package/dist-engine-src/src/json_store/compression.rs +0 -77
  80. package/dist-engine-src/src/json_store/context.rs +0 -423
  81. package/dist-engine-src/src/json_store/encoded.rs +0 -15
  82. package/dist-engine-src/src/json_store/mod.rs +0 -12
  83. package/dist-engine-src/src/json_store/store.rs +0 -1109
  84. package/dist-engine-src/src/json_store/types.rs +0 -217
  85. package/dist-engine-src/src/lib.rs +0 -62
  86. package/dist-engine-src/src/live_state/context.rs +0 -2019
  87. package/dist-engine-src/src/live_state/mod.rs +0 -15
  88. package/dist-engine-src/src/live_state/overlay.rs +0 -75
  89. package/dist-engine-src/src/live_state/reader.rs +0 -23
  90. package/dist-engine-src/src/live_state/types.rs +0 -222
  91. package/dist-engine-src/src/live_state/visibility.rs +0 -223
  92. package/dist-engine-src/src/plugin/archive.rs +0 -438
  93. package/dist-engine-src/src/plugin/component.rs +0 -183
  94. package/dist-engine-src/src/plugin/install.rs +0 -619
  95. package/dist-engine-src/src/plugin/manifest.rs +0 -516
  96. package/dist-engine-src/src/plugin/materializer.rs +0 -477
  97. package/dist-engine-src/src/plugin/mod.rs +0 -33
  98. package/dist-engine-src/src/plugin/plugin_manifest.json +0 -118
  99. package/dist-engine-src/src/plugin/storage.rs +0 -74
  100. package/dist-engine-src/src/schema/annotations/defaults.rs +0 -275
  101. package/dist-engine-src/src/schema/annotations/mod.rs +0 -1
  102. package/dist-engine-src/src/schema/builtin/lix_account.json +0 -21
  103. package/dist-engine-src/src/schema/builtin/lix_active_account.json +0 -29
  104. package/dist-engine-src/src/schema/builtin/lix_binary_blob_ref.json +0 -29
  105. package/dist-engine-src/src/schema/builtin/lix_change.json +0 -63
  106. package/dist-engine-src/src/schema/builtin/lix_change_author.json +0 -45
  107. package/dist-engine-src/src/schema/builtin/lix_commit.json +0 -24
  108. package/dist-engine-src/src/schema/builtin/lix_commit_edge.json +0 -53
  109. package/dist-engine-src/src/schema/builtin/lix_directory_descriptor.json +0 -52
  110. package/dist-engine-src/src/schema/builtin/lix_file_descriptor.json +0 -52
  111. package/dist-engine-src/src/schema/builtin/lix_key_value.json +0 -40
  112. package/dist-engine-src/src/schema/builtin/lix_label.json +0 -29
  113. package/dist-engine-src/src/schema/builtin/lix_label_assignment.json +0 -74
  114. package/dist-engine-src/src/schema/builtin/lix_registered_schema.json +0 -25
  115. package/dist-engine-src/src/schema/builtin/lix_version_descriptor.json +0 -34
  116. package/dist-engine-src/src/schema/builtin/lix_version_ref.json +0 -48
  117. package/dist-engine-src/src/schema/builtin/mod.rs +0 -222
  118. package/dist-engine-src/src/schema/compatibility.rs +0 -787
  119. package/dist-engine-src/src/schema/definition.json +0 -187
  120. package/dist-engine-src/src/schema/definition.rs +0 -742
  121. package/dist-engine-src/src/schema/key.rs +0 -138
  122. package/dist-engine-src/src/schema/mod.rs +0 -20
  123. package/dist-engine-src/src/schema/seed.rs +0 -14
  124. package/dist-engine-src/src/schema/tests.rs +0 -780
  125. package/dist-engine-src/src/session/context.rs +0 -404
  126. package/dist-engine-src/src/session/create_version.rs +0 -88
  127. package/dist-engine-src/src/session/execute.rs +0 -541
  128. package/dist-engine-src/src/session/merge/analysis.rs +0 -102
  129. package/dist-engine-src/src/session/merge/apply.rs +0 -23
  130. package/dist-engine-src/src/session/merge/conflicts.rs +0 -63
  131. package/dist-engine-src/src/session/merge/mod.rs +0 -11
  132. package/dist-engine-src/src/session/merge/stats.rs +0 -65
  133. package/dist-engine-src/src/session/merge/version.rs +0 -427
  134. package/dist-engine-src/src/session/mod.rs +0 -27
  135. package/dist-engine-src/src/session/optimization9_sql2_bench.rs +0 -100
  136. package/dist-engine-src/src/session/switch_version.rs +0 -110
  137. package/dist-engine-src/src/session/transaction.rs +0 -76
  138. package/dist-engine-src/src/sql2/change_provider.rs +0 -331
  139. package/dist-engine-src/src/sql2/classify.rs +0 -174
  140. package/dist-engine-src/src/sql2/context.rs +0 -311
  141. package/dist-engine-src/src/sql2/directory_history_provider.rs +0 -631
  142. package/dist-engine-src/src/sql2/directory_provider.rs +0 -2453
  143. package/dist-engine-src/src/sql2/dml.rs +0 -148
  144. package/dist-engine-src/src/sql2/entity_history_provider.rs +0 -440
  145. package/dist-engine-src/src/sql2/entity_provider.rs +0 -3211
  146. package/dist-engine-src/src/sql2/error.rs +0 -215
  147. package/dist-engine-src/src/sql2/execute.rs +0 -3533
  148. package/dist-engine-src/src/sql2/file_history_provider.rs +0 -910
  149. package/dist-engine-src/src/sql2/file_provider.rs +0 -3679
  150. package/dist-engine-src/src/sql2/filesystem_planner.rs +0 -1490
  151. package/dist-engine-src/src/sql2/filesystem_predicates.rs +0 -159
  152. package/dist-engine-src/src/sql2/filesystem_visibility.rs +0 -383
  153. package/dist-engine-src/src/sql2/history_projection.rs +0 -56
  154. package/dist-engine-src/src/sql2/history_provider.rs +0 -412
  155. package/dist-engine-src/src/sql2/history_route.rs +0 -657
  156. package/dist-engine-src/src/sql2/lix_state_provider.rs +0 -2512
  157. package/dist-engine-src/src/sql2/mod.rs +0 -47
  158. package/dist-engine-src/src/sql2/predicate_typecheck.rs +0 -246
  159. package/dist-engine-src/src/sql2/public_bind/assignment.rs +0 -46
  160. package/dist-engine-src/src/sql2/public_bind/capability.rs +0 -41
  161. package/dist-engine-src/src/sql2/public_bind/dml.rs +0 -172
  162. package/dist-engine-src/src/sql2/public_bind/mod.rs +0 -26
  163. package/dist-engine-src/src/sql2/public_bind/table.rs +0 -168
  164. package/dist-engine-src/src/sql2/read_only.rs +0 -63
  165. package/dist-engine-src/src/sql2/record_batch.rs +0 -17
  166. package/dist-engine-src/src/sql2/result_metadata.rs +0 -29
  167. package/dist-engine-src/src/sql2/runtime.rs +0 -60
  168. package/dist-engine-src/src/sql2/session.rs +0 -132
  169. package/dist-engine-src/src/sql2/udfs/common.rs +0 -295
  170. package/dist-engine-src/src/sql2/udfs/lix_active_version_commit_id.rs +0 -53
  171. package/dist-engine-src/src/sql2/udfs/lix_empty_blob.rs +0 -47
  172. package/dist-engine-src/src/sql2/udfs/lix_json.rs +0 -100
  173. package/dist-engine-src/src/sql2/udfs/lix_json_get.rs +0 -99
  174. package/dist-engine-src/src/sql2/udfs/lix_json_get_text.rs +0 -99
  175. package/dist-engine-src/src/sql2/udfs/lix_text_decode.rs +0 -82
  176. package/dist-engine-src/src/sql2/udfs/lix_text_encode.rs +0 -85
  177. package/dist-engine-src/src/sql2/udfs/lix_timestamp.rs +0 -76
  178. package/dist-engine-src/src/sql2/udfs/lix_uuid_v7.rs +0 -76
  179. package/dist-engine-src/src/sql2/udfs/mod.rs +0 -89
  180. package/dist-engine-src/src/sql2/udfs/public_call.rs +0 -238
  181. package/dist-engine-src/src/sql2/version_provider.rs +0 -1202
  182. package/dist-engine-src/src/sql2/version_scope.rs +0 -394
  183. package/dist-engine-src/src/sql2/write_normalization.rs +0 -345
  184. package/dist-engine-src/src/storage/context.rs +0 -356
  185. package/dist-engine-src/src/storage/mod.rs +0 -14
  186. package/dist-engine-src/src/storage/read_scope.rs +0 -88
  187. package/dist-engine-src/src/storage/types.rs +0 -501
  188. package/dist-engine-src/src/storage_bench.rs +0 -4863
  189. package/dist-engine-src/src/test_support.rs +0 -228
  190. package/dist-engine-src/src/tracked_state/by_file_index.rs +0 -98
  191. package/dist-engine-src/src/tracked_state/codec.rs +0 -2085
  192. package/dist-engine-src/src/tracked_state/context.rs +0 -1867
  193. package/dist-engine-src/src/tracked_state/diff.rs +0 -686
  194. package/dist-engine-src/src/tracked_state/materialization.rs +0 -403
  195. package/dist-engine-src/src/tracked_state/materializer.rs +0 -488
  196. package/dist-engine-src/src/tracked_state/merge.rs +0 -492
  197. package/dist-engine-src/src/tracked_state/mod.rs +0 -32
  198. package/dist-engine-src/src/tracked_state/storage.rs +0 -375
  199. package/dist-engine-src/src/tracked_state/tree.rs +0 -3187
  200. package/dist-engine-src/src/tracked_state/types.rs +0 -231
  201. package/dist-engine-src/src/transaction/commit.rs +0 -1484
  202. package/dist-engine-src/src/transaction/context.rs +0 -1548
  203. package/dist-engine-src/src/transaction/live_state_overlay.rs +0 -35
  204. package/dist-engine-src/src/transaction/mod.rs +0 -13
  205. package/dist-engine-src/src/transaction/normalization.rs +0 -890
  206. package/dist-engine-src/src/transaction/prep.rs +0 -37
  207. package/dist-engine-src/src/transaction/schema_resolver.rs +0 -149
  208. package/dist-engine-src/src/transaction/staging.rs +0 -1731
  209. package/dist-engine-src/src/transaction/types.rs +0 -460
  210. package/dist-engine-src/src/transaction/validation.rs +0 -5830
  211. package/dist-engine-src/src/untracked_state/codec.rs +0 -307
  212. package/dist-engine-src/src/untracked_state/context.rs +0 -98
  213. package/dist-engine-src/src/untracked_state/materialization.rs +0 -63
  214. package/dist-engine-src/src/untracked_state/mod.rs +0 -15
  215. package/dist-engine-src/src/untracked_state/storage.rs +0 -396
  216. package/dist-engine-src/src/untracked_state/types.rs +0 -146
  217. package/dist-engine-src/src/version/context.rs +0 -40
  218. package/dist-engine-src/src/version/lifecycle.rs +0 -221
  219. package/dist-engine-src/src/version/mod.rs +0 -13
  220. package/dist-engine-src/src/version/refs.rs +0 -330
  221. package/dist-engine-src/src/version/stage_rows.rs +0 -67
  222. package/dist-engine-src/src/version/types.rs +0 -21
  223. package/dist-engine-src/src/wasm/mod.rs +0 -60
@@ -1,11 +0,0 @@
1
- mod chunking;
2
- mod codec;
3
- mod context;
4
- pub(crate) mod kv;
5
- mod types;
6
-
7
- pub(crate) use context::{BinaryCasContext, BlobDataReader};
8
- pub(crate) use types::{
9
- BlobBytesBatch, BlobExistsBatch, BlobHash, BlobLayout, BlobMetadata, BlobMetadataBatch,
10
- BlobWrite, BlobWriteReceipt,
11
- };
@@ -1,121 +0,0 @@
1
- use crate::binary_cas::codec::{binary_blob_hash_bytes, hash_bytes_to_hex, hash_hex_to_bytes};
2
- use crate::LixError;
3
-
4
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
5
- pub(crate) struct BlobHash([u8; 32]);
6
-
7
- impl BlobHash {
8
- pub(crate) fn from_bytes(bytes: [u8; 32]) -> Self {
9
- Self(bytes)
10
- }
11
-
12
- pub(crate) fn from_content(content: &[u8]) -> Self {
13
- Self(binary_blob_hash_bytes(content))
14
- }
15
-
16
- pub(crate) fn from_hex(hash_hex: &str) -> Result<Self, LixError> {
17
- Ok(Self(hash_hex_to_bytes(hash_hex, "binary CAS blob")?))
18
- }
19
-
20
- pub(crate) fn to_hex(self) -> String {
21
- hash_bytes_to_hex(&self.0)
22
- }
23
-
24
- pub(crate) fn as_bytes(&self) -> &[u8; 32] {
25
- &self.0
26
- }
27
-
28
- pub(crate) fn into_bytes(self) -> [u8; 32] {
29
- self.0
30
- }
31
- }
32
-
33
- #[derive(Debug, Clone, PartialEq, Eq)]
34
- pub(crate) enum BlobLayout {
35
- Empty,
36
- SingleChunk { chunk_hash: BlobHash },
37
- Chunked { chunk_count: u32 },
38
- }
39
-
40
- #[derive(Debug, Clone, PartialEq, Eq)]
41
- pub(crate) struct BlobMetadata {
42
- pub(crate) hash: BlobHash,
43
- pub(crate) size_bytes: u64,
44
- pub(crate) layout: BlobLayout,
45
- }
46
-
47
- #[derive(Debug, Clone, PartialEq, Eq)]
48
- pub(crate) struct BlobExistsBatch {
49
- entries: Vec<bool>,
50
- }
51
-
52
- impl BlobExistsBatch {
53
- pub(crate) fn new(entries: Vec<bool>) -> Self {
54
- Self { entries }
55
- }
56
-
57
- #[allow(dead_code)]
58
- pub(crate) fn get(&self, index: usize) -> bool {
59
- self.entries.get(index).copied().unwrap_or(false)
60
- }
61
-
62
- #[allow(dead_code)]
63
- pub(crate) fn into_vec(self) -> Vec<bool> {
64
- self.entries
65
- }
66
- }
67
-
68
- #[derive(Debug, Clone, PartialEq, Eq)]
69
- pub(crate) struct BlobMetadataBatch {
70
- entries: Vec<Option<BlobMetadata>>,
71
- }
72
-
73
- impl BlobMetadataBatch {
74
- pub(crate) fn new(entries: Vec<Option<BlobMetadata>>) -> Self {
75
- Self { entries }
76
- }
77
-
78
- #[allow(dead_code)]
79
- pub(crate) fn get(&self, index: usize) -> Option<&BlobMetadata> {
80
- self.entries.get(index).and_then(Option::as_ref)
81
- }
82
-
83
- pub(crate) fn into_vec(self) -> Vec<Option<BlobMetadata>> {
84
- self.entries
85
- }
86
- }
87
-
88
- #[derive(Debug, Clone, PartialEq, Eq)]
89
- pub(crate) struct BlobBytesBatch {
90
- entries: Vec<Option<Vec<u8>>>,
91
- }
92
-
93
- impl BlobBytesBatch {
94
- pub(crate) fn new(entries: Vec<Option<Vec<u8>>>) -> Self {
95
- Self { entries }
96
- }
97
-
98
- #[allow(dead_code)]
99
- pub(crate) fn get(&self, index: usize) -> Option<&[u8]> {
100
- self.entries
101
- .get(index)
102
- .and_then(Option::as_ref)
103
- .map(Vec::as_slice)
104
- }
105
-
106
- pub(crate) fn into_vec(self) -> Vec<Option<Vec<u8>>> {
107
- self.entries
108
- }
109
- }
110
-
111
- #[derive(Debug, Clone, Copy)]
112
- pub(crate) struct BlobWrite<'a> {
113
- pub(crate) bytes: &'a [u8],
114
- }
115
-
116
- #[derive(Debug, Clone, PartialEq, Eq)]
117
- pub(crate) struct BlobWriteReceipt {
118
- pub(crate) hash: BlobHash,
119
- pub(crate) size_bytes: u64,
120
- pub(crate) layout: BlobLayout,
121
- }
@@ -1,412 +0,0 @@
1
- use std::collections::BTreeMap;
2
-
3
- use serde_json::Value as JsonValue;
4
-
5
- use crate::catalog::SchemaCatalogFact;
6
- use crate::domain::{committed_row_is_exact_version_scoped, Domain};
7
- use crate::live_state::MaterializedLiveStateRow;
8
- use crate::live_state::{LiveStateFilter, LiveStateReader, LiveStateScanRequest};
9
- use crate::schema::schema_key_from_definition;
10
- use crate::{LixError, NullableKeyFilter};
11
-
12
- const REGISTERED_SCHEMA_KEY: &str = "lix_registered_schema";
13
-
14
- /// Engine schema visibility boundary.
15
- ///
16
- /// SQL planning receives a schema snapshot from live state. System schemas are
17
- /// seeded as ordinary `lix_registered_schema` rows during initialization, so
18
- /// runtime schema visibility has one source of truth.
19
- pub(crate) struct CatalogContext;
20
-
21
- impl CatalogContext {
22
- pub(crate) fn new() -> Self {
23
- Self
24
- }
25
-
26
- /// Loads schema definitions for SQL surface planning at `version_id`.
27
- ///
28
- /// SQL surfaces are a read-planning projection over the active untracked
29
- /// schema catalog. Validation must use `schema_facts_for_domain` instead so
30
- /// schema durability remains explicit.
31
- pub(crate) async fn schema_jsons_for_sql_read_planning<R>(
32
- &self,
33
- live_state: &R,
34
- version_id: &str,
35
- ) -> Result<Vec<JsonValue>, LixError>
36
- where
37
- R: LiveStateReader + ?Sized,
38
- {
39
- let facts = self
40
- .schema_facts_for_domain(live_state, &Domain::schema_catalog(version_id, true))
41
- .await?;
42
- let mut schemas = BTreeMap::<String, JsonValue>::new();
43
- for fact in facts {
44
- let schema_key = fact.catalog_key().schema_key.clone();
45
- if schemas
46
- .insert(schema_key.clone(), fact.schema().clone())
47
- .is_some()
48
- {
49
- return Err(LixError::new(
50
- LixError::CODE_SCHEMA_DEFINITION,
51
- format!(
52
- "SQL surface schema '{}' is visible from more than one schema catalog fact",
53
- schema_key
54
- ),
55
- )
56
- .with_hint("SQL entity surfaces are named by schema_key. Keep exactly one visible schema per schema_key for SQL planning."));
57
- }
58
- }
59
- Ok(schemas.into_values().collect())
60
- }
61
-
62
- /// Loads schema facts reachable from a row domain.
63
- pub(crate) async fn schema_facts_for_domain<R>(
64
- &self,
65
- live_state: &R,
66
- domain: &Domain,
67
- ) -> Result<Vec<SchemaCatalogFact>, LixError>
68
- where
69
- R: LiveStateReader + ?Sized,
70
- {
71
- let mut facts = Vec::new();
72
- for schema_domain in domain.schema_catalog_domains() {
73
- let rows = live_state
74
- .scan_rows(&LiveStateScanRequest {
75
- filter: LiveStateFilter {
76
- schema_keys: vec![REGISTERED_SCHEMA_KEY.to_string()],
77
- version_ids: vec![schema_domain.version_id().to_string()],
78
- file_ids: vec![NullableKeyFilter::Null],
79
- untracked: Some(schema_domain.untracked()),
80
- include_tombstones: false,
81
- ..LiveStateFilter::default()
82
- },
83
- ..LiveStateScanRequest::default()
84
- })
85
- .await?;
86
- for row in rows
87
- .into_iter()
88
- .filter(|row| row_belongs_to_schema_catalog_domain(row, &schema_domain))
89
- {
90
- let Some((key, schema)) = decode_registered_schema_row(&row)? else {
91
- continue;
92
- };
93
- facts.push(SchemaCatalogFact::new(schema_domain.clone(), key, schema));
94
- }
95
- }
96
- Ok(facts)
97
- }
98
- }
99
-
100
- fn row_belongs_to_schema_catalog_domain(row: &MaterializedLiveStateRow, domain: &Domain) -> bool {
101
- row.schema_key == REGISTERED_SCHEMA_KEY
102
- && row.file_id.is_none()
103
- && row.snapshot_content.is_some()
104
- && row.version_id == domain.version_id()
105
- && row.untracked == domain.untracked()
106
- && committed_row_is_exact_version_scoped(row, domain.version_id())
107
- }
108
-
109
- fn decode_registered_schema_row(
110
- row: &MaterializedLiveStateRow,
111
- ) -> Result<Option<(crate::schema::SchemaKey, JsonValue)>, LixError> {
112
- if row.schema_key != REGISTERED_SCHEMA_KEY {
113
- return Err(LixError::new(
114
- "LIX_ERROR_UNKNOWN",
115
- format!(
116
- "expected lix_registered_schema row, got schema_key={}",
117
- row.schema_key
118
- ),
119
- ));
120
- }
121
-
122
- let Some(snapshot_content) = row.snapshot_content.as_deref() else {
123
- return Ok(None);
124
- };
125
-
126
- let snapshot: JsonValue = serde_json::from_str(snapshot_content).map_err(|err| {
127
- LixError::new(
128
- "LIX_ERROR_UNKNOWN",
129
- format!("invalid registered schema snapshot JSON: {err}"),
130
- )
131
- })?;
132
- let schema = snapshot.get("value").cloned().ok_or_else(|| {
133
- LixError::new(
134
- "LIX_ERROR_UNKNOWN",
135
- "registered schema snapshot missing value",
136
- )
137
- })?;
138
- let key = schema_key_from_definition(&schema)?;
139
- Ok(Some((key, schema)))
140
- }
141
-
142
- #[cfg(test)]
143
- mod tests {
144
- use async_trait::async_trait;
145
- use serde_json::json;
146
-
147
- use super::*;
148
- use crate::live_state::LiveStateRowRequest;
149
- use crate::GLOBAL_VERSION_ID;
150
-
151
- #[tokio::test]
152
- async fn visible_schemas_are_loaded_from_registered_schema_rows() {
153
- let context = CatalogContext::new();
154
-
155
- let schemas = context
156
- .schema_jsons_for_sql_read_planning(
157
- &RowsLiveStateReader::new(vec![
158
- registered_schema_row("lix_registered_schema"),
159
- registered_schema_row("lix_key_value"),
160
- ]),
161
- "global",
162
- )
163
- .await
164
- .expect("schema visibility should load");
165
-
166
- assert!(schemas.iter().any(|schema| {
167
- schema.get("x-lix-key").and_then(JsonValue::as_str) == Some("lix_registered_schema")
168
- }));
169
- assert!(schemas.iter().any(|schema| {
170
- schema.get("x-lix-key").and_then(JsonValue::as_str) == Some("lix_key_value")
171
- }));
172
- }
173
-
174
- #[tokio::test]
175
- async fn visible_schemas_include_registered_schema_rows() {
176
- let context = CatalogContext::new();
177
-
178
- let schemas = context
179
- .schema_jsons_for_sql_read_planning(
180
- &RowsLiveStateReader::new(vec![registered_schema_row("engine_dynamic_schema")]),
181
- "global",
182
- )
183
- .await
184
- .expect("schema visibility should load");
185
-
186
- assert!(schemas.iter().any(|schema| {
187
- schema.get("x-lix-key").and_then(JsonValue::as_str) == Some("engine_dynamic_schema")
188
- }));
189
- }
190
-
191
- #[tokio::test]
192
- async fn sql_read_planning_rejects_multiple_visible_schemas_for_same_surface() {
193
- let context = CatalogContext::new();
194
- let error = context
195
- .schema_jsons_for_sql_read_planning(
196
- &RowsLiveStateReader::new(vec![
197
- registered_schema_row("engine_dynamic_schema"),
198
- registered_schema_row("engine_dynamic_schema"),
199
- ]),
200
- "global",
201
- )
202
- .await
203
- .expect_err("SQL surfaces must not choose a schema identity implicitly");
204
-
205
- assert_eq!(error.code, LixError::CODE_SCHEMA_DEFINITION);
206
- assert!(error.message.contains("SQL surface schema"));
207
- }
208
-
209
- #[tokio::test]
210
- async fn tracked_domain_sees_tracked_seed_schemas_but_not_user_untracked_schemas() {
211
- let context = CatalogContext::new();
212
- let mut seed_schema = registered_schema_row("lix_key_value");
213
- seed_schema.untracked = false;
214
-
215
- let facts = context
216
- .schema_facts_for_domain(
217
- &RowsLiveStateReader::new(vec![
218
- seed_schema,
219
- registered_schema_row("engine_dynamic_schema"),
220
- ]),
221
- &Domain::schema_catalog("global", false),
222
- )
223
- .await
224
- .expect("schema visibility should load");
225
- let schemas = facts
226
- .iter()
227
- .map(SchemaCatalogFact::schema)
228
- .collect::<Vec<_>>();
229
-
230
- assert!(schemas.iter().any(|schema| {
231
- schema.get("x-lix-key").and_then(JsonValue::as_str) == Some("lix_key_value")
232
- }));
233
- assert!(!schemas.iter().any(|schema| {
234
- schema.get("x-lix-key").and_then(JsonValue::as_str) == Some("engine_dynamic_schema")
235
- }));
236
- }
237
-
238
- #[tokio::test]
239
- async fn tracked_domain_does_not_see_untracked_seed_schemas() {
240
- let context = CatalogContext::new();
241
-
242
- let facts = context
243
- .schema_facts_for_domain(
244
- &RowsLiveStateReader::new(vec![registered_schema_row("lix_key_value")]),
245
- &Domain::schema_catalog("global", false),
246
- )
247
- .await
248
- .expect("schema visibility should load");
249
- let schemas = facts
250
- .iter()
251
- .map(SchemaCatalogFact::schema)
252
- .collect::<Vec<_>>();
253
-
254
- assert!(!schemas.iter().any(|schema| {
255
- schema.get("x-lix-key").and_then(JsonValue::as_str) == Some("lix_key_value")
256
- }));
257
- }
258
-
259
- #[tokio::test]
260
- async fn visible_schemas_ignore_projected_global_schema_rows_for_version_scope() {
261
- let context = CatalogContext::new();
262
- let mut global_only = registered_schema_row("global_only_schema");
263
- global_only.global = true;
264
- global_only.version_id = "main".to_string();
265
-
266
- let schemas = context
267
- .schema_jsons_for_sql_read_planning(
268
- &RowsLiveStateReader::new(vec![global_only]),
269
- "main",
270
- )
271
- .await
272
- .expect("schema visibility should load");
273
-
274
- assert!(schemas.is_empty());
275
- }
276
-
277
- #[tokio::test]
278
- async fn schema_facts_post_filter_non_catalog_rows_even_if_reader_returns_them() {
279
- let context = CatalogContext::new();
280
- let valid_schema = registered_schema_row("valid_schema");
281
- let mut file_scoped_schema = registered_schema_row("file_scoped_schema");
282
- file_scoped_schema.file_id = Some("file-a".to_string());
283
- let mut tombstoned_schema = registered_schema_row("tombstoned_schema");
284
- tombstoned_schema.snapshot_content = None;
285
-
286
- let facts = context
287
- .schema_facts_for_domain(
288
- &RowsLiveStateReader::new(vec![
289
- valid_schema,
290
- file_scoped_schema,
291
- tombstoned_schema,
292
- ]),
293
- &Domain::schema_catalog("global", true),
294
- )
295
- .await
296
- .expect("schema facts should load");
297
- let schema_keys = facts
298
- .iter()
299
- .filter_map(|fact| fact.schema().get("x-lix-key").and_then(JsonValue::as_str))
300
- .collect::<Vec<_>>();
301
-
302
- assert_eq!(schema_keys, vec!["valid_schema"]);
303
- }
304
-
305
- #[tokio::test]
306
- async fn visible_schemas_are_empty_when_no_schema_rows_are_visible() {
307
- let context = CatalogContext::new();
308
-
309
- let schemas = context
310
- .schema_jsons_for_sql_read_planning(&RowsLiveStateReader::new(Vec::new()), "global")
311
- .await
312
- .expect("schema visibility should load");
313
-
314
- assert!(schemas.is_empty());
315
- }
316
-
317
- struct RowsLiveStateReader {
318
- rows: Vec<MaterializedLiveStateRow>,
319
- }
320
-
321
- impl RowsLiveStateReader {
322
- fn new(rows: Vec<MaterializedLiveStateRow>) -> Self {
323
- Self { rows }
324
- }
325
- }
326
-
327
- #[async_trait]
328
- impl LiveStateReader for RowsLiveStateReader {
329
- async fn scan_rows(
330
- &self,
331
- request: &LiveStateScanRequest,
332
- ) -> Result<Vec<MaterializedLiveStateRow>, LixError> {
333
- Ok(self
334
- .rows
335
- .iter()
336
- .filter(|row| {
337
- request.filter.schema_keys.is_empty()
338
- || request.filter.schema_keys.contains(&row.schema_key)
339
- })
340
- .filter(|row| {
341
- request.filter.version_ids.is_empty()
342
- || request.filter.version_ids.contains(&row.version_id)
343
- })
344
- .filter(|row| {
345
- request
346
- .filter
347
- .untracked
348
- .is_none_or(|untracked| row.untracked == untracked)
349
- })
350
- .cloned()
351
- .collect())
352
- }
353
-
354
- async fn load_row(
355
- &self,
356
- request: &LiveStateRowRequest,
357
- ) -> Result<Option<MaterializedLiveStateRow>, LixError> {
358
- Ok(self
359
- .rows
360
- .iter()
361
- .find(|row| {
362
- row.schema_key == request.schema_key
363
- && row.version_id == request.version_id
364
- && row.entity_id == request.entity_id
365
- })
366
- .cloned())
367
- }
368
- }
369
-
370
- fn registered_schema_row(schema_key: &str) -> MaterializedLiveStateRow {
371
- MaterializedLiveStateRow {
372
- entity_id: registered_schema_entity_id(schema_key),
373
- file_id: None,
374
- schema_key: REGISTERED_SCHEMA_KEY.to_string(),
375
- version_id: GLOBAL_VERSION_ID.to_string(),
376
- metadata: None,
377
- deleted: false,
378
- change_id: Some("change-registered-schema".to_string()),
379
- commit_id: None,
380
- global: true,
381
- untracked: true,
382
- created_at: "2026-04-23T00:00:00Z".to_string(),
383
- updated_at: "2026-04-23T01:00:00Z".to_string(),
384
- snapshot_content: Some(
385
- json!({
386
- "value": {
387
- "x-lix-key": schema_key,
388
- "type": "object",
389
- "properties": {
390
- "id": { "type": "string" }
391
- },
392
- "required": ["id"],
393
- "additionalProperties": false
394
- }
395
- })
396
- .to_string(),
397
- ),
398
- }
399
- }
400
-
401
- fn registered_schema_entity_id(schema_key: &str) -> crate::entity_identity::EntityIdentity {
402
- crate::entity_identity::EntityIdentity::from_primary_key_paths(
403
- &json!({
404
- "value": {
405
- "x-lix-key": schema_key,
406
- }
407
- }),
408
- &[vec!["value".to_string(), "x-lix-key".to_string()]],
409
- )
410
- .expect("registered schema identity should derive")
411
- }
412
- }
@@ -1,10 +0,0 @@
1
- mod context;
2
- mod schema;
3
- mod snapshot;
4
-
5
- pub(crate) use context::CatalogContext;
6
- pub(crate) use schema::{
7
- ForeignKeyPlan, SchemaCatalogFact, SchemaCatalogKey, SchemaPlan, SchemaPlanId,
8
- StateForeignKeyPlan,
9
- };
10
- pub(crate) use snapshot::{CatalogSnapshot, StateDeleteReferencePlan};
@@ -1,4 +0,0 @@
1
- pub(crate) use super::snapshot::{
2
- ForeignKeyPlan, SchemaCatalogFact, SchemaCatalogKey, SchemaPlan, SchemaPlanId,
3
- StateForeignKeyPlan,
4
- };