@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,11 +1,10 @@
1
1
  use serde_json::{json, Value as JsonValue};
2
2
 
3
- use crate::transaction::types::TransactionWrite;
4
- use crate::version::{VersionLifecycle, VersionOperation, VersionReferenceRole};
3
+ use crate::branch::{BranchLifecycle, BranchOperation, BranchReferenceRole};
4
+ use crate::storage::StorageBackend;
5
5
  use crate::LixError;
6
6
 
7
7
  use super::analysis::{analyze, MergeCommits, MergeOutcome};
8
- use super::apply::adopted_changes_from_merge_plan;
9
8
  use super::conflicts::{
10
9
  MergeConflict as AnalysisMergeConflict,
11
10
  MergeConflictChangeKind as AnalysisMergeConflictChangeKind,
@@ -13,28 +12,30 @@ use super::conflicts::{
13
12
  };
14
13
  use super::stats::MergeStats;
15
14
  use crate::session::context::SessionContext;
15
+ use crate::tracked_state::TrackedStateMergePick;
16
+ use crate::transaction::types::StagedCommitChangeRef;
16
17
 
17
- /// Options for merging another version into this session's active version.
18
+ /// Options for merging another branch into this session's active branch.
18
19
  #[derive(Debug, Clone, PartialEq, Eq)]
19
- pub struct MergeVersionOptions {
20
- /// Version whose changes should be merged into the active session version.
21
- pub source_version_id: String,
20
+ pub struct MergeBranchOptions {
21
+ /// Branch whose changes should be merged into the active session branch.
22
+ pub source_branch_id: String,
22
23
  }
23
24
 
24
- /// Options for previewing a merge from another version into this session's
25
- /// active version.
25
+ /// Options for previewing a merge from another branch into this session's
26
+ /// active branch.
26
27
  #[derive(Debug, Clone, PartialEq, Eq)]
27
- pub struct MergeVersionPreviewOptions {
28
- /// Version whose changes would be merged into the active session version.
29
- pub source_version_id: String,
28
+ pub struct MergeBranchPreviewOptions {
29
+ /// Branch whose changes would be merged into the active session branch.
30
+ pub source_branch_id: String,
30
31
  }
31
32
 
32
- /// Receipt returned after merging a version.
33
+ /// Receipt returned after merging a branch.
33
34
  #[derive(Debug, Clone, PartialEq, Eq)]
34
- pub struct MergeVersionReceipt {
35
- pub outcome: MergeVersionOutcome,
36
- pub target_version_id: String,
37
- pub source_version_id: String,
35
+ pub struct MergeBranchReceipt {
36
+ pub outcome: MergeBranchOutcome,
37
+ pub target_branch_id: String,
38
+ pub source_branch_id: String,
38
39
  pub base_commit_id: String,
39
40
  pub target_head_before_commit_id: String,
40
41
  pub source_head_before_commit_id: String,
@@ -52,10 +53,10 @@ pub struct MergeChangeStats {
52
53
  }
53
54
 
54
55
  #[derive(Debug, Clone, PartialEq, Eq)]
55
- pub struct MergeVersionPreview {
56
- pub outcome: MergeVersionOutcome,
57
- pub target_version_id: String,
58
- pub source_version_id: String,
56
+ pub struct MergeBranchPreview {
57
+ pub outcome: MergeBranchOutcome,
58
+ pub target_branch_id: String,
59
+ pub source_branch_id: String,
59
60
  pub base_commit_id: String,
60
61
  pub target_head_commit_id: String,
61
62
  pub source_head_commit_id: String,
@@ -67,7 +68,7 @@ pub struct MergeVersionPreview {
67
68
  pub struct MergeConflict {
68
69
  pub kind: MergeConflictKind,
69
70
  pub schema_key: String,
70
- pub entity_id: JsonValue,
71
+ pub entity_pk: JsonValue,
71
72
  pub file_id: Option<String>,
72
73
  pub target: MergeConflictSide,
73
74
  pub source: MergeConflictSide,
@@ -93,43 +94,48 @@ pub enum MergeConflictChangeKind {
93
94
  }
94
95
 
95
96
  #[derive(Debug, Clone, Copy, PartialEq, Eq)]
96
- pub enum MergeVersionOutcome {
97
+ pub enum MergeBranchOutcome {
97
98
  AlreadyUpToDate,
98
99
  FastForward,
99
100
  MergeCommitted,
100
101
  }
101
102
 
102
- impl SessionContext {
103
- /// Previews merging `source_version_id` into this session's active version
103
+ impl<B> SessionContext<B>
104
+ where
105
+ B: StorageBackend + Clone + Send + Sync + 'static,
106
+ for<'backend> B::Read<'backend>: Clone + Send + Sync + 'static,
107
+ for<'backend> B::Write<'backend>: Send,
108
+ {
109
+ /// Previews merging `source_branch_id` into this session's active branch
104
110
  /// without advancing refs, staging changes, or creating commits.
105
- pub async fn merge_version_preview(
111
+ pub async fn merge_branch_preview(
106
112
  &self,
107
- options: MergeVersionPreviewOptions,
108
- ) -> Result<MergeVersionPreview, LixError> {
109
- let source_version_id = options.source_version_id;
113
+ options: MergeBranchPreviewOptions,
114
+ ) -> Result<MergeBranchPreview, LixError> {
115
+ let source_branch_id = options.source_branch_id;
110
116
 
111
117
  self.with_write_transaction(|transaction| {
112
118
  Box::pin(async move {
113
- let active_version_id = transaction.active_version_id().to_string();
114
- if source_version_id == active_version_id {
115
- return Err(LixError::invalid_self_merge(active_version_id));
119
+ let active_branch_id = transaction.active_branch_id().to_string();
120
+ if source_branch_id == active_branch_id {
121
+ return Err(LixError::invalid_self_merge(active_branch_id));
116
122
  }
117
123
 
118
124
  let (target_head, source_head) = {
119
- let reader = transaction.version_ref_reader();
120
- let lifecycle = VersionLifecycle::new(&reader);
125
+ let reader = transaction.branch_ref_reader();
126
+ let lifecycle = BranchLifecycle::new(&reader);
121
127
  let target_head = lifecycle
122
128
  .require_existing_commit_id(
123
- &active_version_id,
124
- VersionOperation::MergeVersionPreview,
125
- VersionReferenceRole::Target,
129
+ &active_branch_id,
130
+ BranchOperation::MergeBranchPreview,
131
+ BranchReferenceRole::Target,
126
132
  )
127
133
  .await?;
128
134
  let source_head = lifecycle
129
135
  .require_existing_commit_id(
130
- &source_version_id,
131
- VersionOperation::MergeVersionPreview,
132
- VersionReferenceRole::Source,
136
+ &source_branch_id,
137
+ BranchOperation::MergeBranchPreview,
138
+ BranchReferenceRole::Source,
133
139
  )
134
140
  .await?;
135
141
  (target_head, source_head)
@@ -154,8 +160,8 @@ impl SessionContext {
154
160
  };
155
161
 
156
162
  Ok(preview_from_analysis(
157
- &active_version_id,
158
- &source_version_id,
163
+ &active_branch_id,
164
+ &source_branch_id,
159
165
  &analysis,
160
166
  ))
161
167
  })
@@ -163,40 +169,40 @@ impl SessionContext {
163
169
  .await
164
170
  }
165
171
 
166
- /// Merges `source_version_id` into this session's active version.
172
+ /// Merges `source_branch_id` into this session's active branch.
167
173
  ///
168
174
  /// The generated target commit keeps the previous target head as its first
169
175
  /// parent and records the source head as an additional parent, so the
170
- /// commit graph preserves branch ancestry while tracked-state storage can
171
- /// build the new root by applying source effects onto the target root.
172
- pub async fn merge_version(
176
+ /// commit graph preserves branch ancestry while tracked-state storage
177
+ /// selects the planned source changes into the new target root.
178
+ pub async fn merge_branch(
173
179
  &self,
174
- options: MergeVersionOptions,
175
- ) -> Result<MergeVersionReceipt, LixError> {
176
- let source_version_id = options.source_version_id;
180
+ options: MergeBranchOptions,
181
+ ) -> Result<MergeBranchReceipt, LixError> {
182
+ let source_branch_id = options.source_branch_id;
177
183
 
178
184
  self.with_write_transaction(|transaction| {
179
185
  Box::pin(async move {
180
- let active_version_id = transaction.active_version_id().to_string();
181
- if source_version_id == active_version_id {
182
- return Err(LixError::invalid_self_merge(active_version_id));
186
+ let active_branch_id = transaction.active_branch_id().to_string();
187
+ if source_branch_id == active_branch_id {
188
+ return Err(LixError::invalid_self_merge(active_branch_id));
183
189
  }
184
190
 
185
191
  let (target_head, source_head) = {
186
- let reader = transaction.version_ref_reader();
187
- let lifecycle = VersionLifecycle::new(&reader);
192
+ let reader = transaction.branch_ref_reader();
193
+ let lifecycle = BranchLifecycle::new(&reader);
188
194
  let target_head = lifecycle
189
195
  .require_existing_commit_id(
190
- &active_version_id,
191
- VersionOperation::MergeVersion,
192
- VersionReferenceRole::Target,
196
+ &active_branch_id,
197
+ BranchOperation::MergeBranch,
198
+ BranchReferenceRole::Target,
193
199
  )
194
200
  .await?;
195
201
  let source_head = lifecycle
196
202
  .require_existing_commit_id(
197
- &source_version_id,
198
- VersionOperation::MergeVersion,
199
- VersionReferenceRole::Source,
203
+ &source_branch_id,
204
+ BranchOperation::MergeBranch,
205
+ BranchReferenceRole::Source,
200
206
  )
201
207
  .await?;
202
208
  (target_head, source_head)
@@ -222,10 +228,10 @@ impl SessionContext {
222
228
  };
223
229
 
224
230
  if analysis.outcome == MergeOutcome::AlreadyUpToDate {
225
- return Ok(MergeVersionReceipt {
226
- outcome: MergeVersionOutcome::AlreadyUpToDate,
227
- target_version_id: active_version_id,
228
- source_version_id,
231
+ return Ok(MergeBranchReceipt {
232
+ outcome: MergeBranchOutcome::AlreadyUpToDate,
233
+ target_branch_id: active_branch_id,
234
+ source_branch_id,
229
235
  base_commit_id: analysis.commits.base_commit_id,
230
236
  target_head_after_commit_id: analysis.commits.target_commit_id.clone(),
231
237
  target_head_before_commit_id: analysis.commits.target_commit_id,
@@ -237,13 +243,13 @@ impl SessionContext {
237
243
 
238
244
  if analysis.outcome == MergeOutcome::FastForward {
239
245
  transaction
240
- .advance_version_ref(&active_version_id, &analysis.commits.source_commit_id)
246
+ .advance_branch_ref(&active_branch_id, &analysis.commits.source_commit_id)
241
247
  .await?;
242
248
 
243
- return Ok(MergeVersionReceipt {
244
- outcome: MergeVersionOutcome::FastForward,
245
- target_version_id: active_version_id,
246
- source_version_id,
249
+ return Ok(MergeBranchReceipt {
250
+ outcome: MergeBranchOutcome::FastForward,
251
+ target_branch_id: active_branch_id,
252
+ source_branch_id,
247
253
  base_commit_id: analysis.commits.base_commit_id,
248
254
  target_head_before_commit_id: analysis.commits.target_commit_id,
249
255
  source_head_before_commit_id: analysis.commits.source_commit_id.clone(),
@@ -267,72 +273,56 @@ impl SessionContext {
267
273
  )?);
268
274
  }
269
275
 
270
- let adopted_changes =
271
- adopted_changes_from_merge_plan(merge_plan, &active_version_id);
272
- if adopted_changes.is_empty() {
273
- let created_merge_commit_id =
274
- transaction.stage_empty_commit(active_version_id.clone())?;
275
- transaction.add_commit_parent(
276
- active_version_id.clone(),
277
- analysis.commits.source_commit_id.clone(),
278
- )?;
279
- return Ok(MergeVersionReceipt {
280
- outcome: MergeVersionOutcome::MergeCommitted,
281
- target_version_id: active_version_id,
282
- source_version_id,
283
- base_commit_id: analysis.commits.base_commit_id,
284
- target_head_after_commit_id: created_merge_commit_id.clone(),
285
- target_head_before_commit_id: analysis.commits.target_commit_id,
286
- source_head_before_commit_id: analysis.commits.source_commit_id,
287
- created_merge_commit_id: Some(created_merge_commit_id),
288
- change_stats: merge_change_stats_from_analysis(&analysis.stats),
289
- });
290
- }
291
-
292
- transaction
293
- .stage_write(TransactionWrite::AdoptedChanges {
294
- changes: adopted_changes,
295
- })
296
- .await?;
297
- let created_merge_commit_id = transaction
298
- .staged_commit_id(&active_version_id)?
299
- .ok_or_else(|| {
300
- LixError::new(
301
- "LIX_ERROR_UNKNOWN",
302
- "merge_version staged tracked rows without a commit id",
303
- )
304
- })?;
305
- transaction.add_commit_parent(
306
- active_version_id.clone(),
276
+ let selected_changes = merge_plan
277
+ .picks
278
+ .iter()
279
+ .map(selected_change_from_merge_pick)
280
+ .collect::<Vec<_>>();
281
+ let created_merge_commit_id = transaction.stage_merge_commit(
282
+ active_branch_id.clone(),
307
283
  analysis.commits.source_commit_id.clone(),
284
+ selected_changes,
308
285
  )?;
309
-
310
- Ok(MergeVersionReceipt {
311
- outcome: MergeVersionOutcome::MergeCommitted,
312
- target_version_id: active_version_id,
313
- source_version_id,
286
+ return Ok(MergeBranchReceipt {
287
+ outcome: MergeBranchOutcome::MergeCommitted,
288
+ target_branch_id: active_branch_id,
289
+ source_branch_id,
314
290
  base_commit_id: analysis.commits.base_commit_id,
291
+ target_head_after_commit_id: created_merge_commit_id.clone(),
315
292
  target_head_before_commit_id: analysis.commits.target_commit_id,
316
293
  source_head_before_commit_id: analysis.commits.source_commit_id,
317
- created_merge_commit_id: Some(created_merge_commit_id.clone()),
318
- target_head_after_commit_id: created_merge_commit_id,
294
+ created_merge_commit_id: Some(created_merge_commit_id),
319
295
  change_stats: merge_change_stats_from_analysis(&analysis.stats),
320
- })
296
+ });
321
297
  })
322
298
  })
323
299
  .await
324
300
  }
325
301
  }
326
302
 
303
+ fn selected_change_from_merge_pick(pick: &TrackedStateMergePick) -> StagedCommitChangeRef {
304
+ StagedCommitChangeRef {
305
+ schema_key: pick.selected_row.schema_key.clone(),
306
+ file_id: pick.selected_row.file_id.clone(),
307
+ entity_pk: pick.selected_row.entity_pk.clone(),
308
+ change_id: pick.change_id.clone(),
309
+ snapshot_ref: pick.selected_row.snapshot_ref,
310
+ metadata_ref: pick.selected_row.metadata_ref,
311
+ deleted: pick.selected_row.deleted,
312
+ created_at: pick.selected_row.created_at.clone(),
313
+ updated_at: pick.selected_row.updated_at.clone(),
314
+ }
315
+ }
316
+
327
317
  fn preview_from_analysis(
328
- target_version_id: &str,
329
- source_version_id: &str,
318
+ target_branch_id: &str,
319
+ source_branch_id: &str,
330
320
  analysis: &super::analysis::MergeAnalysis,
331
- ) -> MergeVersionPreview {
332
- MergeVersionPreview {
333
- outcome: merge_version_outcome_from_analysis(analysis.outcome),
334
- target_version_id: target_version_id.to_string(),
335
- source_version_id: source_version_id.to_string(),
321
+ ) -> MergeBranchPreview {
322
+ MergeBranchPreview {
323
+ outcome: merge_branch_outcome_from_analysis(analysis.outcome),
324
+ target_branch_id: target_branch_id.to_string(),
325
+ source_branch_id: source_branch_id.to_string(),
336
326
  base_commit_id: analysis.commits.base_commit_id.clone(),
337
327
  target_head_commit_id: analysis.commits.target_commit_id.clone(),
338
328
  source_head_commit_id: analysis.commits.source_commit_id.clone(),
@@ -345,11 +335,11 @@ fn preview_from_analysis(
345
335
  }
346
336
  }
347
337
 
348
- fn merge_version_outcome_from_analysis(outcome: MergeOutcome) -> MergeVersionOutcome {
338
+ fn merge_branch_outcome_from_analysis(outcome: MergeOutcome) -> MergeBranchOutcome {
349
339
  match outcome {
350
- MergeOutcome::AlreadyUpToDate => MergeVersionOutcome::AlreadyUpToDate,
351
- MergeOutcome::FastForward => MergeVersionOutcome::FastForward,
352
- MergeOutcome::MergeCommitted => MergeVersionOutcome::MergeCommitted,
340
+ MergeOutcome::AlreadyUpToDate => MergeBranchOutcome::AlreadyUpToDate,
341
+ MergeOutcome::FastForward => MergeBranchOutcome::FastForward,
342
+ MergeOutcome::MergeCommitted => MergeBranchOutcome::MergeCommitted,
353
343
  }
354
344
  }
355
345
 
@@ -368,7 +358,7 @@ fn merge_conflict_from_analysis(conflict: &AnalysisMergeConflict) -> MergeConfli
368
358
  AnalysisMergeConflictKind::SameEntityChanged => MergeConflictKind::SameEntityChanged,
369
359
  },
370
360
  schema_key: conflict.schema_key.clone(),
371
- entity_id: conflict.entity_id.clone(),
361
+ entity_pk: conflict.entity_pk.clone(),
372
362
  file_id: conflict.file_id.clone(),
373
363
  target: merge_conflict_side_from_analysis(&conflict.target),
374
364
  source: merge_conflict_side_from_analysis(&conflict.source),
@@ -391,9 +381,9 @@ fn merge_conflict_error(conflicts: &[MergeConflict]) -> Result<LixError, LixErro
391
381
  let conflict_count = conflicts.len();
392
382
  Ok(LixError::new(
393
383
  LixError::CODE_MERGE_CONFLICT,
394
- format!("merge_version found {conflict_count} tracked-state conflict(s)"),
384
+ format!("merge_branch found {conflict_count} tracked-state conflict(s)"),
395
385
  )
396
- .with_hint("Resolve the conflicting entities in the target version, then retry the merge.")
386
+ .with_hint("Resolve the conflicting entities in the target branch, then retry the merge.")
397
387
  .with_details(json!({
398
388
  "conflicts": conflicts.iter()
399
389
  .map(merge_conflict_details)
@@ -407,7 +397,7 @@ fn merge_conflict_details(conflict: &MergeConflict) -> serde_json::Value {
407
397
  MergeConflictKind::SameEntityChanged => "sameEntityChanged",
408
398
  },
409
399
  "schemaKey": conflict.schema_key,
410
- "entityId": conflict.entity_id,
400
+ "entityPk": conflict.entity_pk,
411
401
  "fileId": conflict.file_id,
412
402
  "target": merge_conflict_side_details(&conflict.target),
413
403
  "source": merge_conflict_side_details(&conflict.source),
@@ -8,7 +8,7 @@ use serde_json::Value as JsonValue;
8
8
  pub(crate) struct MergeConflict {
9
9
  pub(crate) kind: MergeConflictKind,
10
10
  pub(crate) schema_key: String,
11
- pub(crate) entity_id: JsonValue,
11
+ pub(crate) entity_pk: JsonValue,
12
12
  pub(crate) file_id: Option<String>,
13
13
  pub(crate) target: MergeConflictSide,
14
14
  pub(crate) source: MergeConflictSide,
@@ -43,7 +43,7 @@ fn conflict_from_tracked(conflict: &TrackedStateMergeConflict) -> Result<MergeCo
43
43
  Ok(MergeConflict {
44
44
  kind: MergeConflictKind::SameEntityChanged,
45
45
  schema_key: conflict.identity.schema_key.clone(),
46
- entity_id: conflict.identity.entity_id.as_json_array_value()?,
46
+ entity_pk: conflict.identity.entity_pk.as_json_array_value()?,
47
47
  file_id: conflict.identity.file_id.clone(),
48
48
  target: conflict_side_from_diff_entry(&conflict.target),
49
49
  source: conflict_side_from_diff_entry(&conflict.source),
@@ -1,11 +1,10 @@
1
1
  mod analysis;
2
- mod apply;
2
+ mod branch;
3
3
  mod conflicts;
4
4
  mod stats;
5
- mod version;
6
5
 
7
- pub use version::{
8
- MergeChangeStats, MergeConflict, MergeConflictChangeKind, MergeConflictKind, MergeConflictSide,
9
- MergeVersionOptions, MergeVersionOutcome, MergeVersionPreview, MergeVersionPreviewOptions,
10
- MergeVersionReceipt,
6
+ pub use branch::{
7
+ MergeBranchOptions, MergeBranchOutcome, MergeBranchPreview, MergeBranchPreviewOptions,
8
+ MergeBranchReceipt, MergeChangeStats, MergeConflict, MergeConflictChangeKind,
9
+ MergeConflictKind, MergeConflictSide,
11
10
  };
@@ -1,5 +1,5 @@
1
1
  use crate::tracked_state::{
2
- TrackedStateDiff, TrackedStateDiffKind, TrackedStateMergePatch, TrackedStateMergePlan,
2
+ TrackedStateDiff, TrackedStateDiffKind, TrackedStateMergePick, TrackedStateMergePlan,
3
3
  };
4
4
  use crate::LixError;
5
5
 
@@ -24,8 +24,8 @@ pub(crate) fn stats_from_plan(
24
24
  source_diff: &TrackedStateDiff,
25
25
  ) -> Result<MergeStats, LixError> {
26
26
  let mut stats = MergeStats::default();
27
- for patch in &plan.patches {
28
- let identity = patch_identity(patch);
27
+ for pick in &plan.picks {
28
+ let identity = pick_identity(pick);
29
29
  let Some(entry) = source_diff
30
30
  .entries
31
31
  .iter()
@@ -34,9 +34,9 @@ pub(crate) fn stats_from_plan(
34
34
  return Err(LixError::new(
35
35
  "LIX_ERROR_UNKNOWN",
36
36
  format!(
37
- "merge analysis could not find source diff entry for adopted schema '{}' entity '{}'",
37
+ "merge analysis could not find source diff entry for source schema '{}' entity '{}'",
38
38
  identity.schema_key,
39
- identity.entity_id.as_json_array_text()?
39
+ identity.entity_pk.as_json_array_text()?
40
40
  ),
41
41
  ));
42
42
  };
@@ -56,10 +56,6 @@ impl MergeStats {
56
56
  }
57
57
  }
58
58
 
59
- fn patch_identity(
60
- patch: &TrackedStateMergePatch,
61
- ) -> &crate::tracked_state::TrackedStateDiffIdentity {
62
- match patch {
63
- TrackedStateMergePatch::Adopt { identity, .. } => identity,
64
- }
59
+ fn pick_identity(pick: &TrackedStateMergePick) -> &crate::tracked_state::TrackedStateDiffIdentity {
60
+ &pick.identity
65
61
  }
@@ -2,26 +2,29 @@
2
2
  //!
3
3
  //! Transaction invariant: a session has one execution lease. Parent-handle
4
4
  //! calls use it for implicit single-statement execution; explicit transactions
5
- //! hold it until commit or rollback. Session APIs must not open `Transaction`
6
- //! directly or use session-level read helpers inside write flows.
5
+ //! hold it until commit or rollback. Session feature submodules should enter
6
+ //! write flows through the centralized session helpers rather than opening
7
+ //! `Transaction` directly or using session-level read helpers inside writes.
8
+ //!
9
+ //! MVP boundary: session close can cancel queued or pre-boundary writes until
10
+ //! the durable commit point-of-no-return. After that point, close waits for
11
+ //! commit completion. Durability itself is the backend's responsibility.
7
12
 
8
13
  mod context;
9
- mod create_version;
14
+ mod create_branch;
10
15
  mod execute;
11
16
  mod merge;
12
- #[cfg(feature = "storage-benches")]
13
- pub mod optimization9_sql2_bench;
14
- mod switch_version;
17
+ mod switch_branch;
15
18
  mod transaction;
16
19
 
17
20
  pub use context::SessionContext;
18
- pub(crate) use context::{SessionMode, WORKSPACE_VERSION_KEY};
19
- pub use create_version::{CreateVersionOptions, CreateVersionReceipt};
21
+ pub(crate) use context::{SessionMode, WORKSPACE_BRANCH_KEY};
22
+ pub use create_branch::{CreateBranchOptions, CreateBranchReceipt};
20
23
  pub use execute::{ExecuteResult, Row, RowRef, TryFromValue};
21
24
  pub use merge::{
22
- MergeChangeStats, MergeConflict, MergeConflictChangeKind, MergeConflictKind, MergeConflictSide,
23
- MergeVersionOptions, MergeVersionOutcome, MergeVersionPreview, MergeVersionPreviewOptions,
24
- MergeVersionReceipt,
25
+ MergeBranchOptions, MergeBranchOutcome, MergeBranchPreview, MergeBranchPreviewOptions,
26
+ MergeBranchReceipt, MergeChangeStats, MergeConflict, MergeConflictChangeKind,
27
+ MergeConflictKind, MergeConflictSide,
25
28
  };
26
- pub use switch_version::{SwitchVersionOptions, SwitchVersionReceipt};
29
+ pub use switch_branch::{SwitchBranchOptions, SwitchBranchReceipt};
27
30
  pub use transaction::SessionTransaction;
@@ -0,0 +1,113 @@
1
+ use std::sync::Arc;
2
+
3
+ use serde_json::json;
4
+
5
+ use crate::branch::{BranchLifecycle, BranchOperation, BranchReferenceRole};
6
+ use crate::storage::StorageBackend;
7
+ use crate::transaction::types::{TransactionJson, TransactionWriteRow};
8
+ use crate::LixError;
9
+ use crate::GLOBAL_BRANCH_ID;
10
+
11
+ use super::context::{SessionContext, SessionMode, WORKSPACE_BRANCH_KEY};
12
+
13
+ const KEY_VALUE_SCHEMA_KEY: &str = "lix_key_value";
14
+
15
+ /// Options for switching a session to another branch.
16
+ #[derive(Debug, Clone, PartialEq, Eq)]
17
+ pub struct SwitchBranchOptions {
18
+ pub branch_id: String,
19
+ }
20
+
21
+ /// Receipt returned after switching to another branch.
22
+ #[derive(Debug, Clone, PartialEq, Eq)]
23
+ pub struct SwitchBranchReceipt {
24
+ pub branch_id: String,
25
+ }
26
+
27
+ impl<B> SessionContext<B>
28
+ where
29
+ B: StorageBackend + Clone + Send + Sync + 'static,
30
+ for<'backend> B::Read<'backend>: Clone + Send + Sync + 'static,
31
+ for<'backend> B::Write<'backend>: Send,
32
+ {
33
+ /// Switches the session's active branch selector.
34
+ ///
35
+ /// Pinned sessions switch in memory and return a new pinned session.
36
+ /// Workspace sessions update the shared workspace selector so other
37
+ /// workspace sessions observe the new active branch on their next use.
38
+ pub async fn switch_branch(
39
+ &self,
40
+ options: SwitchBranchOptions,
41
+ ) -> Result<(SessionContext<B>, SwitchBranchReceipt), LixError> {
42
+ let branch_id = options.branch_id;
43
+ let receipt_branch_id = branch_id.clone();
44
+ let current_mode = self.mode.clone();
45
+ let next_mode = self
46
+ .with_write_transaction(|transaction| {
47
+ Box::pin(async move {
48
+ {
49
+ let reader = transaction.branch_ref_reader();
50
+ BranchLifecycle::new(&reader)
51
+ .require_existing_commit_id(
52
+ &branch_id,
53
+ BranchOperation::SwitchBranch,
54
+ BranchReferenceRole::Target,
55
+ )
56
+ .await?
57
+ };
58
+
59
+ match current_mode {
60
+ SessionMode::Pinned { .. } => Ok(SessionMode::Pinned {
61
+ branch_id: branch_id.clone(),
62
+ }),
63
+ SessionMode::Workspace => {
64
+ transaction
65
+ .stage_rows(vec![workspace_branch_stage_row(&branch_id)?])
66
+ .await?;
67
+ Ok(SessionMode::Workspace)
68
+ }
69
+ }
70
+ })
71
+ })
72
+ .await?;
73
+
74
+ let session = SessionContext::new_with_transaction_manager(
75
+ next_mode,
76
+ self.storage.clone(),
77
+ Arc::clone(&self.live_state),
78
+ Arc::clone(&self.tracked_state),
79
+ Arc::clone(&self.binary_cas),
80
+ Arc::clone(&self.branch_ctx),
81
+ Arc::clone(&self.catalog_context),
82
+ self.write_lock.clone(),
83
+ self.transaction_manager(),
84
+ );
85
+ Ok((
86
+ session,
87
+ SwitchBranchReceipt {
88
+ branch_id: receipt_branch_id,
89
+ },
90
+ ))
91
+ }
92
+ }
93
+
94
+ fn workspace_branch_stage_row(branch_id: &str) -> Result<TransactionWriteRow, LixError> {
95
+ Ok(TransactionWriteRow {
96
+ entity_pk: Some(crate::entity_pk::EntityPk::single(WORKSPACE_BRANCH_KEY)),
97
+ schema_key: KEY_VALUE_SCHEMA_KEY.to_string(),
98
+ file_id: None,
99
+ snapshot: Some(TransactionJson::from_value_unchecked(json!({
100
+ "key": WORKSPACE_BRANCH_KEY,
101
+ "value": branch_id,
102
+ }))),
103
+ metadata: None,
104
+ origin: None,
105
+ created_at: None,
106
+ updated_at: None,
107
+ global: true,
108
+ change_id: None,
109
+ commit_id: None,
110
+ untracked: true,
111
+ branch_id: GLOBAL_BRANCH_ID.to_string(),
112
+ })
113
+ }