@lix-js/sdk 0.6.0-preview.3 → 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 (235) hide show
  1. package/README.md +1 -1
  2. package/SKILL.md +105 -65
  3. package/dist/engine-wasm/index.js +4 -4
  4. package/dist/engine-wasm/wasm/lix_engine.d.ts +30 -6
  5. package/dist/engine-wasm/wasm/lix_engine.js +187 -117
  6. package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
  7. package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +14 -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 +42 -28
  11. package/dist/open-lix.js +49 -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 +819 -124
  94. package/dist-engine-src/src/session/create_branch.rs +94 -0
  95. package/dist-engine-src/src/session/execute.rs +260 -57
  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 +19 -16
  102. package/dist-engine-src/src/session/switch_branch.rs +113 -0
  103. package/dist-engine-src/src/session/transaction.rs +557 -0
  104. package/dist-engine-src/src/sql2/bind/classify.rs +102 -0
  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} +98 -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 +4 -5
  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 +30 -24
  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 -109
  218. package/dist-engine-src/src/sql2/classify.rs +0 -182
  219. package/dist-engine-src/src/sql2/entity_provider.rs +0 -3211
  220. package/dist-engine-src/src/sql2/execute.rs +0 -3440
  221. package/dist-engine-src/src/sql2/public_bind/assignment.rs +0 -46
  222. package/dist-engine-src/src/sql2/public_bind/capability.rs +0 -41
  223. package/dist-engine-src/src/sql2/public_bind/dml.rs +0 -166
  224. package/dist-engine-src/src/sql2/public_bind/mod.rs +0 -25
  225. package/dist-engine-src/src/sql2/public_bind/table.rs +0 -168
  226. package/dist-engine-src/src/sql2/version_scope.rs +0 -394
  227. package/dist-engine-src/src/storage/types.rs +0 -501
  228. package/dist-engine-src/src/tracked_state/by_file_index.rs +0 -98
  229. package/dist-engine-src/src/tracked_state/materializer.rs +0 -488
  230. package/dist-engine-src/src/transaction/live_state_overlay.rs +0 -35
  231. package/dist-engine-src/src/version/lifecycle.rs +0 -221
  232. package/dist-engine-src/src/version/mod.rs +0 -13
  233. package/dist-engine-src/src/version/refs.rs +0 -330
  234. package/dist-engine-src/src/version/stage_rows.rs +0 -67
  235. package/dist-engine-src/src/version/types.rs +0 -21
@@ -1,9 +1,9 @@
1
- use std::collections::{BTreeMap, BTreeSet, HashMap};
1
+ use std::collections::{BTreeMap, HashMap};
2
2
  use std::sync::{Arc, Mutex};
3
3
 
4
4
  use crate::catalog::SchemaPlanId;
5
5
  use crate::domain::{Domain, DomainRowIdentity};
6
- use crate::entity_identity::EntityIdentity;
6
+ use crate::entity_pk::EntityPk;
7
7
  use crate::functions::{FunctionProvider, FunctionProviderHandle};
8
8
  #[cfg(test)]
9
9
  use crate::live_state::LiveStateRowRequest;
@@ -11,11 +11,12 @@ use crate::live_state::{LiveStateScanRequest, MaterializedLiveStateRow};
11
11
  #[cfg(test)]
12
12
  use crate::transaction::types::{stage_json_from_value, TransactionJson};
13
13
  use crate::transaction::types::{
14
- LogicalPrimaryKey, PreparedTransactionWrite, TransactionFileData, TransactionWriteMode,
15
- TransactionWriteOperation, TransactionWriteOrigin, TransactionWriteOutcome,
14
+ LogicalPrimaryKey, PreparedTransactionWrite, StagedCommitChangeRef, TransactionFileData,
15
+ TransactionWriteMode, TransactionWriteOperation, TransactionWriteOrigin,
16
+ TransactionWriteOutcome,
16
17
  };
17
- use crate::transaction::types::{PreparedAdoptedStateRow, PreparedStateRow, StagedCommitMembers};
18
- use crate::GLOBAL_VERSION_ID;
18
+ use crate::transaction::types::{PreparedStateRow, StagedCommitChangeRefs};
19
+ use crate::GLOBAL_BRANCH_ID;
19
20
  use crate::{LixError, NullableKeyFilter};
20
21
 
21
22
  /// Transaction-local write buffer after transaction-boundary preparation.
@@ -27,28 +28,25 @@ use crate::{LixError, NullableKeyFilter};
27
28
  pub(crate) struct TransactionWriteBuffer {
28
29
  functions: FunctionProviderHandle,
29
30
  rows: Mutex<Vec<Option<PreparedStateRow>>>,
30
- adopted_rows: Mutex<Vec<Option<PreparedAdoptedStateRow>>>,
31
31
  by_identity: Mutex<HashMap<PreparedStateRowIdentity, RowSlot>>,
32
32
  insert_identities: Mutex<BTreeMap<PreparedStateRowIdentity, Option<TransactionWriteOrigin>>>,
33
- commit_members_by_version: Mutex<BTreeMap<String, StagedCommitMembers>>,
34
- extra_commit_parents_by_version: Mutex<BTreeMap<String, Vec<String>>>,
33
+ commit_change_refs_by_branch: Mutex<BTreeMap<String, StagedCommitChangeRefs>>,
34
+ extra_commit_parents_by_branch: Mutex<BTreeMap<String, Vec<String>>>,
35
35
  file_data_writes: Mutex<Vec<TransactionFileData>>,
36
36
  }
37
37
 
38
38
  #[derive(Debug, Clone, Copy, PartialEq, Eq)]
39
39
  pub(crate) enum RowSlot {
40
40
  State(usize),
41
- Adopted(usize),
42
41
  }
43
42
 
44
43
  /// Drained prepared transaction writes ready for commit.
45
44
  pub(crate) struct PreparedWriteSet {
46
45
  pub(crate) state_rows: Vec<PreparedStateRow>,
47
- pub(crate) adopted_rows: Vec<PreparedAdoptedStateRow>,
48
46
  pub(crate) insert_identities:
49
47
  BTreeMap<PreparedStateRowIdentity, Option<TransactionWriteOrigin>>,
50
- pub(crate) commit_members_by_version: BTreeMap<String, StagedCommitMembers>,
51
- pub(crate) extra_commit_parents_by_version: BTreeMap<String, Vec<String>>,
48
+ pub(crate) commit_change_refs_by_branch: BTreeMap<String, StagedCommitChangeRefs>,
49
+ pub(crate) extra_commit_parents_by_branch: BTreeMap<String, Vec<String>>,
52
50
  pub(crate) file_data_writes: Vec<TransactionFileData>,
53
51
  }
54
52
 
@@ -75,35 +73,30 @@ pub(crate) struct PreparedWriteValidationIndex<'a> {
75
73
  #[derive(Clone, Copy)]
76
74
  pub(crate) enum PreparedValidationRow<'a> {
