@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
@@ -1,394 +0,0 @@
1
- use std::collections::BTreeSet;
2
-
3
- use datafusion::error::DataFusionError;
4
- use datafusion::logical_expr::expr::InList;
5
- use datafusion::logical_expr::{BinaryExpr, Expr, Operator};
6
- use datafusion::scalar::ScalarValue;
7
-
8
- use crate::version::VersionRefReader;
9
- use crate::LixError;
10
- use crate::GLOBAL_VERSION_ID;
11
-
12
- /// Version scope requested by a SQL surface.
13
- ///
14
- /// Active surfaces read through one session version. By-version surfaces either
15
- /// read explicitly filtered versions or, without a version predicate, enumerate
16
- /// every visible version scope before handing the request to live_state.
17
- pub(crate) enum SqlVersionScope {
18
- Active(String),
19
- Explicit(Vec<String>),
20
- AllVisible,
21
- }
22
-
23
- #[derive(Debug, Clone, PartialEq, Eq)]
24
- pub(crate) enum VersionBinding {
25
- Active { version_id: String },
26
- Explicit,
27
- }
28
-
29
- #[derive(Debug, Clone, PartialEq, Eq)]
30
- pub(crate) struct WriteVersionScope {
31
- pub(crate) version_id: String,
32
- pub(crate) global: bool,
33
- }
34
-
35
- impl VersionBinding {
36
- pub(crate) fn active(version_id: impl Into<String>) -> Self {
37
- Self::Active {
38
- version_id: version_id.into(),
39
- }
40
- }
41
-
42
- pub(crate) fn explicit() -> Self {
43
- Self::Explicit
44
- }
45
-
46
- pub(crate) fn active_version_id(&self) -> Option<&str> {
47
- match self {
48
- Self::Active { version_id } => Some(version_id),
49
- Self::Explicit => None,
50
- }
51
- }
52
-
53
- pub(crate) fn require_active_version_id(&self, action: &str) -> Result<String, LixError> {
54
- match self {
55
- Self::Active { version_id } => Ok(version_id.clone()),
56
- Self::Explicit => Err(LixError::new(
57
- "LIX_ERROR_UNKNOWN",
58
- format!("{action} is only supported for active-version SQL surfaces"),
59
- )),
60
- }
61
- }
62
- }
63
-
64
- pub(crate) fn resolve_write_version_scope(
65
- explicit_global: Option<bool>,
66
- explicit_version_id: Option<String>,
67
- fallback_version_id: Option<&str>,
68
- action: &str,
69
- surface: &str,
70
- ) -> Result<WriteVersionScope, DataFusionError> {
71
- if explicit_global == Some(true) {
72
- if explicit_version_id
73
- .as_deref()
74
- .is_some_and(|version_id| version_id != GLOBAL_VERSION_ID)
75
- {
76
- return Err(DataFusionError::Execution(format!(
77
- "{surface} cannot set lixcol_global=true with non-global lixcol_version_id"
78
- )));
79
- }
80
- return Ok(WriteVersionScope {
81
- version_id: GLOBAL_VERSION_ID.to_string(),
82
- global: true,
83
- });
84
- }
85
-
86
- let version_id = explicit_version_id
87
- .or_else(|| fallback_version_id.map(ToOwned::to_owned))
88
- .ok_or_else(|| {
89
- DataFusionError::Execution(format!("{action} requires lixcol_version_id"))
90
- })?;
91
- if explicit_global == Some(false) && version_id == GLOBAL_VERSION_ID {
92
- return Err(DataFusionError::Execution(format!(
93
- "{surface} cannot set lixcol_global=false with global lixcol_version_id"
94
- )));
95
- }
96
- Ok(WriteVersionScope {
97
- global: explicit_global.unwrap_or(version_id == GLOBAL_VERSION_ID),
98
- version_id,
99
- })
100
- }
101
-
102
- impl SqlVersionScope {
103
- pub(crate) fn from_provider(
104
- binding: &VersionBinding,
105
- requested_version_ids: Vec<String>,
106
- ) -> Self {
107
- match binding {
108
- VersionBinding::Active { version_id } => Self::Active(version_id.clone()),
109
- VersionBinding::Explicit if requested_version_ids.is_empty() => Self::AllVisible,
110
- VersionBinding::Explicit => Self::Explicit(requested_version_ids),
111
- }
112
- }
113
- }
114
-
115
- pub(crate) async fn resolve_sql_version_scope(
116
- version_ref: &dyn VersionRefReader,
117
- scope: SqlVersionScope,
118
- ) -> Result<Vec<String>, LixError> {
119
- match scope {
120
- SqlVersionScope::Active(version_id) => Ok(vec![version_id]),
121
- SqlVersionScope::Explicit(version_ids) => Ok(version_ids),
122
- SqlVersionScope::AllVisible => visible_version_ids(version_ref).await,
123
- }
124
- }
125
-
126
- pub(crate) async fn resolve_provider_version_ids(
127
- version_ref: &dyn VersionRefReader,
128
- binding: &VersionBinding,
129
- requested_version_ids: Vec<String>,
130
- ) -> Result<Vec<String>, LixError> {
131
- resolve_sql_version_scope(
132
- version_ref,
133
- SqlVersionScope::from_provider(binding, requested_version_ids),
134
- )
135
- .await
136
- }
137
-
138
- pub(crate) fn explicit_version_ids_from_dml_filters(filters: &[Expr]) -> Vec<String> {
139
- filters
140
- .iter()
141
- .flat_map(version_ids_from_filter)
142
- .collect::<BTreeSet<_>>()
143
- .into_iter()
144
- .collect()
145
- }
146
-
147
- fn version_ids_from_filter(expr: &Expr) -> Vec<String> {
148
- match expr {
149
- Expr::BinaryExpr(binary_expr) if binary_expr.op == Operator::And => {
150
- let mut values = version_ids_from_filter(&binary_expr.left);
151
- values.extend(version_ids_from_filter(&binary_expr.right));
152
- values
153
- }
154
- Expr::BinaryExpr(binary_expr) => version_id_from_binary_filter(binary_expr)
155
- .map(|value| vec![value])
156
- .unwrap_or_default(),
157
- Expr::InList(in_list) => version_ids_from_in_list_filter(in_list).unwrap_or_default(),
158
- _ => Vec::new(),
159
- }
160
- }
161
-
162
- fn version_id_from_binary_filter(binary_expr: &BinaryExpr) -> Option<String> {
163
- if binary_expr.op != Operator::Eq {
164
- return None;
165
- }
166
-
167
- version_id_from_column_literal_filter(&binary_expr.left, &binary_expr.right)
168
- .or_else(|| version_id_from_column_literal_filter(&binary_expr.right, &binary_expr.left))
169
- }
170
-
171
- fn version_ids_from_in_list_filter(in_list: &InList) -> Option<Vec<String>> {
172
- if in_list.negated {
173
- return None;
174
- }
175
- let Expr::Column(column) = in_list.expr.as_ref() else {
176
- return None;
177
- };
178
- if column.name != "lixcol_version_id" {
179
- return None;
180
- }
181
-
182
- let values = in_list
183
- .list
184
- .iter()
185
- .map(string_expr_literal)
186
- .collect::<Option<Vec<_>>>()?;
187
- if values.is_empty() {
188
- return None;
189
- }
190
- Some(values)
191
- }
192
-
193
- fn version_id_from_column_literal_filter(
194
- column_expr: &Expr,
195
- literal_expr: &Expr,
196
- ) -> Option<String> {
197
- let Expr::Column(column) = column_expr else {
198
- return None;
199
- };
200
- if column.name != "lixcol_version_id" {
201
- return None;
202
- }
203
- string_expr_literal(literal_expr)
204
- }
205
-
206
- fn string_expr_literal(expr: &Expr) -> Option<String> {
207
- let Expr::Literal(literal, _) = expr else {
208
- return None;
209
- };
210
- match literal {
211
- ScalarValue::Utf8(Some(value))
212
- | ScalarValue::Utf8View(Some(value))
213
- | ScalarValue::LargeUtf8(Some(value)) => Some(value.clone()),
214
- _ => None,
215
- }
216
- }
217
-
218
- async fn visible_version_ids(version_ref: &dyn VersionRefReader) -> Result<Vec<String>, LixError> {
219
- let mut version_ids = version_ref
220
- .scan_heads()
221
- .await?
222
- .into_iter()
223
- .map(|head| head.version_id)
224
- .collect::<BTreeSet<_>>();
225
- version_ids.insert(GLOBAL_VERSION_ID.to_string());
226
- Ok(version_ids.into_iter().collect())
227
- }
228
-
229
- #[cfg(test)]
230
- mod tests {
231
- use async_trait::async_trait;
232
-
233
- use super::*;
234
- use crate::version::VersionHead;
235
-
236
- #[tokio::test]
237
- async fn active_scope_uses_session_version() {
238
- let version_ref = RowsVersionRefReader::new(Vec::new());
239
- let ids =
240
- resolve_provider_version_ids(&version_ref, &VersionBinding::active("main"), Vec::new())
241
- .await
242
- .expect("scope should resolve");
243
-
244
- assert_eq!(ids, vec!["main".to_string()]);
245
- }
246
-
247
- #[tokio::test]
248
- async fn explicit_scope_keeps_requested_versions() {
249
- let version_ref = RowsVersionRefReader::new(Vec::new());
250
- let ids = resolve_provider_version_ids(
251
- &version_ref,
252
- &VersionBinding::explicit(),
253
- vec!["version-a".to_string(), "global".to_string()],
254
- )
255
- .await
256
- .expect("scope should resolve");
257
-
258
- assert_eq!(ids, vec!["version-a".to_string(), "global".to_string()]);
259
- }
260
-
261
- #[tokio::test]
262
- async fn all_visible_scope_loads_version_refs_and_global() {
263
- let version_ref = RowsVersionRefReader::new(vec![
264
- VersionHead {
265
- version_id: "version-b".to_string(),
266
- commit_id: "commit-version-b".to_string(),
267
- },
268
- VersionHead {
269
- version_id: "version-a".to_string(),
270
- commit_id: "commit-version-a".to_string(),
271
- },
272
- ]);
273
- let ids =
274
- resolve_provider_version_ids(&version_ref, &VersionBinding::explicit(), Vec::new())
275
- .await
276
- .expect("scope should resolve");
277
-
278
- assert_eq!(
279
- ids,
280
- vec![
281
- "global".to_string(),
282
- "version-a".to_string(),
283
- "version-b".to_string(),
284
- ]
285
- );
286
- }
287
-
288
- #[test]
289
- fn write_scope_uses_fallback_version_when_version_is_implicit() {
290
- let scope = resolve_write_version_scope(
291
- None,
292
- None,
293
- Some("active-version"),
294
- "INSERT into surface",
295
- "surface",
296
- )
297
- .expect("scope should resolve");
298
-
299
- assert_eq!(
300
- scope,
301
- WriteVersionScope {
302
- version_id: "active-version".to_string(),
303
- global: false,
304
- }
305
- );
306
- }
307
-
308
- #[test]
309
- fn write_scope_requires_version_without_fallback() {
310
- let error = resolve_write_version_scope(None, None, None, "INSERT into surface", "surface")
311
- .expect_err("missing version should be rejected");
312
-
313
- assert!(error
314
- .to_string()
315
- .contains("INSERT into surface requires lixcol_version_id"));
316
- }
317
-
318
- #[test]
319
- fn write_scope_derives_global_from_global_version_id() {
320
- let scope = resolve_write_version_scope(
321
- None,
322
- Some(GLOBAL_VERSION_ID.to_string()),
323
- None,
324
- "INSERT into surface",
325
- "surface",
326
- )
327
- .expect("scope should resolve");
328
-
329
- assert_eq!(
330
- scope,
331
- WriteVersionScope {
332
- version_id: GLOBAL_VERSION_ID.to_string(),
333
- global: true,
334
- }
335
- );
336
- }
337
-
338
- #[test]
339
- fn write_scope_rejects_non_global_with_global_version_id() {
340
- let error = resolve_write_version_scope(
341
- Some(false),
342
- Some(GLOBAL_VERSION_ID.to_string()),
343
- None,
344
- "INSERT into surface",
345
- "surface",
346
- )
347
- .expect_err("conflicting global/version scope should be rejected");
348
-
349
- assert!(error
350
- .to_string()
351
- .contains("surface cannot set lixcol_global=false with global lixcol_version_id"));
352
- }
353
-
354
- #[test]
355
- fn write_scope_rejects_global_with_non_global_version_id() {
356
- let error = resolve_write_version_scope(
357
- Some(true),
358
- Some("version-a".to_string()),
359
- None,
360
- "INSERT into surface",
361
- "surface",
362
- )
363
- .expect_err("conflicting global/version scope should be rejected");
364
-
365
- assert!(error
366
- .to_string()
367
- .contains("surface cannot set lixcol_global=true with non-global lixcol_version_id"));
368
- }
369
-
370
- struct RowsVersionRefReader {
371
- heads: Vec<VersionHead>,
372
- }
373
-
374
- impl RowsVersionRefReader {
375
- fn new(heads: Vec<VersionHead>) -> Self {
376
- Self { heads }
377
- }
378
- }
379
-
380
- #[async_trait]
381
- impl VersionRefReader for RowsVersionRefReader {
382
- async fn load_head(&self, version_id: &str) -> Result<Option<VersionHead>, LixError> {
383
- Ok(self
384
- .heads
385
- .iter()
386
- .find(|head| head.version_id == version_id)
387
- .cloned())
388
- }
389
-
390
- async fn scan_heads(&self) -> Result<Vec<VersionHead>, LixError> {
391
- Ok(self.heads.clone())
392
- }
393
- }
394
- }