@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,221 +0,0 @@
1
- use crate::commit_graph::{CommitGraphCommit, CommitGraphReader};
2
- use crate::common::validate_non_empty_identity_value;
3
- use crate::LixError;
4
-
5
- use super::{VersionHead, VersionRefReader};
6
-
7
- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
8
- pub(crate) enum VersionOperation {
9
- CreateVersion,
10
- SwitchVersion,
11
- MergeVersion,
12
- MergeVersionPreview,
13
- LoadWorkspaceSelector,
14
- }
15
-
16
- impl VersionOperation {
17
- pub(crate) fn label(self) -> &'static str {
18
- match self {
19
- Self::CreateVersion => "create_version",
20
- Self::SwitchVersion => "switch_version",
21
- Self::MergeVersion => "merge_version",
22
- Self::MergeVersionPreview => "merge_version_preview",
23
- Self::LoadWorkspaceSelector => "load_workspace_version_id",
24
- }
25
- }
26
- }
27
-
28
- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
29
- pub(crate) enum VersionReferenceRole {
30
- Source,
31
- Target,
32
- WorkspaceSelector,
33
- CommitSource,
34
- }
35
-
36
- impl VersionReferenceRole {
37
- pub(crate) fn label(self) -> &'static str {
38
- match self {
39
- Self::Source => "source",
40
- Self::Target => "target",
41
- Self::WorkspaceSelector => "workspace_selector",
42
- Self::CommitSource => "commit_source",
43
- }
44
- }
45
- }
46
-
47
- /// Shared domain service for resolving public version references.
48
- ///
49
- /// Built-in version schemas describe row shape. This service owns semantic
50
- /// ref validation: non-empty ids, global sentinel handling, and missing refs.
51
- pub(crate) struct VersionLifecycle<'a> {
52
- refs: &'a dyn VersionRefReader,
53
- }
54
-
55
- impl<'a> VersionLifecycle<'a> {
56
- pub(crate) fn new(refs: &'a dyn VersionRefReader) -> Self {
57
- Self { refs }
58
- }
59
-
60
- pub(crate) fn require_non_empty_id(
61
- version_id: &str,
62
- operation: VersionOperation,
63
- role: VersionReferenceRole,
64
- ) -> Result<(), LixError> {
65
- require_non_empty_public_id("version_id", version_id, operation, role)
66
- }
67
-
68
- pub(crate) async fn require_existing_commit(
69
- commit_graph: &mut dyn CommitGraphReader,
70
- commit_id: &str,
71
- operation: VersionOperation,
72
- role: VersionReferenceRole,
73
- ) -> Result<CommitGraphCommit, LixError> {
74
- require_non_empty_public_id("commit_id", commit_id, operation, role)?;
75
- commit_graph
76
- .load_commit(commit_id)
77
- .await?
78
- .ok_or_else(|| LixError::version_not_found(commit_id, operation.label(), role.label()))
79
- }
80
-
81
- pub(crate) async fn require_existing_ref(
82
- &self,
83
- version_id: &str,
84
- operation: VersionOperation,
85
- role: VersionReferenceRole,
86
- ) -> Result<VersionHead, LixError> {
87
- Self::require_non_empty_id(version_id, operation, role)?;
88
- self.require_existing_stored_ref(version_id, operation, role)
89
- .await
90
- }
91
-
92
- pub(crate) async fn require_existing_commit_id(
93
- &self,
94
- version_id: &str,
95
- operation: VersionOperation,
96
- role: VersionReferenceRole,
97
- ) -> Result<String, LixError> {
98
- Ok(self
99
- .require_existing_ref(version_id, operation, role)
100
- .await?
101
- .commit_id)
102
- }
103
-
104
- async fn require_existing_stored_ref(
105
- &self,
106
- version_id: &str,
107
- operation: VersionOperation,
108
- role: VersionReferenceRole,
109
- ) -> Result<VersionHead, LixError> {
110
- self.refs
111
- .load_head(version_id)
112
- .await?
113
- .ok_or_else(|| LixError::version_not_found(version_id, operation.label(), role.label()))
114
- }
115
- }
116
-
117
- fn require_non_empty_public_id(
118
- label: &str,
119
- value: &str,
120
- operation: VersionOperation,
121
- role: VersionReferenceRole,
122
- ) -> Result<(), LixError> {
123
- validate_non_empty_identity_value(label, value)
124
- .map(|_| ())
125
- .map_err(|_| {
126
- LixError::new(
127
- LixError::CODE_INVALID_PARAM,
128
- format!(
129
- "{} {} {label} must be non-empty",
130
- operation.label(),
131
- role.label()
132
- ),
133
- )
134
- })
135
- }
136
-
137
- #[cfg(test)]
138
- mod tests {
139
- use async_trait::async_trait;
140
-
141
- use super::*;
142
-
143
- #[tokio::test]
144
- async fn require_existing_ref_returns_head() {
145
- let reader = RowsVersionRefReader::new(vec![VersionHead {
146
- version_id: "version-a".to_string(),
147
- commit_id: "commit-a".to_string(),
148
- }]);
149
- let lifecycle = VersionLifecycle::new(&reader);
150
-
151
- let head = lifecycle
152
- .require_existing_ref(
153
- "version-a",
154
- VersionOperation::SwitchVersion,
155
- VersionReferenceRole::Target,
156
- )
157
- .await
158
- .expect("version should resolve");
159
-
160
- assert_eq!(head.commit_id, "commit-a");
161
- }
162
-
163
- #[tokio::test]
164
- async fn require_existing_ref_rejects_empty_id_as_invalid_param() {
165
- let reader = RowsVersionRefReader::new(Vec::new());
166
- let lifecycle = VersionLifecycle::new(&reader);
167
-
168
- let error = lifecycle
169
- .require_existing_ref(
170
- "",
171
- VersionOperation::SwitchVersion,
172
- VersionReferenceRole::Target,
173
- )
174
- .await
175
- .expect_err("empty version id should be rejected before lookup");
176
-
177
- assert_eq!(error.code, LixError::CODE_INVALID_PARAM);
178
- }
179
-
180
- #[tokio::test]
181
- async fn require_existing_ref_reports_missing_version() {
182
- let reader = RowsVersionRefReader::new(Vec::new());
183
- let lifecycle = VersionLifecycle::new(&reader);
184
-
185
- let error = lifecycle
186
- .require_existing_ref(
187
- "missing",
188
- VersionOperation::SwitchVersion,
189
- VersionReferenceRole::Target,
190
- )
191
- .await
192
- .expect_err("missing version should be rejected");
193
-
194
- assert_eq!(error.code, LixError::CODE_VERSION_NOT_FOUND);
195
- }
196
-
197
- struct RowsVersionRefReader {
198
- heads: Vec<VersionHead>,
199
- }
200
-
201
- impl RowsVersionRefReader {
202
- fn new(heads: Vec<VersionHead>) -> Self {
203
- Self { heads }
204
- }
205
- }
206
-
207
- #[async_trait]
208
- impl VersionRefReader for RowsVersionRefReader {
209
- async fn load_head(&self, version_id: &str) -> Result<Option<VersionHead>, LixError> {
210
- Ok(self
211
- .heads
212
- .iter()
213
- .find(|head| head.version_id == version_id)
214
- .cloned())
215
- }
216
-
217
- async fn scan_heads(&self) -> Result<Vec<VersionHead>, LixError> {
218
- Ok(self.heads.clone())
219
- }
220
- }
221
- }
@@ -1,13 +0,0 @@
1
- mod context;
2
- mod lifecycle;
3
- mod refs;
4
- mod stage_rows;
5
- mod types;
6
-
7
- pub(crate) use context::VersionContext;
8
- pub(crate) use lifecycle::{VersionLifecycle, VersionOperation, VersionReferenceRole};
9
- pub(crate) use stage_rows::{
10
- version_descriptor_stage_row, version_descriptor_tombstone_row, version_ref_stage_row,
11
- version_ref_tombstone_row, VERSION_DESCRIPTOR_SCHEMA_KEY, VERSION_REF_SCHEMA_KEY,
12
- };
13
- pub(crate) use types::{VersionHead, VersionRefReader};
@@ -1,330 +0,0 @@
1
- use std::sync::Arc;
2
-
3
- use tokio::sync::Mutex;
4
-
5
- use crate::entity_identity::EntityIdentity;
6
- use crate::storage::{StorageReader, StorageWriteSet};
7
- use crate::untracked_state::{
8
- MaterializedUntrackedStateRow, UntrackedStateContext, UntrackedStateFilter, UntrackedStateRow,
9
- UntrackedStateRowRequest, UntrackedStateScanRequest,
10
- };
11
- use crate::version::VERSION_REF_SCHEMA_KEY;
12
- use crate::version::{VersionHead, VersionRefReader};
13
- use crate::GLOBAL_VERSION_ID;
14
- use crate::{LixError, NullableKeyFilter};
15
-
16
- /// Typed access to moving version heads stored in untracked state.
17
- ///
18
- /// Version refs are one of the inputs used by live_state visibility, so this
19
- /// context deliberately bypasses live_state and reads the underlying untracked
20
- /// rows directly. That keeps the dependency acyclic:
21
- /// untracked_state -> version_ref -> live_state.
22
- pub(super) struct VersionRefContext {
23
- untracked_state: Arc<UntrackedStateContext>,
24
- }
25
-
26
- impl VersionRefContext {
27
- pub(super) fn new(untracked_state: Arc<UntrackedStateContext>) -> Self {
28
- Self { untracked_state }
29
- }
30
-
31
- /// Creates a version-ref reader over a caller-provided KV store.
32
- pub(super) fn reader<S>(&self, store: S) -> VersionRefStoreReader<S>
33
- where
34
- S: StorageReader,
35
- {
36
- VersionRefStoreReader {
37
- untracked_state: Arc::clone(&self.untracked_state),
38
- store: Mutex::new(store),
39
- }
40
- }
41
-
42
- /// Creates a version-ref writer over a transaction-local storage write set.
43
- pub(super) fn writer<'a>(&self, writes: &'a mut StorageWriteSet) -> VersionRefWriter<'a> {
44
- VersionRefWriter {
45
- untracked_state: Arc::clone(&self.untracked_state),
46
- writes,
47
- }
48
- }
49
- }
50
-
51
- /// Read side for version heads.
52
- pub(super) struct VersionRefStoreReader<S>
53
- where
54
- S: StorageReader,
55
- {
56
- untracked_state: Arc<UntrackedStateContext>,
57
- store: Mutex<S>,
58
- }
59
-
60
- impl<S> VersionRefStoreReader<S>
61
- where
62
- S: StorageReader,
63
- {
64
- pub(crate) async fn load_head(
65
- &self,
66
- version_id: &str,
67
- ) -> Result<Option<VersionHead>, LixError> {
68
- let mut store = self.store.lock().await;
69
- let Some(row) = self
70
- .untracked_state
71
- .reader(&mut *store as &mut dyn StorageReader)
72
- .load_row(&UntrackedStateRowRequest {
73
- schema_key: VERSION_REF_SCHEMA_KEY.to_string(),
74
- version_id: GLOBAL_VERSION_ID.to_string(),
75
- entity_id: EntityIdentity::single(version_id),
76
- file_id: NullableKeyFilter::Null,
77
- })
78
- .await?
79
- else {
80
- return Ok(None);
81
- };
82
-
83
- decode_version_head(version_id, &row)
84
- }
85
-
86
- pub(crate) async fn load_head_commit_id(
87
- &self,
88
- version_id: &str,
89
- ) -> Result<Option<String>, LixError> {
90
- Ok(self.load_head(version_id).await?.map(|head| head.commit_id))
91
- }
92
-
93
- pub(crate) async fn scan_heads(&self) -> Result<Vec<VersionHead>, LixError> {
94
- let mut store = self.store.lock().await;
95
- let rows = self
96
- .untracked_state
97
- .reader(&mut *store as &mut dyn StorageReader)
98
- .scan_rows(&UntrackedStateScanRequest {
99
- filter: UntrackedStateFilter {
100
- schema_keys: vec![VERSION_REF_SCHEMA_KEY.to_string()],
101
- version_ids: vec![GLOBAL_VERSION_ID.to_string()],
102
- ..UntrackedStateFilter::default()
103
- },
104
- ..UntrackedStateScanRequest::default()
105
- })
106
- .await?;
107
- let mut heads = rows
108
- .iter()
109
- .map(|row| {
110
- let version_id = row.entity_id.as_single_string_owned()?;
111
- decode_version_head(&version_id, row)
112
- })
113
- .collect::<Result<Vec<_>, _>>()?
114
- .into_iter()
115
- .flatten()
116
- .collect::<Vec<_>>();
117
- heads.sort_by(|left, right| left.version_id.cmp(&right.version_id));
118
- Ok(heads)
119
- }
120
- }
121
-
122
- #[async_trait::async_trait]
123
- impl<S> VersionRefReader for VersionRefStoreReader<S>
124
- where
125
- S: StorageReader + Send,
126
- {
127
- async fn load_head(&self, version_id: &str) -> Result<Option<VersionHead>, LixError> {
128
- VersionRefStoreReader::load_head(self, version_id).await
129
- }
130
-
131
- async fn load_head_commit_id(&self, version_id: &str) -> Result<Option<String>, LixError> {
132
- VersionRefStoreReader::load_head_commit_id(self, version_id).await
133
- }
134
-
135
- async fn scan_heads(&self) -> Result<Vec<VersionHead>, LixError> {
136
- VersionRefStoreReader::scan_heads(self).await
137
- }
138
- }
139
-
140
- /// Write side for moving version heads.
141
- pub(super) struct VersionRefWriter<'a> {
142
- untracked_state: Arc<UntrackedStateContext>,
143
- writes: &'a mut StorageWriteSet,
144
- }
145
-
146
- impl VersionRefWriter<'_> {
147
- pub(crate) fn stage_rows(&mut self, rows: &[UntrackedStateRow]) -> Result<(), LixError> {
148
- self.untracked_state
149
- .writer(self.writes)
150
- .stage_rows(rows.iter().map(|row| row.as_ref()))
151
- }
152
- }
153
-
154
- fn decode_version_head(
155
- requested_version_id: &str,
156
- row: &MaterializedUntrackedStateRow,
157
- ) -> Result<Option<VersionHead>, LixError> {
158
- let Some(snapshot_content) = row.snapshot_content.as_deref() else {
159
- return Ok(None);
160
- };
161
- let snapshot =
162
- serde_json::from_str::<serde_json::Value>(snapshot_content).map_err(|error| {
163
- LixError::new(
164
- "LIX_ERROR_UNKNOWN",
165
- format!("engine version-ref snapshot parse failed: {error}"),
166
- )
167
- })?;
168
- let commit_id = snapshot
169
- .get("commit_id")
170
- .and_then(serde_json::Value::as_str)
171
- .ok_or_else(|| {
172
- LixError::new(
173
- "LIX_ERROR_UNKNOWN",
174
- format!("version ref for version '{requested_version_id}' is missing commit_id"),
175
- )
176
- })?;
177
- Ok(Some(VersionHead {
178
- version_id: requested_version_id.to_string(),
179
- commit_id: commit_id.to_string(),
180
- }))
181
- }
182
-
183
- #[cfg(test)]
184
- mod tests {
185
- use std::sync::Arc;
186
-
187
- use crate::backend::testing::UnitTestBackend;
188
- use crate::storage::{StorageContext, StorageWriteSet};
189
- use crate::transaction::prepare_version_ref_row;
190
- use crate::untracked_state::{UntrackedStateContext, UntrackedStateRowRequest};
191
-
192
- use super::*;
193
-
194
- #[tokio::test]
195
- async fn load_head_returns_none_when_missing() {
196
- let storage = StorageContext::new(Arc::new(UnitTestBackend::new()));
197
- let version_ref = test_version_ref();
198
-
199
- let head = version_ref
200
- .reader(storage)
201
- .load_head("missing-version")
202
- .await
203
- .expect("missing version ref should load cleanly");
204
-
205
- assert_eq!(head, None);
206
- }
207
-
208
- #[tokio::test]
209
- async fn advance_head_writes_untracked_global_ref() {
210
- let storage = StorageContext::new(Arc::new(UnitTestBackend::new()));
211
- let version_ref = VersionRefContext::new(Arc::new(UntrackedStateContext::new()));
212
- let mut transaction = storage
213
- .begin_write_transaction()
214
- .await
215
- .expect("transaction should open");
216
-
217
- let mut writes = StorageWriteSet::new();
218
- stage_version_head(
219
- &version_ref,
220
- &mut writes,
221
- "version-a",
222
- "commit-a",
223
- "2026-01-01T00:00:00Z",
224
- )
225
- .expect("version head should advance");
226
- writes
227
- .apply(&mut transaction.as_mut())
228
- .await
229
- .expect("version head should apply");
230
- transaction
231
- .commit()
232
- .await
233
- .expect("transaction should commit");
234
-
235
- let head = version_ref
236
- .reader(storage.clone())
237
- .load_head("version-a")
238
- .await
239
- .expect("version head should load")
240
- .expect("version head should exist");
241
- assert_eq!(head.version_id, "version-a");
242
- assert_eq!(head.commit_id, "commit-a");
243
-
244
- let mut reader = UntrackedStateContext::new().reader(storage);
245
- let row = reader
246
- .load_row(&UntrackedStateRowRequest {
247
- schema_key: VERSION_REF_SCHEMA_KEY.to_string(),
248
- version_id: GLOBAL_VERSION_ID.to_string(),
249
- entity_id: crate::entity_identity::EntityIdentity::single("version-a"),
250
- file_id: NullableKeyFilter::Null,
251
- })
252
- .await
253
- .expect("version-ref row should load")
254
- .expect("version-ref row should exist");
255
- assert!(row.global);
256
- assert_eq!(row.created_at, "2026-01-01T00:00:00Z");
257
- assert_eq!(row.updated_at, "2026-01-01T00:00:00Z");
258
- }
259
-
260
- #[tokio::test]
261
- async fn scan_heads_returns_sorted_version_heads() {
262
- let storage = StorageContext::new(Arc::new(UnitTestBackend::new()));
263
- let version_ref = test_version_ref();
264
- let mut transaction = storage
265
- .begin_write_transaction()
266
- .await
267
- .expect("transaction should open");
268
-
269
- let mut writes = StorageWriteSet::new();
270
- stage_version_head(
271
- &version_ref,
272
- &mut writes,
273
- "version-b",
274
- "commit-b",
275
- "2026-01-01T00:00:00Z",
276
- )
277
- .expect("version-b should advance");
278
- stage_version_head(
279
- &version_ref,
280
- &mut writes,
281
- "version-a",
282
- "commit-a",
283
- "2026-01-01T00:00:00Z",
284
- )
285
- .expect("version-a should advance");
286
- writes
287
- .apply(&mut transaction.as_mut())
288
- .await
289
- .expect("version heads should apply");
290
- transaction
291
- .commit()
292
- .await
293
- .expect("transaction should commit");
294
-
295
- let heads = version_ref
296
- .reader(storage)
297
- .scan_heads()
298
- .await
299
- .expect("heads should scan");
300
-
301
- assert_eq!(
302
- heads,
303
- vec![
304
- VersionHead {
305
- version_id: "version-a".to_string(),
306
- commit_id: "commit-a".to_string(),
307
- },
308
- VersionHead {
309
- version_id: "version-b".to_string(),
310
- commit_id: "commit-b".to_string(),
311
- },
312
- ]
313
- );
314
- }
315
-
316
- fn test_version_ref() -> VersionRefContext {
317
- VersionRefContext::new(Arc::new(UntrackedStateContext::new()))
318
- }
319
-
320
- fn stage_version_head(
321
- version_ref: &VersionRefContext,
322
- writes: &mut StorageWriteSet,
323
- version_id: &str,
324
- commit_id: &str,
325
- timestamp: &str,
326
- ) -> Result<(), LixError> {
327
- let canonical_row = prepare_version_ref_row(version_id, commit_id, timestamp)?;
328
- version_ref.writer(writes).stage_rows(&[canonical_row.row])
329
- }
330
- }
@@ -1,67 +0,0 @@
1
- use serde_json::json;
2
-
3
- use crate::entity_identity::EntityIdentity;
4
- use crate::transaction::types::{TransactionJson, TransactionWriteRow};
5
- use crate::GLOBAL_VERSION_ID;
6
-
7
- pub(crate) const VERSION_DESCRIPTOR_SCHEMA_KEY: &str = "lix_version_descriptor";
8
- pub(crate) const VERSION_REF_SCHEMA_KEY: &str = "lix_version_ref";
9
-
10
- pub(crate) fn version_descriptor_stage_row(
11
- version_id: &str,
12
- name: &str,
13
- hidden: bool,
14
- ) -> TransactionWriteRow {
15
- TransactionWriteRow {
16
- entity_id: Some(EntityIdentity::single(version_id)),
17
- schema_key: VERSION_DESCRIPTOR_SCHEMA_KEY.to_string(),
18
- file_id: None,
19
- snapshot: Some(TransactionJson::from_value_unchecked(json!({
20
- "id": version_id,
21
- "name": name,
22
- "hidden": hidden,
23
- }))),
24
- metadata: None,
25
- origin: None,
26
- created_at: None,
27
- updated_at: None,
28
- global: true,
29
- change_id: None,
30
- commit_id: None,
31
- untracked: false,
32
- version_id: GLOBAL_VERSION_ID.to_string(),
33
- }
34
- }
35
-
36
- pub(crate) fn version_ref_stage_row(version_id: &str, commit_id: &str) -> TransactionWriteRow {
37
- TransactionWriteRow {
38
- entity_id: Some(EntityIdentity::single(version_id)),
39
- schema_key: VERSION_REF_SCHEMA_KEY.to_string(),
40
- file_id: None,
41
- snapshot: Some(TransactionJson::from_value_unchecked(json!({
42
- "id": version_id,
43
- "commit_id": commit_id,
44
- }))),
45
- metadata: None,
46
- origin: None,
47
- created_at: None,
48
- updated_at: None,
49
- global: true,
50
- change_id: None,
51
- commit_id: None,
52
- untracked: true,
53
- version_id: GLOBAL_VERSION_ID.to_string(),
54
- }
55
- }
56
-
57
- pub(crate) fn version_descriptor_tombstone_row(version_id: &str) -> TransactionWriteRow {
58
- let mut row = version_descriptor_stage_row(version_id, "", false);
59
- row.snapshot = None;
60
- row
61
- }
62
-
63
- pub(crate) fn version_ref_tombstone_row(version_id: &str) -> TransactionWriteRow {
64
- let mut row = version_ref_stage_row(version_id, "");
65
- row.snapshot = None;
66
- row
67
- }
@@ -1,21 +0,0 @@
1
- /// Current changelog head for a version.
2
- #[derive(Debug, Clone, PartialEq, Eq)]
3
- pub(crate) struct VersionHead {
4
- pub(crate) version_id: String,
5
- pub(crate) commit_id: String,
6
- }
7
-
8
- /// Typed reader for moving version heads.
9
- #[async_trait::async_trait]
10
- pub(crate) trait VersionRefReader: Send + Sync {
11
- async fn load_head(&self, version_id: &str) -> Result<Option<VersionHead>, crate::LixError>;
12
-
13
- async fn load_head_commit_id(
14
- &self,
15
- version_id: &str,
16
- ) -> Result<Option<String>, crate::LixError> {
17
- Ok(self.load_head(version_id).await?.map(|head| head.commit_id))
18
- }
19
-
20
- async fn scan_heads(&self) -> Result<Vec<VersionHead>, crate::LixError>;
21
- }