77
75
  State(&'a PreparedStateRow),
78
- Adopted(&'a PreparedAdoptedStateRow),
79
76
  }
80
77
 
81
78
  impl<'a> PreparedValidationRow<'a> {
82
- pub(crate) fn entity_id(&self) -> &EntityIdentity {
79
+ pub(crate) fn entity_pk(&self) -> &EntityPk {
83
80
  match self {
84
- Self::State(row) => &row.entity_id,
85
- Self::Adopted(row) => &row.entity_id,
81
+ Self::State(row) => &row.entity_pk,
86
82
  }
87
83
  }
88
84
 
89
85
  pub(crate) fn schema_plan_id(&self) -> SchemaPlanId {
90
86
  match self {
91
87
  Self::State(row) => row.schema_plan_id,
92
- Self::Adopted(row) => row.schema_plan_id,
93
88
  }
94
89
  }
95
90
 
96
91
  pub(crate) fn schema_key(&self) -> &str {
97
92
  match self {
98
93
  Self::State(row) => &row.schema_key,
99
- Self::Adopted(row) => &row.schema_key,
100
94
  }
101
95
  }
102
96
 
103
97
  pub(crate) fn file_id(&self) -> &Option<String> {
104
98
  match self {
105
99
  Self::State(row) => &row.file_id,
106
- Self::Adopted(row) => &row.file_id,
107
100
  }
108
101
  }
109
102
 
@@ -114,10 +107,6 @@ impl<'a> PreparedValidationRow<'a> {
114
107
  .snapshot
115
108
  .as_ref()
116
109
  .map(|snapshot| snapshot.normalized.as_ref()),
117
- Self::Adopted(row) => row
118
- .snapshot
119
- .as_ref()
120
- .map(|snapshot| snapshot.normalized.as_ref()),
121
110
  }
122
111
  }
123
112
 
@@ -127,10 +116,6 @@ impl<'a> PreparedValidationRow<'a> {
127
116
  .snapshot
128
117
  .as_ref()
129
118
  .map(|snapshot| snapshot.value.as_ref()),
130
- Self::Adopted(row) => row
131
- .snapshot
132
- .as_ref()
133
- .map(|snapshot| snapshot.value.as_ref()),
134
119
  }
135
120
  }
136
121
 
@@ -140,30 +125,30 @@ impl<'a> PreparedValidationRow<'a> {
140
125
  .metadata
141
126
  .as_ref()
142
127
  .map(|metadata| metadata.value.as_ref()),
143
- Self::Adopted(row) => row
144
- .metadata
145
- .as_ref()
146
- .map(|metadata| metadata.value.as_ref()),
128
+ }
129
+ }
130
+
131
+ pub(crate) fn is_tombstone(&self) -> bool {
132
+ match self {
133
+ Self::State(row) => row.snapshot.is_none(),
147
134
  }
148
135
  }
149
136
 
150
137
  pub(crate) fn untracked(&self) -> bool {
151
138
  match self {
152
139
  Self::State(row) => row.untracked,
153
- Self::Adopted(_) => false,
154
140
  }
155
141
  }
156
142
 
157
- pub(crate) fn version_id(&self) -> &str {
143
+ pub(crate) fn branch_id(&self) -> &str {
158
144
  match self {
159
- Self::State(row) => &row.version_id,
160
- Self::Adopted(row) => &row.version_id,
145
+ Self::State(row) => &row.branch_id,
161
146
  }
162
147
  }
163
148
 
164
149
  pub(crate) fn domain(&self) -> Domain {
165
150
  Domain::exact_file(
166
- self.version_id().to_string(),
151
+ self.branch_id().to_string(),
167
152
  self.untracked(),
168
153
  self.file_id().clone(),
169
154
  )
@@ -173,7 +158,7 @@ impl<'a> PreparedValidationRow<'a> {
173
158
  DomainRowIdentity::in_domain(
174
159
  self.domain(),
175
160
  self.schema_key().to_string(),
176
- self.entity_id().clone(),
161
+ self.entity_pk().clone(),
177
162
  )
178
163
  }
179
164
  }
@@ -193,7 +178,7 @@ impl<'a> PreparedWriteValidationIndex<'a> {
193
178
  .flat_map(|(target_scope, rows)| {
194
179
  rows.iter().copied().filter(move |row| {
195
180
  schema_scope.validation_scope_contains_constraint_domain(target_scope)
196
- || (row.snapshot_json().is_none()
181
+ || (row.is_tombstone()
197
182
  && target_scope.tombstone_domain_affects_validation_scope(schema_scope))
198
183
  })
199
184
  })
@@ -235,10 +220,7 @@ impl<'a> PreparedWriteValidationSet<'a> {
235
220
  impl PreparedWriteSet {
236
221
  #[cfg(test)]
237
222
  pub(crate) fn validation_rows(&self) -> impl Iterator<Item = PreparedValidationRow<'_>> + '_ {
238
- self.state_rows
239
- .iter()
240
- .map(PreparedValidationRow::State)
241
- .chain(self.adopted_rows.iter().map(PreparedValidationRow::Adopted))
223
+ self.state_rows.iter().map(PreparedValidationRow::State)
242
224
  }
243
225
 
244
226
  pub(crate) fn validation_index(&self) -> PreparedWriteValidationIndex<'_> {
@@ -250,14 +232,6 @@ impl PreparedWriteSet {
250
232
  .or_default()
251
233
  .push(row);
252
234
  }
253
- for row in &self.adopted_rows {
254
- let row = PreparedValidationRow::Adopted(row);
255
- rows_by_schema_scope
256
- .entry(row.domain().schema_catalog_domain())
257
- .or_default()
258
- .push(row);
259
- }
260
-
261
235
  let mut insert_identities_by_schema_scope = BTreeMap::<
262
236
  Domain,
263
237
  Vec<(&PreparedStateRowIdentity, Option<&TransactionWriteOrigin>)>,
@@ -296,11 +270,10 @@ impl TransactionWriteBuffer {
296
270
  Self {
297
271
  functions,
298
272
  rows: Mutex::new(Vec::new()),
299
- adopted_rows: Mutex::new(Vec::new()),
300
273
  by_identity: Mutex::new(HashMap::new()),
301
274
  insert_identities: Mutex::new(BTreeMap::new()),
302
- commit_members_by_version: Mutex::new(BTreeMap::new()),
303
- extra_commit_parents_by_version: Mutex::new(BTreeMap::new()),
275
+ commit_change_refs_by_branch: Mutex::new(BTreeMap::new()),
276
+ extra_commit_parents_by_branch: Mutex::new(BTreeMap::new()),
304
277
  file_data_writes: Mutex::new(Vec::new()),
305
278
  }
306
279
  }
@@ -313,12 +286,6 @@ impl TransactionWriteBuffer {
313
286
  "failed to acquire transaction staged writes lock",
314
287
  )
315
288
  })?;
316
- let mut adopted_rows_guard = self.adopted_rows.lock().map_err(|_| {
317
- LixError::new(
318
- "LIX_ERROR_UNKNOWN",
319
- "failed to acquire transaction staged adopted writes lock",
320
- )
321
- })?;
322
289
  let mut by_identity_guard = self.by_identity.lock().map_err(|_| {
323
290
  LixError::new(
324
291
  "LIX_ERROR_UNKNOWN",
@@ -337,112 +304,87 @@ impl TransactionWriteBuffer {
337
304
  "failed to acquire transaction staged insert identity lock",
338
305
  )
339
306
  })?;
340
- let mut commit_members_guard = self.commit_members_by_version.lock().map_err(|_| {
341
- LixError::new(
342
- "LIX_ERROR_UNKNOWN",
343
- "failed to acquire transaction staged commit membership lock",
344
- )
345
- })?;
346
- let mut extra_parents_guard =
347
- self.extra_commit_parents_by_version.lock().map_err(|_| {
307
+ let mut commit_change_refs_guard =
308
+ self.commit_change_refs_by_branch.lock().map_err(|_| {
348
309
  LixError::new(
349
310
  "LIX_ERROR_UNKNOWN",
350
- "failed to acquire transaction staged extra commit parents lock",
311
+ "failed to acquire transaction staged commit change refs lock",
351
312
  )
352
313
  })?;
314
+ let mut extra_parents_guard = self.extra_commit_parents_by_branch.lock().map_err(|_| {
315
+ LixError::new(
316
+ "LIX_ERROR_UNKNOWN",
317
+ "failed to acquire transaction staged extra commit parents lock",
318
+ )
319
+ })?;
353
320
  let result = Ok(PreparedWriteSet {
354
321
  state_rows: std::mem::take(&mut *rows_guard)
355
322
  .into_iter()
356
323
  .flatten()
357
324
  .collect(),
358
- adopted_rows: std::mem::take(&mut *adopted_rows_guard)
359
- .into_iter()
360
- .flatten()
361
- .collect(),
362
325
  insert_identities: std::mem::take(&mut *insert_identities_guard),
363
- commit_members_by_version: std::mem::take(&mut *commit_members_guard),
364
- extra_commit_parents_by_version: std::mem::take(&mut *extra_parents_guard),
326
+ commit_change_refs_by_branch: std::mem::take(&mut *commit_change_refs_guard),
327
+ extra_commit_parents_by_branch: std::mem::take(&mut *extra_parents_guard),
365
328
  file_data_writes: std::mem::take(&mut *file_data_guard),
366
329
  });
367
330
  by_identity_guard.clear();
368
331
  result
369
332
  }
370
333
 
371
- /// Records an additional parent for the commit generated for `version_id`.
334
+ /// Records an additional parent for the commit generated for `branch_id`.
372
335
  ///
373
- /// Normal writes parent the new commit to the version's previous head.
374
- /// Merges add the source version head as an extra parent so the commit graph
336
+ /// Normal writes parent the new commit to the branch's previous head.
337
+ /// Merges add the source branch head as an extra parent so the commit graph
375
338
  /// preserves branch ancestry while tracked-state roots still apply source
376
339
  /// rows onto the target root.
377
340
  pub(crate) fn add_commit_parent(
378
341
  &self,
379
- version_id: String,
342
+ branch_id: String,
380
343
  parent_commit_id: String,
381
344
  ) -> Result<(), LixError> {
382
- let mut guard = self.extra_commit_parents_by_version.lock().map_err(|_| {
345
+ let mut guard = self.extra_commit_parents_by_branch.lock().map_err(|_| {
383
346
  LixError::new(
384
347
  "LIX_ERROR_UNKNOWN",
385
348
  "failed to acquire transaction staged extra commit parents lock",
386
349
  )
387
350
  })?;
388
- let parents = guard.entry(version_id).or_default();
351
+ let parents = guard.entry(branch_id).or_default();
389
352
  if !parents.contains(&parent_commit_id) {
390
353
  parents.push(parent_commit_id);
391
354
  }
392
355
  Ok(())
393
356
  }
394
357
 
395
- pub(crate) fn staged_commit_id(&self, version_id: &str) -> Result<Option<String>, LixError> {
396
- let guard = self.commit_members_by_version.lock().map_err(|_| {
397
- LixError::new(
398
- "LIX_ERROR_UNKNOWN",
399
- "failed to acquire transaction staged commit membership lock",
400
- )
401
- })?;
402
- Ok(guard
403
- .get(version_id)
404
- .map(|members| members.commit_id.clone()))
405
- }
406
-
407
- /// Stages a commit for `version_id` even if no tracked state rows changed.
408
- ///
409
- /// Merge uses this to record graph ancestry for convergent merges where the
410
- /// target already has the same final state as the source, but the source
411
- /// head is not reachable from the target head.
412
- pub(crate) fn stage_empty_commit(&self, version_id: String) -> Result<String, LixError> {
358
+ pub(crate) fn stage_selected_commit_change_refs(
359
+ &self,
360
+ branch_id: String,
361
+ selected_change_refs: impl IntoIterator<Item = StagedCommitChangeRef>,
362
+ ) -> Result<String, LixError> {
413
363
  let mut functions = self.functions.clone();
414
- let mut guard = self.commit_members_by_version.lock().map_err(|_| {
364
+ let mut guard = self.commit_change_refs_by_branch.lock().map_err(|_| {
415
365
  LixError::new(
416
366
  "LIX_ERROR_UNKNOWN",
417
- "failed to acquire transaction staged commit membership lock",
367
+ "failed to acquire transaction staged commit change refs lock",
418
368
  )
419
369
  })?;
420
- let members = guard.entry(version_id).or_insert_with(|| {
421
- StagedCommitMembers::new(
370
+ let change_refs = guard.entry(branch_id).or_insert_with(|| {
371
+ StagedCommitChangeRefs::new(
422
372
  functions.uuid_v7(),
423
373
  functions.uuid_v7(),
424
374
  functions.timestamp(),
425
375
  )
426
376
  });
427
- members.allow_empty();
428
- Ok(members.commit_id.clone())
377
+ change_refs.allow_empty();
378
+ for change_ref in selected_change_refs {
379
+ change_refs.add_selected_change_ref(change_ref);
380
+ }
381
+ Ok(change_refs.commit_id.clone())
429
382
  }
430
383
 
431
384
  /// Builds the transaction-local read overlay from currently staged writes.
432
385
  pub(crate) fn staging_overlay(self: &Arc<Self>) -> Result<PreparedStateRowOverlay, LixError> {
433
- let by_identity_guard = self.by_identity.lock().map_err(|_| {
434
- LixError::new(
435
- "LIX_ERROR_UNKNOWN",
436
- "failed to acquire transaction staged identity index lock",
437
- )
438
- })?;
439
- let slots = by_identity_guard
440
- .iter()
441
- .map(|(identity, slot)| (identity.clone(), *slot))
442
- .collect();
443
386
  Ok(PreparedStateRowOverlay {
444
387
  staged_writes: Arc::clone(self),
445
- slots,
446
388
  })
447
389
  }
448
390
 
@@ -458,16 +400,9 @@ impl TransactionWriteBuffer {
458
400
  let (mode, count) = match &write {
459
401
  PreparedTransactionWrite::Rows { mode, rows } => (Some(*mode), rows.len() as u64),
460
402
  PreparedTransactionWrite::RowsWithFileData { mode, count, .. } => (Some(*mode), *count),
461
- PreparedTransactionWrite::AdoptedChanges { rows } => (None, rows.len() as u64),
462
403
  };
463
404
  let mut functions = self.functions.clone();
464
- let (rows, adopted_rows, file_data_writes) = self.state_rows_from_stage_write(write)?;
465
- for row in &rows {
466
- validate_commit_membership_support(row)?;
467
- }
468
- for row in &adopted_rows {
469
- validate_adopted_commit_membership_support(row)?;
470
- }
405
+ let (rows, file_data_writes) = self.state_rows_from_stage_write(write);
471
406
  reject_duplicate_present_rows_in_batch(&rows)?;
472
407
  let mut guard = self.rows.lock().map_err(|_| {
473
408
  LixError::new(
@@ -475,24 +410,19 @@ impl TransactionWriteBuffer {
475
410
  "failed to acquire transaction staged writes lock",
476
411
  )
477
412
  })?;
478
- let mut adopted_guard = self.adopted_rows.lock().map_err(|_| {
479
- LixError::new(
480
- "LIX_ERROR_UNKNOWN",
481
- "failed to acquire transaction staged adopted writes lock",
482
- )
483
- })?;
484
413
  let mut by_identity_guard = self.by_identity.lock().map_err(|_| {
485
414
  LixError::new(
486
415
  "LIX_ERROR_UNKNOWN",
487
416
  "failed to acquire transaction staged identity index lock",
488
417
  )
489
418
  })?;
490
- let mut commit_members_guard = self.commit_members_by_version.lock().map_err(|_| {
491
- LixError::new(
492
- "LIX_ERROR_UNKNOWN",
493
- "failed to acquire transaction staged commit membership lock",
494
- )
495
- })?;
419
+ let mut commit_change_refs_guard =
420
+ self.commit_change_refs_by_branch.lock().map_err(|_| {
421
+ LixError::new(
422
+ "LIX_ERROR_UNKNOWN",
423
+ "failed to acquire transaction staged commit change refs lock",
424
+ )
425
+ })?;
496
426
  let mut insert_identities_guard = self.insert_identities.lock().map_err(|_| {
497
427
  LixError::new(
498
428
  "LIX_ERROR_UNKNOWN",
@@ -500,22 +430,25 @@ impl TransactionWriteBuffer {
500
430
  )
501
431
  })?;
502
432
  for mut row in rows {
433
+ if row.global && row.branch_id != GLOBAL_BRANCH_ID {
434
+ return Err(LixError::new(
435
+ LixError::CODE_INVALID_PARAM,
436
+ "global staged rows must use the global branch id",
437
+ ));
438
+ }
503
439
  let identity = PreparedStateRowIdentity::from(&row);
504
440
  if mode == Some(TransactionWriteMode::Insert)
505
441
  && by_identity_guard.contains_key(&identity)
506
442
  {
507
443
  return Err(duplicate_insert_identity_error(&row));
508
444
  }
509
- if matches!(by_identity_guard.get(&identity), Some(RowSlot::Adopted(_))) {
510
- return Err(conflicting_adopted_identity_error(&row));
511
- }
512
445
  let existing_slot = by_identity_guard.remove(&identity);
513
446
  if let Some(RowSlot::State(index)) = existing_slot {
514
447
  if let Some(previous) = guard.get_mut(index).and_then(Option::take) {
515
- remove_row_from_commit_members(&mut commit_members_guard, &previous);
448
+ remove_row_from_commit_change_refs(&mut commit_change_refs_guard, &previous);
516
449
  }
517
450
  }
518
- add_row_to_commit_members(&mut commit_members_guard, &mut row, &mut functions);
451
+ add_row_to_commit_change_refs(&mut commit_change_refs_guard, &mut row, &mut functions);
519
452
  let identity = PreparedStateRowIdentity::from(&row);
520
453
  if mode == Some(TransactionWriteMode::Insert) {
521
454
  insert_identities_guard.insert(identity.clone(), row.origin.clone());
@@ -533,17 +466,6 @@ impl TransactionWriteBuffer {
533
466
  };
534
467
  by_identity_guard.insert(identity, slot);
535
468
  }
536
- for mut row in adopted_rows {
537
- let identity = PreparedStateRowIdentity::from(&row);
538
- if by_identity_guard.contains_key(&identity) {
539
- return Err(conflicting_adopted_projection_error(&row));
540
- }
541
- add_adopted_row_to_commit_members(&mut commit_members_guard, &mut row, &mut functions);
542
- let identity = PreparedStateRowIdentity::from(&row);
543
- let index = adopted_guard.len();
544
- adopted_guard.push(Some(row));
545
- by_identity_guard.insert(identity, RowSlot::Adopted(index));
546
- }
547
469
  if !file_data_writes.is_empty() {
548
470
  self.file_data_writes
549
471
  .lock()
@@ -561,16 +483,8 @@ impl TransactionWriteBuffer {
561
483
  fn state_rows_from_stage_write(
562
484
  &self,
563
485
  write: PreparedTransactionWrite,
564
- ) -> Result<
565
- (
566
- Vec<PreparedStateRow>,
567
- Vec<PreparedAdoptedStateRow>,
568
- Vec<TransactionFileData>,
569
- ),
570
- LixError,
571
- > {
486
+ ) -> (Vec<PreparedStateRow>, Vec<TransactionFileData>) {
572
487
  let mut state_rows = Vec::new();
573
- let mut adopted_rows = Vec::new();
574
488
  let mut file_data_writes = Vec::new();
575
489
  match write {
576
490
  PreparedTransactionWrite::Rows { rows, .. } => {
@@ -582,23 +496,19 @@ impl TransactionWriteBuffer {
582
496
  state_rows.extend(rows);
583
497
  file_data_writes.extend(file_data);
584
498
  }
585
- PreparedTransactionWrite::AdoptedChanges { rows } => {
586
- adopted_rows.extend(rows);
587
- }
588
499
  }
589
- Ok((state_rows, adopted_rows, file_data_writes))
500
+ (state_rows, file_data_writes)
590
501
  }
591
502
  }
592
503
 
593
504
  /// Read overlay derived from staged transaction writes.
505
+ #[derive(Clone)]
594
506
  pub(crate) struct PreparedStateRowOverlay {
595
507
  staged_writes: Arc<TransactionWriteBuffer>,
596
- slots: BTreeMap<PreparedStateRowIdentity, RowSlot>,
597
508
  }
598
509
 
599
510
  pub(crate) struct StagedScanParts {
600
511
  pub(crate) rows: Vec<MaterializedLiveStateRow>,
601
- pub(crate) hidden_identities: BTreeSet<PreparedStateRowIdentity>,
602
512
  }
603
513
 
604
514
  impl PreparedStateRowOverlay {
@@ -608,7 +518,17 @@ impl PreparedStateRowOverlay {
608
518
  &self,
609
519
  request: &LiveStateScanRequest,
610
520
  ) -> Result<Vec<MaterializedLiveStateRow>, LixError> {
611
- Ok(self.scan_parts(request)?.rows)
521
+ Ok(crate::live_state::resolve_visible_rows(
522
+ self.scan_parts(request)?.rows,
523
+ Vec::new(),
524
+ &crate::live_state::VisibilityRequest {
525
+ branch_scope: crate::live_state::VisibilityBranchScope::BranchIds {
526
+ branch_ids: request.filter.branch_ids.clone(),
527
+ },
528
+ include_tombstones: request.filter.include_tombstones,
529
+ limit: None,
530
+ },
531
+ ))
612
532
  }
613
533
 
614
534
  /// Returns staged rows and base-row identities hidden by staged rows in one pass.
@@ -619,22 +539,28 @@ impl PreparedStateRowOverlay {
619
539
  &self,
620
540
  request: &LiveStateScanRequest,
621
541
  ) -> Result<StagedScanParts, LixError> {
542
+ if matches!(
543
+ request.filter.rows,
544
+ crate::live_state::LiveStateRowFilter::None
545
+ ) {
546
+ return Ok(StagedScanParts { rows: Vec::new() });
547
+ }
548
+
622
549
  let rows_guard = self.staged_writes.rows.lock().map_err(|_| {
623
550
  LixError::new(
624
551
  "LIX_ERROR_UNKNOWN",
625
552
  "failed to acquire transaction staged writes lock",
626
553
  )
627
554
  })?;
628
- let adopted_guard = self.staged_writes.adopted_rows.lock().map_err(|_| {
555
+ let by_identity_guard = self.staged_writes.by_identity.lock().map_err(|_| {
629
556
  LixError::new(
630
557
  "LIX_ERROR_UNKNOWN",
631
- "failed to acquire transaction staged adopted writes lock",
558
+ "failed to acquire transaction staged identity index lock",
632
559
  )
633
560
  })?;
634
561
 
635
562
  let mut rows = Vec::new();
636
- let mut hidden_identities = BTreeSet::new();
637
- for (identity, slot) in &self.slots {
563
+ for slot in by_identity_guard.values() {
638
564
  match *slot {
639
565
  RowSlot::State(index) => {
640
566
  let Some(row) = rows_guard.get(index).and_then(Option::as_ref) else {
@@ -643,29 +569,11 @@ impl PreparedStateRowOverlay {
643
569
  if !staged_row_identity_matches_scan(row, request) {
644
570
  continue;
645
571
  }
646
- hidden_identities.insert(identity.clone());
647
- if row.snapshot.is_some() || request.filter.include_tombstones {
648
- rows.push(MaterializedLiveStateRow::from(row));
649
- }
650
- }
651
- RowSlot::Adopted(index) => {
652
- let Some(row) = adopted_guard.get(index).and_then(Option::as_ref) else {
653
- continue;
654
- };
655
- if !adopted_row_identity_matches_scan(row, request) {
656
- continue;
657
- }
658
- hidden_identities.insert(identity.clone());
659
- if row.snapshot.is_some() || request.filter.include_tombstones {
660
- rows.push(MaterializedLiveStateRow::from(row));
661
- }
572
+ rows.push(MaterializedLiveStateRow::from(row));
662
573
  }
663
574
  }
664
575
  }
665
- Ok(StagedScanParts {
666
- rows,
667
- hidden_identities,
668
- })
576
+ Ok(StagedScanParts { rows })
669
577
  }
670
578
 
671
579
  /// Returns a staged exact-row answer, if this transaction has one.
@@ -688,44 +596,26 @@ impl PreparedStateRowOverlay {
688
596
  StagedExactRow::Row(MaterializedLiveStateRow::from(&row))
689
597
  });
690
598
  }
691
- self.load_adopted_slot(&identity).map(|row| {
692
- if row.snapshot.is_none() {
693
- StagedExactRow::Tombstone
694
- } else {
695
- StagedExactRow::Row(MaterializedLiveStateRow::from(&row))
696
- }
697
- })
599
+ None
698
600
  }
699
601
 
700
602
  #[cfg(test)]
701
603
  fn load_state_slot(&self, identity: &PreparedStateRowIdentity) -> Option<PreparedStateRow> {
702
- let Some(RowSlot::State(index)) = self.slots.get(identity).copied() else {
604
+ let rows_guard = self.staged_writes.rows.lock().ok()?;
605
+ let by_identity_guard = self.staged_writes.by_identity.lock().ok()?;
606
+ let Some(RowSlot::State(index)) = by_identity_guard.get(identity).copied() else {
703
607
  return None;
704
608
  };
705
- self.staged_writes
706
- .rows
707
- .lock()
708
- .ok()?
709
- .get(index)?
710
- .as_ref()
711
- .cloned()
609
+ rows_guard.get(index)?.as_ref().cloned()
712
610
  }
611
+ }
713
612
 
714
- #[cfg(test)]
715
- fn load_adopted_slot(
613
+ impl crate::live_state::StagedLiveStateRows for PreparedStateRowOverlay {
614
+ fn staged_rows(
716
615
  &self,
717
- identity: &PreparedStateRowIdentity,
718
- ) -> Option<PreparedAdoptedStateRow> {
719
- let Some(RowSlot::Adopted(index)) = self.slots.get(identity).copied() else {
720
- return None;
721
- };
722
- self.staged_writes
723
- .adopted_rows
724
- .lock()
725
- .ok()?
726
- .get(index)?
727
- .as_ref()
728
- .cloned()
616
+ request: &LiveStateScanRequest,
617
+ ) -> Result<Vec<MaterializedLiveStateRow>, LixError> {
618
+ Ok(self.scan_parts(request)?.rows)
729
619
  }
730
620
  }
731
621
 
@@ -739,9 +629,9 @@ pub(crate) enum StagedExactRow {
739
629
  pub(crate) struct PreparedStateRowIdentity {
740
630
  untracked: bool,
741
631
  schema_key: String,
742
- entity_id: crate::entity_identity::EntityIdentity,
632
+ entity_pk: crate::entity_pk::EntityPk,
743
633
  file_id: Option<String>,
744
- version_id: String,
634
+ branch_id: String,
745
635
  }
746
636
 
747
637
  impl PreparedStateRowIdentity {
@@ -749,9 +639,9 @@ impl PreparedStateRowIdentity {
749
639
  Self {
750
640
  untracked: row.untracked,
751
641
  schema_key: row.schema_key.clone(),
752
- entity_id: row.entity_id.clone(),
642
+ entity_pk: row.entity_pk.clone(),
753
643
  file_id: row.file_id.clone(),
754
- version_id: row.version_id.clone(),
644
+ branch_id: row.branch_id.clone(),
755
645
  }
756
646
  }
757
647
 
@@ -766,9 +656,9 @@ impl PreparedStateRowIdentity {
766
656
  Some(Self {
767
657
  untracked,
768
658
  schema_key: request.schema_key.clone(),
769
- entity_id: request.entity_id.clone(),
659
+ entity_pk: request.entity_pk.clone(),
770
660
  file_id,
771
- version_id: request.version_id.clone(),
661
+ branch_id: request.branch_id.clone(),
772
662
  })
773
663
  }
774
664
 
@@ -776,16 +666,12 @@ impl PreparedStateRowIdentity {
776
666
  &self.schema_key
777
667
  }
778
668
 
779
- pub(crate) fn entity_id(&self) -> &crate::entity_identity::EntityIdentity {
780
- &self.entity_id
669
+ pub(crate) fn entity_pk(&self) -> &crate::entity_pk::EntityPk {
670
+ &self.entity_pk
781
671
  }
782
672
 
783
673
  pub(crate) fn domain(&self) -> Domain {
784
- Domain::exact_file(
785
- self.version_id.clone(),
786
- self.untracked,
787
- self.file_id.clone(),
788
- )
674
+ Domain::exact_file(self.branch_id.clone(), self.untracked, self.file_id.clone())
789
675
  }
790
676
  }
791
677
 
@@ -795,52 +681,18 @@ impl From<&PreparedStateRow> for PreparedStateRowIdentity {
795
681
  }
796
682
  }
797
683
 
798
- impl From<&PreparedAdoptedStateRow> for PreparedStateRowIdentity {
799
- fn from(row: &PreparedAdoptedStateRow) -> Self {
800
- Self {
801
- untracked: false,
802
- schema_key: row.schema_key.clone(),
803
- entity_id: row.entity_id.clone(),
804
- file_id: row.file_id.clone(),
805
- version_id: row.version_id.clone(),
806
- }
807
- }
808
- }
809
-
810
684
  impl From<&MaterializedLiveStateRow> for PreparedStateRowIdentity {
811
685
  fn from(row: &MaterializedLiveStateRow) -> Self {
812
686
  Self {
813
687
  untracked: row.untracked,
814
688
  schema_key: row.schema_key.clone(),
815
- entity_id: row.entity_id.clone(),
689
+ entity_pk: row.entity_pk.clone(),
816
690
  file_id: row.file_id.clone(),
817
- version_id: row.version_id.clone(),
691
+ branch_id: row.branch_id.clone(),
818
692
  }
819
693
  }
820
694
  }
821
695
 
822
- fn validate_commit_membership_support(row: &PreparedStateRow) -> Result<(), LixError> {
823
- if row.global && row.version_id != GLOBAL_VERSION_ID {
824
- return Err(LixError::new(
825
- "LIX_ERROR_UNKNOWN",
826
- "engine global staged rows must use the global version id",
827
- ));
828
- }
829
- Ok(())
830
- }
831
-
832
- fn validate_adopted_commit_membership_support(
833
- row: &PreparedAdoptedStateRow,
834
- ) -> Result<(), LixError> {
835
- if row.global && row.version_id != GLOBAL_VERSION_ID {
836
- return Err(LixError::new(
837
- "LIX_ERROR_UNKNOWN",
838
- "engine global adopted rows must use the global version id",
839
- ));
840
- }
841
- Ok(())
842
- }
843
-
844
696
  fn reject_duplicate_present_rows_in_batch(rows: &[PreparedStateRow]) -> Result<(), LixError> {
845
697
  let mut pending_present_rows = BTreeMap::<PreparedStateRowIdentity, &PreparedStateRow>::new();
846
698
  for row in rows {
@@ -863,13 +715,13 @@ fn duplicate_staged_present_row_error(
863
715
  let message = logical_primary_key_violation_message(row.origin.as_ref())
864
716
  .unwrap_or_else(|| {
865
717
  format!(
866
- "primary-key constraint violation on schema '{}': duplicate staged rows for entity_id '{}' in version '{}'",
718
+ "primary-key constraint violation on schema '{}': duplicate staged rows for entity_pk '{}' in branch '{}'",
867
719
  row.schema_key,
868
720
  previous
869
- .entity_id
721
+ .entity_pk
870
722
  .as_json_array_text()
871
- .unwrap_or_else(|_| "<invalid entity_id>".to_string()),
872
- row.version_id
723
+ .unwrap_or_else(|_| "<invalid entity_pk>".to_string()),
724
+ row.branch_id
873
725
  )
874
726
  });
875
727
  LixError::new(LixError::CODE_UNIQUE, message)
@@ -877,22 +729,22 @@ fn duplicate_staged_present_row_error(
877
729
 
878
730
  pub(crate) fn duplicate_insert_identity_message(
879
731
  schema_key: &str,
880
- entity_id: &crate::entity_identity::EntityIdentity,
881
- version_id: Option<&str>,
732
+ entity_pk: &crate::entity_pk::EntityPk,
733
+ branch_id: Option<&str>,
882
734
  origin: Option<&TransactionWriteOrigin>,
883
735
  ) -> String {
884
736
  if let Some(message) = logical_primary_key_violation_message(origin) {
885
737
  return message;
886
738
  }
887
- let entity_id = entity_id
739
+ let entity_pk = entity_pk
888
740
  .as_json_array_text()
889
- .unwrap_or_else(|_| "<invalid entity_id>".to_string());
890
- match version_id {
891
- Some(version_id) => format!(
892
- "primary-key constraint violation on schema '{schema_key}': INSERT would duplicate entity_id '{entity_id}' in version '{version_id}'"
741
+ .unwrap_or_else(|_| "<invalid entity_pk>".to_string());
742
+ match branch_id {
743
+ Some(branch_id) => format!(
744
+ "primary-key constraint violation on schema '{schema_key}': INSERT would duplicate entity_pk '{entity_pk}' in branch '{branch_id}'"
893
745
  ),
894
746
  None => format!(
895
- "primary-key constraint violation on schema '{schema_key}': INSERT would duplicate entity_id '{entity_id}'"
747
+ "primary-key constraint violation on schema '{schema_key}': INSERT would duplicate entity_pk '{entity_pk}'"
896
748
  ),
897
749
  }
898
750
  }
@@ -900,8 +752,8 @@ pub(crate) fn duplicate_insert_identity_message(
900
752
  fn duplicate_insert_identity_error(row: &PreparedStateRow) -> LixError {
901
753
  let message = duplicate_insert_identity_message(
902
754
  &row.schema_key,
903
- &row.entity_id,
904
- Some(&row.version_id),
755
+ &row.entity_pk,
756
+ Some(&row.branch_id),
905
757
  row.origin.as_ref(),
906
758
  );
907
759
  LixError::new(LixError::CODE_UNIQUE, message)
@@ -939,36 +791,8 @@ fn format_logical_primary_key(primary_key: &LogicalPrimaryKey) -> String {
939
791
  .join(", ")
940
792
  }
941
793
 
942
- fn conflicting_adopted_identity_error(row: &PreparedStateRow) -> LixError {
943
- LixError::new(
944
- LixError::CODE_UNIQUE,
945
- format!(
946
- "transaction cannot stage a new row and an adopted projection for schema '{}' entity_id '{}' in version '{}'",
947
- row.schema_key,
948
- row.entity_id
949
- .as_json_array_text()
950
- .unwrap_or_else(|_| "<invalid entity_id>".to_string()),
951
- row.version_id
952
- ),
953
- )
954
- }
955
-
956
- fn conflicting_adopted_projection_error(row: &PreparedAdoptedStateRow) -> LixError {
957
- LixError::new(
958
- LixError::CODE_UNIQUE,
959
- format!(
960
- "transaction cannot stage duplicate adopted projections for schema '{}' entity_id '{}' in version '{}'",
961
- row.schema_key,
962
- row.entity_id
963
- .as_json_array_text()
964
- .unwrap_or_else(|_| "<invalid entity_id>".to_string()),
965
- row.version_id
966
- ),
967
- )
968
- }
969
-
970
- fn add_row_to_commit_members(
971
- members_by_version: &mut BTreeMap<String, StagedCommitMembers>,
794
+ fn add_row_to_commit_change_refs(
795
+ change_refs_by_branch: &mut BTreeMap<String, StagedCommitChangeRefs>,
972
796
  row: &mut PreparedStateRow,
973
797
  functions: &mut dyn FunctionProvider,
974
798
  ) {
@@ -978,81 +802,39 @@ fn add_row_to_commit_members(
978
802
  let change_id = row
979
803
  .change_id
980
804
  .clone()
981
- .expect("tracked staged rows must carry change_id for commit membership");
982
- let members = members_by_version
983
- .entry(row.version_id.clone())
984
- .or_insert_with(|| {
985
- StagedCommitMembers::new(
986
- functions.uuid_v7(),
987
- functions.uuid_v7(),
988
- functions.timestamp(),
989
- )
990
- });
991
- row.commit_id = Some(members.commit_id.clone());
992
- members.add_change_id(change_id);
993
- }
994
-
995
- fn add_adopted_row_to_commit_members(
996
- members_by_version: &mut BTreeMap<String, StagedCommitMembers>,
997
- row: &mut PreparedAdoptedStateRow,
998
- functions: &mut dyn FunctionProvider,
999
- ) {
1000
- let members = members_by_version
1001
- .entry(row.version_id.clone())
805
+ .expect("tracked staged rows must carry change_id for commit change refs");
806
+ let change_refs = change_refs_by_branch
807
+ .entry(row.branch_id.clone())
1002
808
  .or_insert_with(|| {
1003
- StagedCommitMembers::new(
809
+ StagedCommitChangeRefs::new(
1004
810
  functions.uuid_v7(),
1005
811
  functions.uuid_v7(),
1006
812
  functions.timestamp(),
1007
813
  )
1008
814
  });
1009
- row.commit_id = members.commit_id.clone();
1010
- members.add_change_id(row.change_id.clone());
815
+ row.commit_id = Some(change_refs.commit_id.clone());
816
+ change_refs.add_change_id(change_id);
1011
817
  }
1012
818
 
1013
- fn remove_row_from_commit_members(
1014
- members_by_version: &mut BTreeMap<String, StagedCommitMembers>,
819
+ fn remove_row_from_commit_change_refs(
820
+ change_refs_by_branch: &mut BTreeMap<String, StagedCommitChangeRefs>,
1015
821
  row: &PreparedStateRow,
1016
822
  ) {
1017
823
  if row.untracked {
1018
824
  return;
1019
825
  }
1020
- let Some(members) = members_by_version.get_mut(&row.version_id) else {
826
+ let Some(change_refs) = change_refs_by_branch.get_mut(&row.branch_id) else {
1021
827
  return;
1022
828
  };
1023
829
  let Some(change_id) = row.change_id.as_deref() else {
1024
830
  return;
1025
831
  };
1026
- members.remove_change_id(change_id);
1027
- if members.is_empty() {
1028
- members_by_version.remove(&row.version_id);
832
+ change_refs.remove_change_id(change_id);
833
+ if change_refs.is_empty() {
834
+ change_refs_by_branch.remove(&row.branch_id);
1029
835
  }
1030
836
  }
1031
837
 
1032
- fn adopted_row_identity_matches_scan(
1033
- row: &PreparedAdoptedStateRow,
1034
- request: &LiveStateScanRequest,
1035
- ) -> bool {
1036
- if !request.filter.schema_keys.is_empty()
1037
- && !request.filter.schema_keys.contains(&row.schema_key)
1038
- {
1039
- return false;
1040
- }
1041
- if !request.filter.entity_ids.is_empty() && !request.filter.entity_ids.contains(&row.entity_id)
1042
- {
1043
- return false;
1044
- }
1045
- if !request.filter.version_ids.is_empty()
1046
- && !request.filter.version_ids.contains(&row.version_id)
1047
- {
1048
- return false;
1049
- }
1050
- if request.filter.untracked == Some(true) {
1051
- return false;
1052
- }
1053
- nullable_key_matches_filters(&row.file_id, &request.filter.file_ids)
1054
- }
1055
-
1056
838
  fn staged_row_identity_matches_scan(
1057
839
  row: &PreparedStateRow,
1058
840
  request: &LiveStateScanRequest,
@@ -1062,13 +844,11 @@ fn staged_row_identity_matches_scan(
1062
844
  {
1063
845
  return false;
1064
846
  }
1065
- if !request.filter.entity_ids.is_empty() && !request.filter.entity_ids.contains(&row.entity_id)
847
+ if !request.filter.entity_pks.is_empty() && !request.filter.entity_pks.contains(&row.entity_pk)
1066
848
  {
1067
849
  return false;
1068
850
  }
1069
- if !request.filter.version_ids.is_empty()
1070
- && !request.filter.version_ids.contains(&row.version_id)
1071
- {
851
+ if !staged_branch_matches_scan(&row.branch_id, request) {
1072
852
  return false;
1073
853
  }
1074
854
  if request
@@ -1091,6 +871,21 @@ fn nullable_key_matches_filters(
1091
871
  .any(|filter| nullable_key_matches_filter(value, filter))
1092
872
  }
1093
873
 
874
+ fn staged_branch_matches_scan(branch_id: &str, request: &LiveStateScanRequest) -> bool {
875
+ request.filter.branch_ids.is_empty()
876
+ || request
877
+ .filter
878
+ .branch_ids
879
+ .iter()
880
+ .any(|requested| requested == branch_id)
881
+ || (branch_id == GLOBAL_BRANCH_ID
882
+ && request
883
+ .filter
884
+ .branch_ids
885
+ .iter()
886
+ .any(|requested| requested != GLOBAL_BRANCH_ID))
887
+ }
888
+
1094
889
  fn nullable_key_matches_filter(value: &Option<String>, filter: &NullableKeyFilter<String>) -> bool {
1095
890
  match filter {
1096
891
  NullableKeyFilter::Any => true,
@@ -1128,8 +923,8 @@ mod tests {
1128
923
  let row = overlay
1129
924
  .load_exact(&LiveStateRowRequest {
1130
925
  schema_key: "lix_key_value".to_string(),
1131
- version_id: "global".to_string(),
1132
- entity_id: crate::entity_identity::EntityIdentity::single("sql2-duplicate-key"),
926
+ branch_id: "global".to_string(),
927
+ entity_pk: crate::entity_pk::EntityPk::single("sql2-duplicate-key"),
1133
928
  file_id: NullableKeyFilter::Null,
1134
929
  })
1135
930
  .expect("staged row should be visible");
@@ -1268,7 +1063,7 @@ mod tests {
1268
1063
 
1269
1064
  assert_eq!(drained.state_rows.len(), 2);
1270
1065
  assert!(drained.state_rows.iter().any(|row| {
1271
- row.entity_id == crate::entity_identity::EntityIdentity::single("sql2-key-a")
1066
+ row.entity_pk == crate::entity_pk::EntityPk::single("sql2-key-a")
1272
1067
  && row
1273
1068
  .snapshot
1274
1069
  .as_ref()
@@ -1276,7 +1071,7 @@ mod tests {
1276
1071
  == Some("{\"key\":\"sql2-key-a\",\"value\":\"second\"}")
1277
1072
  }));
1278
1073
  assert!(drained.state_rows.iter().any(|row| {
1279
- row.entity_id == crate::entity_identity::EntityIdentity::single("sql2-key-b")
1074
+ row.entity_pk == crate::entity_pk::EntityPk::single("sql2-key-b")
1280
1075
  && row
1281
1076
  .snapshot
1282
1077
  .as_ref()
@@ -1295,7 +1090,7 @@ mod tests {
1295
1090
  rows: vec![state_row("file-readme", "descriptor")],
1296
1091
  file_data: vec![TransactionFileData {
1297
1092
  file_id: "file-readme".to_string(),
1298
- version_id: "global".to_string(),
1093
+ branch_id: "global".to_string(),
1299
1094
  untracked: true,
1300
1095
  data: b"hello".to_vec(),
1301
1096
  }],
@@ -1323,12 +1118,12 @@ mod tests {
1323
1118
  .expect("tracked global row should stage");
1324
1119
 
1325
1120
  let drained = staged_writes.drain().expect("drain should succeed");
1326
- let members = drained
1327
- .commit_members_by_version
1121
+ let change_refs = drained
1122
+ .commit_change_refs_by_branch
1328
1123
  .get("global")
1329
- .expect("global commit members should exist");
1124
+ .expect("global commit change_refs should exist");
1330
1125
  assert_eq!(
1331
- members.change_ids.iter().cloned().collect::<Vec<_>>(),
1126
+ change_refs.change_ids.iter().cloned().collect::<Vec<_>>(),
1332
1127
  vec!["test-change-id".to_string()]
1333
1128
  );
1334
1129
  }
@@ -1345,7 +1140,7 @@ mod tests {
1345
1140
  .expect("untracked row should stage");
1346
1141
 
1347
1142
  let drained = staged_writes.drain().expect("drain should succeed");
1348
- assert!(drained.commit_members_by_version.is_empty());
1143
+ assert!(drained.commit_change_refs_by_branch.is_empty());
1349
1144
  }
1350
1145
 
1351
1146
  #[tokio::test]
@@ -1370,12 +1165,12 @@ mod tests {
1370
1165
  .expect("tracked overwrite should stage");
1371
1166
 
1372
1167
  let drained = staged_writes.drain().expect("drain should succeed");
1373
- let members = drained
1374
- .commit_members_by_version
1168
+ let change_refs = drained
1169
+ .commit_change_refs_by_branch
1375
1170
  .get("global")
1376
- .expect("global commit members should exist");
1171
+ .expect("global commit change_refs should exist");
1377
1172
  assert_eq!(
1378
- members.change_ids.iter().cloned().collect::<Vec<_>>(),
1173
+ change_refs.change_ids.iter().cloned().collect::<Vec<_>>(),
1379
1174
  vec!["change-second".to_string()]
1380
1175
  );
1381
1176
  }
@@ -1407,12 +1202,12 @@ mod tests {
1407
1202
  .state_rows
1408
1203
  .iter()
1409
1204
  .any(|row| { row.change_id.as_deref() == Some("change-untracked") && row.untracked }));
1410
- let members = drained
1411
- .commit_members_by_version
1205
+ let change_refs = drained
1206
+ .commit_change_refs_by_branch
1412
1207
  .get("global")
1413
1208
  .expect("tracked commit member should remain in tracked domain");
1414
1209
  assert_eq!(
1415
- members.change_ids.iter().cloned().collect::<Vec<_>>(),
1210
+ change_refs.change_ids.iter().cloned().collect::<Vec<_>>(),
1416
1211
  vec!["change-tracked".to_string()]
1417
1212
  );
1418
1213
  }
@@ -1455,41 +1250,41 @@ mod tests {
1455
1250
  let drained = staged_writes.drain().expect("drain should succeed");
1456
1251
  assert_eq!(drained.state_rows.len(), 2);
1457
1252
  assert!(drained.state_rows.iter().any(|row| {
1458
- row.entity_id == crate::entity_identity::EntityIdentity::single("shared-domain-key")
1253
+ row.entity_pk == crate::entity_pk::EntityPk::single("shared-domain-key")
1459
1254
  && !row.untracked
1460
1255
  }));
1461
1256
  assert!(drained.state_rows.iter().any(|row| {
1462
- row.entity_id == crate::entity_identity::EntityIdentity::single("shared-domain-key")
1257
+ row.entity_pk == crate::entity_pk::EntityPk::single("shared-domain-key")
1463
1258
  && row.untracked
1464
1259
  }));
1465
1260
  }
1466
1261
 
1467
1262
  #[tokio::test]
1468
- async fn staged_writes_track_active_version_members_separately() {
1263
+ async fn staged_writes_track_active_branch_members_separately() {
1469
1264
  let staged_writes = test_staged_writes();
1470
1265
 
1471
1266
  staged_writes
1472
1267
  .stage_write(PreparedTransactionWrite::Rows {
1473
1268
  mode: TransactionWriteMode::Replace,
1474
- rows: vec![state_row("active-version-key", "value")
1269
+ rows: vec![state_row("active-branch-key", "value")
1475
1270
  .with_tracked()
1476
- .with_version("version-a")],
1271
+ .with_branch("branch-a")],
1477
1272
  })
1478
- .expect("active-version tracked staging should accumulate members");
1273
+ .expect("active-branch tracked staging should accumulate change_refs");
1479
1274
 
1480
1275
  let drained = staged_writes.drain().expect("drain should succeed");
1481
- let members = drained
1482
- .commit_members_by_version
1483
- .get("version-a")
1484
- .expect("active-version commit members should exist");
1276
+ let change_refs = drained
1277
+ .commit_change_refs_by_branch
1278
+ .get("branch-a")
1279
+ .expect("active-branch commit change_refs should exist");
1485
1280
  assert_eq!(
1486
- members.change_ids.iter().cloned().collect::<Vec<_>>(),
1281
+ change_refs.change_ids.iter().cloned().collect::<Vec<_>>(),
1487
1282
  vec!["test-change-id".to_string()]
1488
1283
  );
1489
1284
  }
1490
1285
 
1491
1286
  #[tokio::test]
1492
- async fn staged_writes_reject_global_rows_with_non_global_version_id() {
1287
+ async fn staged_writes_reject_global_rows_with_non_global_branch_id() {
1493
1288
  let staged_writes = test_staged_writes();
1494
1289
 
1495
1290
  let error = staged_writes
@@ -1497,15 +1292,15 @@ mod tests {
1497
1292
  mode: TransactionWriteMode::Replace,
1498
1293
  rows: vec![{
1499
1294
  let mut row = state_row("invalid-global-key", "value");
1500
- row.version_id = "version-a".to_string();
1295
+ row.branch_id = "branch-a".to_string();
1501
1296
  row
1502
1297
  }],
1503
1298
  })
1504
- .expect_err("global row with non-global version should fail");
1299
+ .expect_err("global row with non-global branch should fail");
1505
1300
 
1506
1301
  assert!(error
1507
1302
  .message
1508
- .contains("global staged rows must use the global version id"));
1303
+ .contains("global staged rows must use the global branch id"));
1509
1304
  }
1510
1305
 
1511
1306
  #[tokio::test]
@@ -1523,7 +1318,7 @@ mod tests {
1523
1318
  mode: TransactionWriteMode::Replace,
1524
1319
  rows: vec![
1525
1320
  state_row("shared-entity", "base"),
1526
- state_row("shared-entity", "other-version").with_version("version-b"),
1321
+ state_row("shared-entity", "other-branch").with_branch("branch-b"),
1527
1322
  state_row("shared-entity", "other-schema").with_schema("other_schema"),
1528
1323
  state_row("shared-entity", "other-file").with_file_id("file-a"),
1529
1324
  state_row("shared-entity", "tracked").with_tracked(),
@@ -1537,9 +1332,7 @@ mod tests {
1537
1332
  let rows = overlay
1538
1333
  .scan(&LiveStateScanRequest {
1539
1334
  filter: LiveStateFilter {
1540
- entity_ids: vec![crate::entity_identity::EntityIdentity::single(
1541
- "shared-entity",
1542
- )],
1335
+ entity_pks: vec![crate::entity_pk::EntityPk::single("shared-entity")],
1543
1336
  include_tombstones: true,
1544
1337
  ..LiveStateFilter::default()
1545
1338
  },
@@ -1547,20 +1340,21 @@ mod tests {
1547
1340
  })
1548
1341
  .expect("overlay scan should succeed");
1549
1342
 
1550
- assert_eq!(rows.len(), 5);
1343
+ assert_eq!(rows.len(), 4);
1551
1344
  assert_eq!(
1552
1345
  rows.iter()
1553
- .filter(|row| row.entity_id
1554
- == crate::entity_identity::EntityIdentity::single("shared-entity")
1555
- && row.version_id == "global"
1556
- && row.schema_key == "lix_key_value"
1557
- && row.file_id.is_none())
1346
+ .filter(
1347
+ |row| row.entity_pk == crate::entity_pk::EntityPk::single("shared-entity")
1348
+ && row.branch_id == "global"
1349
+ && row.schema_key == "lix_key_value"
1350
+ && row.file_id.is_none()
1351
+ )
1558
1352
  .count(),
1559
- 2
1353
+ 1
1560
1354
  );
1561
1355
  assert!(rows.iter().any(|row| {
1562
1356
  row.snapshot_content.as_deref()
1563
- == Some("{\"key\":\"shared-entity\",\"value\":\"tracked\"}")
1357
+ == Some("{\"key\":\"shared-entity\",\"value\":\"base\"}")
1564
1358
  }));
1565
1359
  }
1566
1360
 
@@ -1576,13 +1370,13 @@ mod tests {
1576
1370
  .expect("staging rows should succeed");
1577
1371
 
1578
1372
  let drained = staged_writes.drain().expect("drain should succeed");
1579
- let members = drained
1580
- .commit_members_by_version
1373
+ let change_refs = drained
1374
+ .commit_change_refs_by_branch
1581
1375
  .get("global")
1582
- .expect("global commit members should exist");
1583
- assert_eq!(members.commit_id, "test-uuid-1");
1584
- assert_eq!(members.commit_change_id, "test-uuid-2");
1585
- assert_eq!(members.created_at, "test-timestamp-1");
1376
+ .expect("global commit change_refs should exist");
1377
+ assert_eq!(change_refs.commit_id, "test-uuid-1");
1378
+ assert_eq!(change_refs.commit_change_id, "test-uuid-2");
1379
+ assert_eq!(change_refs.created_at, "test-timestamp-1");
1586
1380
  }
1587
1381
 
1588
1382
  #[tokio::test]
@@ -1604,9 +1398,9 @@ mod tests {
1604
1398
  );
1605
1399
  assert_eq!(
1606
1400
  drained
1607
- .commit_members_by_version
1401
+ .commit_change_refs_by_branch
1608
1402
  .get("global")
1609
- .expect("global commit members should exist")
1403
+ .expect("global commit change_refs should exist")
1610
1404
  .commit_id,
1611
1405
  "test-uuid-1"
1612
1406
  );
@@ -1645,7 +1439,7 @@ mod tests {
1645
1439
  PreparedStateRow {
1646
1440
  schema_plan_id: SchemaPlanId::for_test(0),
1647
1441
  facts: crate::transaction::types::PreparedRowFacts::default(),
1648
- entity_id: crate::entity_identity::EntityIdentity::single(key),
1442
+ entity_pk: crate::entity_pk::EntityPk::single(key),
1649
1443
  schema_key: "lix_key_value".to_string(),
1650
1444
  file_id: None,
1651
1445
  snapshot: Some(snapshot),
@@ -1657,7 +1451,7 @@ mod tests {
1657
1451
  change_id: None,
1658
1452
  commit_id: None,
1659
1453
  untracked: true,
1660
- version_id: "global".to_string(),
1454
+ branch_id: "global".to_string(),
1661
1455
  }
1662
1456
  }
1663
1457
 
@@ -1670,8 +1464,8 @@ mod tests {
1670
1464
  fn exact_request_for_key(key: &str) -> LiveStateRowRequest {
1671
1465
  LiveStateRowRequest {
1672
1466
  schema_key: "lix_key_value".to_string(),
1673
- version_id: "global".to_string(),
1674
- entity_id: crate::entity_identity::EntityIdentity::single(key),
1467
+ branch_id: "global".to_string(),
1468
+ entity_pk: crate::entity_pk::EntityPk::single(key),
1675
1469
  file_id: NullableKeyFilter::Null,
1676
1470
  }
1677
1471
  }
@@ -1680,8 +1474,8 @@ mod tests {
1680
1474
  LiveStateScanRequest {
1681
1475
  filter: LiveStateFilter {
1682
1476
  schema_keys: vec!["lix_key_value".to_string()],
1683
- entity_ids: vec![crate::entity_identity::EntityIdentity::single(key)],
1684
- version_ids: vec!["global".to_string()],
1477
+ entity_pks: vec![crate::entity_pk::EntityPk::single(key)],
1478
+ branch_ids: vec!["global".to_string()],
1685
1479
  file_ids: vec![NullableKeyFilter::Null],
1686
1480
  include_tombstones,
1687
1481
  ..LiveStateFilter::default()
@@ -1694,7 +1488,7 @@ mod tests {
1694
1488
  fn with_schema(self, schema_key: &str) -> Self;
1695
1489
  fn with_file_id(self, file_id: &str) -> Self;
1696
1490
  fn with_tracked(self) -> Self;
1697
- fn with_version(self, version_id: &str) -> Self;
1491
+ fn with_branch(self, branch_id: &str) -> Self;
1698
1492
  fn with_change_id(self, change_id: &str) -> Self;
1699
1493
  }
1700
1494
 
@@ -1717,9 +1511,9 @@ mod tests {
1717
1511
  self
1718
1512
  }
1719
1513
 
1720
- fn with_version(mut self, version_id: &str) -> Self {
1721
- self.version_id = version_id.to_string();
1722
- self.global = version_id == GLOBAL_VERSION_ID;
1514
+ fn with_branch(mut self, branch_id: &str) -> Self {
1515
+ self.branch_id = branch_id.to_string();
1516
+ self.global = branch_id == GLOBAL_BRANCH_ID;
1723
1517
  self
1724
1518
  }
1725
1519