@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
@@ -10,7 +10,7 @@ use datafusion::arrow::compute::{and, filter_record_batch};
10
10
  use datafusion::arrow::datatypes::{DataType, Field, Schema, SchemaRef};
11
11
  use datafusion::arrow::record_batch::RecordBatch;
12
12
  use datafusion::catalog::{Session, TableProvider};
13
- use datafusion::common::{not_impl_err, DFSchema, DataFusionError, Result, ScalarValue};
13
+ use datafusion::common::{not_impl_err, DFSchema, DataFusionError, Result, ScalarValue, SchemaExt};
14
14
  use datafusion::datasource::TableType;
15
15
  use datafusion::execution::TaskContext;
16
16
  use datafusion::logical_expr::dml::InsertOp;
@@ -27,20 +27,23 @@ use futures_util::{stream, TryStreamExt};
27
27
  use serde::Deserialize;
28
28
 
29
29
  use crate::binary_cas::{BlobDataReader, BlobHash};
30
- use crate::entity_identity::EntityIdentity;
30
+ use crate::branch::BranchRefReader;
31
+ use crate::entity_pk::EntityPk;
31
32
  use crate::functions::FunctionProviderHandle;
32
33
  use crate::live_state::MaterializedLiveStateRow;
33
34
  use crate::live_state::{
34
35
  LiveStateFilter, LiveStateProjection, LiveStateReader, LiveStateScanRequest,
35
36
  };
37
+ use crate::sql2::branch_scope::{
38
+ explicit_branch_ids_from_dml_filters, resolve_provider_branch_ids, resolve_write_branch_scope,
39
+ BranchBinding,
40
+ };
36
41
  use crate::sql2::dml::{InsertExec, InsertSink};
37
42
  use crate::sql2::filesystem_predicates::{
38
43
  canonicalize_filesystem_path_filters, FilesystemPathKind,
39
44
  };
40
- use crate::sql2::predicate_typecheck::validate_json_predicate_filters;
41
- use crate::sql2::version_scope::{
42
- explicit_version_ids_from_dml_filters, resolve_provider_version_ids,
43
- resolve_write_version_scope, VersionBinding,
45
+ use crate::sql2::predicate_typecheck::{
46
+ canonicalize_json_identity_text_filters, validate_json_predicate_filters,
44
47
  };
45
48
  use crate::sql2::write_normalization::{
46
49
  is_binary_type, lix_file_data_type_error, lix_file_data_type_error_with_value,
@@ -49,56 +52,68 @@ use crate::sql2::write_normalization::{
49
52
  UpdateCell,
50
53
  };
51
54
  use crate::transaction::types::{TransactionJson, TransactionWriteRow};
52
- use crate::version::VersionRefReader;
53
55
  use crate::{parse_row_metadata_value, serialize_row_metadata, LixError};
54
56
 
55
57
  const FILE_DESCRIPTOR_SCHEMA_KEY: &str = "lix_file_descriptor";
56
58
  const BLOB_REF_SCHEMA_KEY: &str = "lix_binary_blob_ref";
57
59
  const DIRECTORY_DESCRIPTOR_SCHEMA_KEY: &str = "lix_directory_descriptor";
58
60
 
59
- use super::filesystem_planner::{
61
+ use crate::sql2::filesystem_planner::{
60
62
  blob_ref_row, directory_path_resolvers_from_state_rows, file_descriptor_row,
61
63
  file_descriptor_write_row, filesystem_storage_scope_key, plan_file_delete,
62
64
  plan_file_path_update, BlobRefRowInput, DirectoryPathResolver, FileDeleteInput,
63
65
  FileDescriptorRowInput, FileDescriptorWriteIntent, FilePathWriteInput, FilesystemDeletePlan,
64
66
  FilesystemRowContext,
65
67
  };
66
- use super::result_metadata::json_field;
68
+ use crate::sql2::result_metadata::json_field;
69
+ use crate::sql2::session::SqlWriteSessionOptions;
67
70
  use crate::sql2::{
68
- SqlWriteContext, WriteAccess, WriteContextLiveStateReader, WriteContextVersionRefReader,
71
+ SqlWriteContext, WriteAccess, WriteContextBranchRefReader, WriteContextLiveStateReader,
69
72
  };
70
73
  use crate::transaction::types::{
71
74
  LogicalPrimaryKey, TransactionFileData, TransactionWrite, TransactionWriteMode,
72
75
  TransactionWriteOperation, TransactionWriteOrigin,
73
76
  };
74
77
 
75
- pub(crate) async fn register_lix_file_providers(
78
+ pub(super) async fn register_lix_file_active_provider(
76
79
  session: &SessionContext,
77
- active_version_id: &str,
80
+ surface_name: &str,
81
+ active_branch_id: &str,
78
82
  live_state: Arc<dyn LiveStateReader>,
79
- version_ref: Arc<dyn VersionRefReader>,
83
+ branch_ref: Arc<dyn BranchRefReader>,
80
84
  blob_reader: Arc<dyn BlobDataReader>,
81
85
  functions: FunctionProviderHandle,
82
86
  ) -> Result<(), LixError> {
83
87
  session
84
88
  .register_table(
85
- "lix_file_by_version",
86
- Arc::new(LixFileProvider::by_version(
87
- Arc::clone(&live_state),
88
- Arc::clone(&version_ref),
89
- Arc::clone(&blob_reader),
90
- functions.clone(),
89
+ surface_name,
90
+ Arc::new(LixFileProvider::active_branch(
91
+ active_branch_id,
92
+ live_state,
93
+ branch_ref,
94
+ blob_reader,
95
+ functions,
91
96
  )),
92
97
  )
93
98
  .map_err(datafusion_error_to_lix_error)?;
99
+ Ok(())
100
+ }
101
+
102
+ pub(super) async fn register_lix_file_by_branch_provider(
103
+ session: &SessionContext,
104
+ surface_name: &str,
105
+ live_state: Arc<dyn LiveStateReader>,
106
+ branch_ref: Arc<dyn BranchRefReader>,
107
+ blob_reader: Arc<dyn BlobDataReader>,
108
+ functions: FunctionProviderHandle,
109
+ ) -> Result<(), LixError> {
94
110
  session
95
111
  .register_table(
96
- "lix_file",
97
- Arc::new(LixFileProvider::active_version(
98
- active_version_id,
112
+ surface_name,
113
+ Arc::new(LixFileProvider::by_branch(
99
114
  live_state,
100
- version_ref,
101
- Arc::clone(&blob_reader),
115
+ branch_ref,
116
+ blob_reader,
102
117
  functions,
103
118
  )),
104
119
  )
@@ -106,20 +121,33 @@ pub(crate) async fn register_lix_file_providers(
106
121
  Ok(())
107
122
  }
108
123
 
109
- pub(crate) async fn register_lix_file_write_providers(
124
+ pub(super) async fn register_by_branch_write_provider(
110
125
  session: &SessionContext,
126
+ surface_name: &str,
111
127
  write_ctx: SqlWriteContext,
128
+ options: SqlWriteSessionOptions,
112
129
  ) -> Result<(), LixError> {
113
130
  session
114
131
  .register_table(
115
- "lix_file_by_version",
116
- Arc::new(LixFileProvider::by_version_with_write(write_ctx.clone())),
132
+ surface_name,
133
+ Arc::new(LixFileProvider::by_branch_with_write(write_ctx, options)),
117
134
  )
118
135
  .map_err(datafusion_error_to_lix_error)?;
136
+ Ok(())
137
+ }
138
+
139
+ pub(super) async fn register_active_write_provider(
140
+ session: &SessionContext,
141
+ surface_name: &str,
142
+ write_ctx: SqlWriteContext,
143
+ options: SqlWriteSessionOptions,
144
+ ) -> Result<(), LixError> {
119
145
  session
120
146
  .register_table(
121
- "lix_file",
122
- Arc::new(LixFileProvider::active_version_with_write(write_ctx)),
147
+ surface_name,
148
+ Arc::new(LixFileProvider::active_branch_with_write(
149
+ write_ctx, options,
150
+ )),
123
151
  )
124
152
  .map_err(datafusion_error_to_lix_error)?;
125
153
  Ok(())
@@ -128,11 +156,12 @@ pub(crate) async fn register_lix_file_write_providers(
128
156
  pub(crate) struct LixFileProvider {
129
157
  schema: SchemaRef,
130
158
  live_state: Arc<dyn LiveStateReader>,
131
- version_ref: Arc<dyn VersionRefReader>,
159
+ branch_ref: Arc<dyn BranchRefReader>,
132
160
  blob_reader: Arc<dyn BlobDataReader>,
133
161
  write_access: WriteAccess,
134
162
  functions: FunctionProviderHandle,
135
- version_binding: VersionBinding,
163
+ branch_binding: BranchBinding,
164
+ options: SqlWriteSessionOptions,
136
165
  }
137
166
 
138
167
  impl std::fmt::Debug for LixFileProvider {
@@ -142,71 +171,81 @@ impl std::fmt::Debug for LixFileProvider {
142
171
  }
143
172
 
144
173
  impl LixFileProvider {
145
- pub(crate) fn active_version(
146
- active_version_id: impl Into<String>,
174
+ pub(crate) fn active_branch(
175
+ active_branch_id: impl Into<String>,
147
176
  live_state: Arc<dyn LiveStateReader>,
148
- version_ref: Arc<dyn VersionRefReader>,
177
+ branch_ref: Arc<dyn BranchRefReader>,
149
178
  blob_reader: Arc<dyn BlobDataReader>,
150
179
  functions: FunctionProviderHandle,
151
180
  ) -> Self {
152
181
  Self {
153
182
  schema: lix_file_schema(),
154
183
  live_state,
155
- version_ref,
184
+ branch_ref,
156
185
  blob_reader,
157
186
  write_access: WriteAccess::read_only(),
158
187
  functions,
159
- version_binding: VersionBinding::active(active_version_id),
188
+ branch_binding: BranchBinding::active(active_branch_id),
189
+ options: SqlWriteSessionOptions::default(),
160
190
  }
161
191
  }
162
192
 
163
- pub(crate) fn active_version_with_write(write_ctx: SqlWriteContext) -> Self {
164
- let active_version_id = write_ctx.active_version_id();
193
+ pub(crate) fn active_branch_with_write(
194
+ write_ctx: SqlWriteContext,
195
+ options: SqlWriteSessionOptions,
196
+ ) -> Self {
197
+ let active_branch_id = write_ctx.active_branch_id();
165
198
  let functions = write_ctx.functions();
166
199
  let live_state = Arc::new(WriteContextLiveStateReader::new(write_ctx.clone()));
167
- let version_ref = Arc::new(WriteContextVersionRefReader::new(write_ctx.clone()));
200
+ let branch_ref = Arc::new(WriteContextBranchRefReader::new(write_ctx.clone()));
168
201
  let blob_reader = write_ctx.blob_reader();
169
202
  Self {
170
203
  schema: lix_file_schema(),
171
204
  live_state,
172
- version_ref,
205
+ branch_ref,
173
206
  blob_reader,
174
207
  write_access: WriteAccess::write(write_ctx),
175
208
  functions,
176
- version_binding: VersionBinding::active(active_version_id),
209
+ branch_binding: BranchBinding::active(active_branch_id),
210
+ options,
177
211
  }
178
212
  }
179
213
 
180
- pub(crate) fn by_version(
214
+ pub(crate) fn by_branch(
181
215
  live_state: Arc<dyn LiveStateReader>,
182
- version_ref: Arc<dyn VersionRefReader>,
216
+ branch_ref: Arc<dyn BranchRefReader>,
183
217
  blob_reader: Arc<dyn BlobDataReader>,
184
218
  functions: FunctionProviderHandle,
185
219
  ) -> Self {
186
220
  Self {
187
- schema: lix_file_by_version_schema(),
221
+ schema: lix_file_by_branch_schema(),
188
222
  live_state,
189
- version_ref,
223
+ branch_ref,
190
224
  blob_reader,
191
225
  write_access: WriteAccess::read_only(),
192
226
  functions,
193
- version_binding: VersionBinding::explicit(),
227
+ branch_binding: BranchBinding::explicit(),
228
+ options: SqlWriteSessionOptions::default(),
194
229
  }
195
230
  }
196
231
 
197
- pub(crate) fn by_version_with_write(write_ctx: SqlWriteContext) -> Self {
232
+ pub(crate) fn by_branch_with_write(
233
+ write_ctx: SqlWriteContext,
234
+ options: SqlWriteSessionOptions,
235
+ ) -> Self {
198
236
  let functions = write_ctx.functions();
199
237
  let live_state = Arc::new(WriteContextLiveStateReader::new(write_ctx.clone()));
200
- let version_ref = Arc::new(WriteContextVersionRefReader::new(write_ctx.clone()));
238
+ let branch_ref = Arc::new(WriteContextBranchRefReader::new(write_ctx.clone()));
201
239
  let blob_reader = write_ctx.blob_reader();
202
240
  Self {
203
- schema: lix_file_by_version_schema(),
241
+ schema: lix_file_by_branch_schema(),
204
242
  live_state,
205
- version_ref,
243
+ branch_ref,
206
244
  blob_reader,
207
245
  write_access: WriteAccess::write(write_ctx),
208
246
  functions,
209
- version_binding: VersionBinding::explicit(),
247
+ branch_binding: BranchBinding::explicit(),
248
+ options,
210
249
  }
211
250
  }
212
251
  }
@@ -233,7 +272,7 @@ impl TableProvider for LixFileProvider {
233
272
  Ok(filters
234
273
  .iter()
235
274
  .map(|filter| {
236
- if ExactStringColumnFilterAnalyzer::new("lixcol_version_id").supports(filter)
275
+ if ExactStringColumnFilterAnalyzer::new("lixcol_branch_id").supports(filter)
237
276
  || analyzer.supports(filter)
238
277
  || contains_column(filter, "path")
239
278
  {
@@ -255,24 +294,14 @@ impl TableProvider for LixFileProvider {
255
294
  let projected_schema = projected_schema(&self.schema, projection)?;
256
295
  let scan_limit = if filters.is_empty() { limit } else { None };
257
296
  let mut request = lix_file_scan_request(
258
- self.version_binding.active_version_id(),
297
+ self.branch_binding.active_branch_id(),
259
298
  Some(projected_schema.as_ref()),
260
299
  scan_limit,
261
300
  );
262
- if self.write_access.is_write() && matches!(self.version_binding, VersionBinding::Explicit)
263
- {
264
- request.filter.version_ids = explicit_version_ids_from_dml_filters(filters);
265
- if request.filter.version_ids.is_empty() {
266
- return Err(DataFusionError::Plan(
267
- "DELETE FROM lix_file_by_version requires an explicit lixcol_version_id predicate"
268
- .to_string(),
269
- ));
270
- }
271
- }
272
- request.filter.version_ids = resolve_provider_version_ids(
273
- self.version_ref.as_ref(),
274
- &self.version_binding,
275
- request.filter.version_ids,
301
+ request.filter.branch_ids = resolve_provider_branch_ids(
302
+ self.branch_ref.as_ref(),
303
+ &self.branch_binding,
304
+ request.filter.branch_ids,
276
305
  )
277
306
  .await
278
307
  .map_err(lix_error_to_datafusion_error)?;
@@ -306,19 +335,20 @@ impl TableProvider for LixFileProvider {
306
335
  if insert_op != InsertOp::Append {
307
336
  return not_impl_err!("{insert_op} not implemented for lix_file yet");
308
337
  }
309
-
310
338
  let write_ctx = self.write_access.require_write("INSERT into lix_file")?;
311
- let insert_column_intents = InsertColumnIntents::from_input(&input);
312
- let include_data_writes = insert_column_intents.includes_column("data");
339
+ self.schema
340
+ .logically_equivalent_names_and_types(&input.schema())?;
341
+ let insert_intents = InsertColumnIntents::from_input(&input);
342
+ let include_data_writes = self.schema.field_with_name("data").is_ok()
343
+ && insert_intents.includes_column("data")
344
+ && !self.options.omitted_insert_columns.contains("data");
313
345
  if include_data_writes {
314
346
  reject_non_binary_casts_for_insert_column(&input, "data", "INSERT into lix_file")?;
315
347
  }
316
-
317
348
  let sink = LixFileInsertSink::new(
318
- input.schema(),
319
- write_ctx.clone(),
349
+ write_ctx,
320
350
  self.functions.clone(),
321
- self.version_binding.clone(),
351
+ self.branch_binding.clone(),
322
352
  include_data_writes,
323
353
  );
324
354
  Ok(Arc::new(InsertExec::new(input, Arc::new(sink))))
@@ -330,32 +360,29 @@ impl TableProvider for LixFileProvider {
330
360
  filters: Vec<Expr>,
331
361
  ) -> Result<Arc<dyn ExecutionPlan>> {
332
362
  let write_ctx = self.write_access.require_write("DELETE FROM lix_file")?;
333
-
334
- let df_schema = DFSchema::try_from(Arc::clone(&self.schema))?;
335
363
  let filters = canonicalize_filesystem_path_filters(&filters, FilesystemPathKind::File)?;
364
+ let filters = canonicalize_json_identity_text_filters(self.schema.as_ref(), &filters)?;
365
+ let target_file_ids = file_id_constraint_from_filters(&filters)?;
366
+ let df_schema = DFSchema::try_from(Arc::clone(&self.schema))?;
336
367
  validate_json_predicate_filters(self.schema.as_ref(), &filters)?;
337
368
  let physical_filters = filters
338
369
  .iter()
339
370
  .map(|expr| create_physical_expr(expr, &df_schema, state.execution_props()))
340
371
  .collect::<Result<Vec<_>>>()?;
341
- let target_file_ids = file_id_constraint_from_filters(&filters)?;
342
- let mut request =
343
- lix_file_scan_request(self.version_binding.active_version_id(), None, None);
344
- if matches!(self.version_binding, VersionBinding::Explicit) {
345
- request.filter.version_ids = explicit_version_ids_from_dml_filters(&filters);
346
- if request.filter.version_ids.is_empty() {
347
- return Err(DataFusionError::Plan(
348
- "DELETE FROM lix_file_by_version requires an explicit lixcol_version_id predicate"
349
- .to_string(),
350
- ));
351
- }
352
- }
353
-
372
+ let mut request = lix_file_scan_request(self.branch_binding.active_branch_id(), None, None);
373
+ request.filter.branch_ids = explicit_branch_ids_from_dml_filters(&filters);
374
+ request.filter.branch_ids = resolve_provider_branch_ids(
375
+ self.branch_ref.as_ref(),
376
+ &self.branch_binding,
377
+ request.filter.branch_ids,
378
+ )
379
+ .await
380
+ .map_err(lix_error_to_datafusion_error)?;
354
381
  Ok(Arc::new(LixFileDeleteExec::new(
355
382
  Arc::clone(&self.blob_reader),
356
- write_ctx.clone(),
383
+ write_ctx,
357
384
  Arc::clone(&self.schema),
358
- self.version_binding.clone(),
385
+ self.branch_binding.clone(),
359
386
  request,
360
387
  target_file_ids,
361
388
  physical_filters,
@@ -369,10 +396,12 @@ impl TableProvider for LixFileProvider {
369
396
  filters: Vec<Expr>,
370
397
  ) -> Result<Arc<dyn ExecutionPlan>> {
371
398
  let write_ctx = self.write_access.require_write("UPDATE lix_file")?;
372
-
373
399
  validate_lix_file_update_assignments(&self.schema, &assignments)?;
374
-
400
+ let filters = canonicalize_filesystem_path_filters(&filters, FilesystemPathKind::File)?;
401
+ let filters = canonicalize_json_identity_text_filters(self.schema.as_ref(), &filters)?;
402
+ let target_file_ids = file_id_constraint_from_filters(&filters)?;
375
403
  let df_schema = DFSchema::try_from(Arc::clone(&self.schema))?;
404
+ validate_json_predicate_filters(self.schema.as_ref(), &filters)?;
376
405
  let physical_assignments = assignments
377
406
  .iter()
378
407
  .map(|(column_name, expr)| {
@@ -382,20 +411,24 @@ impl TableProvider for LixFileProvider {
382
411
  ))
383
412
  })
384
413
  .collect::<Result<Vec<_>>>()?;
385
- let filters = canonicalize_filesystem_path_filters(&filters, FilesystemPathKind::File)?;
386
- let target_file_ids = file_id_constraint_from_filters(&filters)?;
387
- validate_json_predicate_filters(self.schema.as_ref(), &filters)?;
388
414
  let physical_filters = filters
389
415
  .iter()
390
416
  .map(|expr| create_physical_expr(expr, &df_schema, state.execution_props()))
391
417
  .collect::<Result<Vec<_>>>()?;
392
- let request = lix_file_scan_request(self.version_binding.active_version_id(), None, None);
393
-
418
+ let mut request = lix_file_scan_request(self.branch_binding.active_branch_id(), None, None);
419
+ request.filter.branch_ids = explicit_branch_ids_from_dml_filters(&filters);
420
+ request.filter.branch_ids = resolve_provider_branch_ids(
421
+ self.branch_ref.as_ref(),
422
+ &self.branch_binding,
423
+ request.filter.branch_ids,
424
+ )
425
+ .await
426
+ .map_err(lix_error_to_datafusion_error)?;
394
427
  Ok(Arc::new(LixFileUpdateExec::new(
395
428
  Arc::clone(&self.blob_reader),
396
- write_ctx.clone(),
429
+ write_ctx,
397
430
  Arc::clone(&self.schema),
398
- self.version_binding.clone(),
431
+ self.branch_binding.clone(),
399
432
  self.functions.clone(),
400
433
  request,
401
434
  target_file_ids,
@@ -409,7 +442,7 @@ impl TableProvider for LixFileProvider {
409
442
  struct LixFileInsertSink {
410
443
  write_ctx: SqlWriteContext,
411
444
  functions: FunctionProviderHandle,
412
- version_binding: VersionBinding,
445
+ branch_binding: BranchBinding,
413
446
  surface_name: &'static str,
414
447
  include_data_writes: bool,
415
448
  }
@@ -422,17 +455,16 @@ impl std::fmt::Debug for LixFileInsertSink {
422
455
 
423
456
  impl LixFileInsertSink {
424
457
  fn new(
425
- _schema: SchemaRef,
426
458
  write_ctx: SqlWriteContext,
427
459
  functions: FunctionProviderHandle,
428
- version_binding: VersionBinding,
460
+ branch_binding: BranchBinding,
429
461
  include_data_writes: bool,
430
462
  ) -> Self {
431
- let surface_name = lix_file_surface_name(&version_binding);
463
+ let surface_name = lix_file_surface_name(&branch_binding);
432
464
  Self {
433
465
  write_ctx,
434
466
  functions,
435
- version_binding,
467
+ branch_binding,
436
468
  surface_name,
437
469
  include_data_writes,
438
470
  }
@@ -464,7 +496,7 @@ impl InsertSink for LixFileInsertSink {
464
496
  path_resolvers = Some(
465
497
  file_path_resolvers_from_live_state(
466
498
  Arc::new(WriteContextLiveStateReader::new(self.write_ctx.clone())),
467
- self.version_binding.active_version_id(),
499
+ self.branch_binding.active_branch_id(),
468
500
  )
469
501
  .await
470
502
  .map_err(lix_error_to_datafusion_error)?,
@@ -473,7 +505,7 @@ impl InsertSink for LixFileInsertSink {
473
505
  if record_batch_has_non_null_column(&batch, "path")? {
474
506
  staged.extend(lix_file_insert_stage_from_batch_with_path_resolvers(
475
507
  &batch,
476
- self.version_binding.active_version_id(),
508
+ self.branch_binding.active_branch_id(),
477
509
  self.surface_name,
478
510
  path_resolvers
479
511
  .as_mut()
@@ -485,7 +517,7 @@ impl InsertSink for LixFileInsertSink {
485
517
  staged.extend(
486
518
  lix_file_insert_stage_from_batch_with_id_generator_and_path_resolvers(
487
519
  &batch,
488
- self.version_binding.active_version_id(),
520
+ self.branch_binding.active_branch_id(),
489
521
  self.surface_name,
490
522
  path_resolvers
491
523
  .as_mut()
@@ -521,10 +553,10 @@ impl InsertSink for LixFileInsertSink {
521
553
  }
522
554
  }
523
555
 
524
- fn lix_file_surface_name(version_binding: &VersionBinding) -> &'static str {
525
- match version_binding {
526
- VersionBinding::Active { .. } => "lix_file",
527
- VersionBinding::Explicit => "lix_file_by_version",
556
+ fn lix_file_surface_name(branch_binding: &BranchBinding) -> &'static str {
557
+ match branch_binding {
558
+ BranchBinding::Active { .. } => "lix_file",
559
+ BranchBinding::Explicit => "lix_file_by_branch",
528
560
  }
529
561
  }
530
562
 
@@ -533,7 +565,7 @@ struct LixFileDeleteExec {
533
565
  blob_reader: Arc<dyn BlobDataReader>,
534
566
  write_ctx: SqlWriteContext,
535
567
  table_schema: SchemaRef,
536
- version_binding: VersionBinding,
568
+ branch_binding: BranchBinding,
537
569
  request: LiveStateScanRequest,
538
570
  target_file_ids: FileIdConstraint,
539
571
  filters: Vec<Arc<dyn PhysicalExpr>>,
@@ -552,7 +584,7 @@ impl LixFileDeleteExec {
552
584
  blob_reader: Arc<dyn BlobDataReader>,
553
585
  write_ctx: SqlWriteContext,
554
586
  table_schema: SchemaRef,
555
- version_binding: VersionBinding,
587
+ branch_binding: BranchBinding,
556
588
  request: LiveStateScanRequest,
557
589
  target_file_ids: FileIdConstraint,
558
590
  filters: Vec<Arc<dyn PhysicalExpr>>,
@@ -568,7 +600,7 @@ impl LixFileDeleteExec {
568
600
  blob_reader,
569
601
  write_ctx,
570
602
  table_schema,
571
- version_binding,
603
+ branch_binding,
572
604
  request,
573
605
  target_file_ids,
574
606
  filters,
@@ -632,7 +664,7 @@ impl ExecutionPlan for LixFileDeleteExec {
632
664
  let blob_reader = Arc::clone(&self.blob_reader);
633
665
  let write_ctx = self.write_ctx.clone();
634
666
  let table_schema = Arc::clone(&self.table_schema);
635
- let version_binding = self.version_binding.clone();
667
+ let branch_binding = self.branch_binding.clone();
636
668
  let request = self.request.clone();
637
669
  let target_file_ids = self.target_file_ids.clone();
638
670
  let filters = self.filters.clone();
@@ -655,7 +687,7 @@ impl ExecutionPlan for LixFileDeleteExec {
655
687
  let matched_batch = filter_lix_file_batch(source_batch, &filters)?;
656
688
  let staged = lix_file_delete_stage_from_batch(
657
689
  &matched_batch,
658
- version_binding.active_version_id(),
690
+ branch_binding.active_branch_id(),
659
691
  &blob_ref_file_ids,
660
692
  )?;
661
693
  let count = staged.count;
@@ -688,7 +720,7 @@ struct LixFileUpdateExec {
688
720
  blob_reader: Arc<dyn BlobDataReader>,
689
721
  write_ctx: SqlWriteContext,
690
722
  table_schema: SchemaRef,
691
- version_binding: VersionBinding,
723
+ branch_binding: BranchBinding,
692
724
  functions: FunctionProviderHandle,
693
725
  request: LiveStateScanRequest,
694
726
  target_file_ids: FileIdConstraint,
@@ -709,7 +741,7 @@ impl LixFileUpdateExec {
709
741
  blob_reader: Arc<dyn BlobDataReader>,
710
742
  write_ctx: SqlWriteContext,
711
743
  table_schema: SchemaRef,
712
- version_binding: VersionBinding,
744
+ branch_binding: BranchBinding,
713
745
  functions: FunctionProviderHandle,
714
746
  request: LiveStateScanRequest,
715
747
  target_file_ids: FileIdConstraint,
@@ -727,7 +759,7 @@ impl LixFileUpdateExec {
727
759
  blob_reader,
728
760
  write_ctx,
729
761
  table_schema,
730
- version_binding,
762
+ branch_binding,
731
763
  functions,
732
764
  request,
733
765
  target_file_ids,
@@ -798,7 +830,7 @@ impl ExecutionPlan for LixFileUpdateExec {
798
830
  let blob_reader = Arc::clone(&self.blob_reader);
799
831
  let write_ctx = self.write_ctx.clone();
800
832
  let table_schema = Arc::clone(&self.table_schema);
801
- let version_binding = self.version_binding.clone();
833
+ let branch_binding = self.branch_binding.clone();
802
834
  let functions = self.functions.clone();
803
835
  let request = self.request.clone();
804
836
  let target_file_ids = self.target_file_ids.clone();
@@ -826,7 +858,7 @@ impl ExecutionPlan for LixFileUpdateExec {
826
858
  path_resolvers = Some(
827
859
  file_path_resolvers_from_live_state(
828
860
  Arc::new(WriteContextLiveStateReader::new(write_ctx.clone())),
829
- version_binding.active_version_id(),
861
+ branch_binding.active_branch_id(),
830
862
  )
831
863
  .await
832
864
  .map_err(lix_error_to_datafusion_error)?,
@@ -835,7 +867,7 @@ impl ExecutionPlan for LixFileUpdateExec {
835
867
  let staged = lix_file_update_stage_from_batch(
836
868
  &matched_batch,
837
869
  &assignment_values,
838
- version_binding.active_version_id(),
870
+ branch_binding.active_branch_id(),
839
871
  update_columns,
840
872
  path_resolvers.as_mut(),
841
873
  &mut || functions.call_uuid_v7(),
@@ -1035,7 +1067,7 @@ struct DirectoryDescriptorRecord {
1035
1067
  id: String,
1036
1068
  parent_id: Option<String>,
1037
1069
  name: String,
1038
- version_id: String,
1070
+ branch_id: String,
1039
1071
  }
1040
1072
 
1041
1073
  #[derive(Debug, Deserialize)]
@@ -1073,7 +1105,10 @@ impl LixFileStagedBatch {
1073
1105
  self.count += other.count;
1074
1106
  }
1075
1107
 
1076
- fn extend_filesystem_plan(&mut self, plan: super::filesystem_planner::FilesystemWritePlan) {
1108
+ fn extend_filesystem_plan(
1109
+ &mut self,
1110
+ plan: crate::sql2::filesystem_planner::FilesystemWritePlan,
1111
+ ) {
1077
1112
  self.state_rows.extend(plan.rows);
1078
1113
  self.file_data_writes.extend(plan.file_data);
1079
1114
  self.count += plan.count;
@@ -1088,20 +1123,20 @@ impl LixFileStagedBatch {
1088
1123
  #[cfg(test)]
1089
1124
  fn lix_file_write_rows_from_batch(
1090
1125
  batch: &RecordBatch,
1091
- version_binding: Option<&str>,
1126
+ branch_binding: Option<&str>,
1092
1127
  ) -> Result<Vec<TransactionWriteRow>> {
1093
- Ok(lix_file_insert_stage_from_batch(batch, version_binding)?.state_rows)
1128
+ Ok(lix_file_insert_stage_from_batch(batch, branch_binding)?.state_rows)
1094
1129
  }
1095
1130
 
1096
1131
  fn lix_file_delete_stage_from_batch(
1097
1132
  batch: &RecordBatch,
1098
- version_binding: Option<&str>,
1133
+ branch_binding: Option<&str>,
1099
1134
  blob_ref_file_ids: &BTreeSet<String>,
1100
1135
  ) -> Result<LixFileStagedBatch> {
1101
1136
  let mut staged = LixFileStagedBatch::default();
1102
1137
  for row_index in 0..batch.num_rows() {
1103
1138
  let file_id = required_string_value(batch, row_index, "id")?;
1104
- let context = file_row_context_from_batch(batch, row_index, version_binding)?;
1139
+ let context = file_row_context_from_batch(batch, row_index, branch_binding)?;
1105
1140
  staged.extend_filesystem_delete_plan(plan_file_delete(FileDeleteInput {
1106
1141
  file_id: file_id.clone(),
1107
1142
  has_blob_ref: blob_ref_file_ids.contains(&file_id),
@@ -1137,14 +1172,14 @@ fn blob_ref_file_ids_from_live_rows(
1137
1172
  #[cfg(test)]
1138
1173
  fn lix_file_insert_stage_from_batch(
1139
1174
  batch: &RecordBatch,
1140
- version_binding: Option<&str>,
1175
+ branch_binding: Option<&str>,
1141
1176
  ) -> Result<LixFileStagedBatch> {
1142
- lix_file_stage_from_batch_with_options(batch, version_binding, "lix_file", true, true, true)
1177
+ lix_file_stage_from_batch_with_options(batch, branch_binding, "lix_file", true, true, true)
1143
1178
  }
1144
1179
 
1145
1180
  fn lix_file_insert_stage_from_batch_with_id_generator_and_path_resolvers(
1146
1181
  batch: &RecordBatch,
1147
- version_binding: Option<&str>,
1182
+ branch_binding: Option<&str>,
1148
1183
  surface_name: &str,
1149
1184
  path_resolvers: &mut BTreeMap<String, DirectoryPathResolver>,
1150
1185
  generate_id: &mut dyn FnMut() -> String,
@@ -1152,7 +1187,7 @@ fn lix_file_insert_stage_from_batch_with_id_generator_and_path_resolvers(
1152
1187
  ) -> Result<LixFileStagedBatch> {
1153
1188
  lix_file_stage_from_batch_with_options_and_path_resolvers(
1154
1189
  batch,
1155
- version_binding,
1190
+ branch_binding,
1156
1191
  surface_name,
1157
1192
  true,
1158
1193
  true,
@@ -1164,7 +1199,7 @@ fn lix_file_insert_stage_from_batch_with_id_generator_and_path_resolvers(
1164
1199
 
1165
1200
  fn lix_file_insert_stage_from_batch_with_path_resolvers(
1166
1201
  batch: &RecordBatch,
1167
- version_binding: Option<&str>,
1202
+ branch_binding: Option<&str>,
1168
1203
  surface_name: &str,
1169
1204
  path_resolvers: &mut BTreeMap<String, DirectoryPathResolver>,
1170
1205
  generate_directory_id: &mut dyn FnMut() -> String,
@@ -1172,7 +1207,7 @@ fn lix_file_insert_stage_from_batch_with_path_resolvers(
1172
1207
  ) -> Result<LixFileStagedBatch> {
1173
1208
  lix_file_stage_from_batch_with_options_and_path_resolvers(
1174
1209
  batch,
1175
- version_binding,
1210
+ branch_binding,
1176
1211
  surface_name,
1177
1212
  true,
1178
1213
  true,
@@ -1185,7 +1220,7 @@ fn lix_file_insert_stage_from_batch_with_path_resolvers(
1185
1220
  fn lix_file_existing_update_stage_from_batch(
1186
1221
  batch: &RecordBatch,
1187
1222
  assignment_values: &UpdateAssignmentValues,
1188
- version_binding: Option<&str>,
1223
+ branch_binding: Option<&str>,
1189
1224
  include_descriptor_writes: bool,
1190
1225
  include_data_writes: bool,
1191
1226
  path_resolvers: Option<&mut BTreeMap<String, DirectoryPathResolver>>,
@@ -1198,7 +1233,7 @@ fn lix_file_existing_update_stage_from_batch(
1198
1233
  let hidden = update_optional_bool_value(batch, assignment_values, row_index, "hidden")?
1199
1234
  .unwrap_or(false);
1200
1235
  let context =
1201
- file_row_context_from_update(batch, assignment_values, row_index, version_binding)?;
1236
+ file_row_context_from_update(batch, assignment_values, row_index, branch_binding)?;
1202
1237
 
1203
1238
  if include_descriptor_writes {
1204
1239
  let directory_id =
@@ -1266,7 +1301,7 @@ impl LixFileUpdateColumns {
1266
1301
  fn lix_file_update_stage_from_batch(
1267
1302
  batch: &RecordBatch,
1268
1303
  assignment_values: &UpdateAssignmentValues,
1269
- version_binding: Option<&str>,
1304
+ branch_binding: Option<&str>,
1270
1305
  update_columns: LixFileUpdateColumns,
1271
1306
  path_resolvers: Option<&mut BTreeMap<String, DirectoryPathResolver>>,
1272
1307
  generate_directory_id: &mut dyn FnMut() -> String,
@@ -1281,7 +1316,7 @@ fn lix_file_update_stage_from_batch(
1281
1316
  lix_file_path_update_stage_from_batch(
1282
1317
  batch,
1283
1318
  assignment_values,
1284
- version_binding,
1319
+ branch_binding,
1285
1320
  update_columns,
1286
1321
  path_resolvers,
1287
1322
  generate_directory_id,
@@ -1290,7 +1325,7 @@ fn lix_file_update_stage_from_batch(
1290
1325
  lix_file_existing_update_stage_from_batch(
1291
1326
  batch,
1292
1327
  assignment_values,
1293
- version_binding,
1328
+ branch_binding,
1294
1329
  update_columns.descriptor,
1295
1330
  update_columns.data,
1296
1331
  Some(path_resolvers),
@@ -1301,7 +1336,7 @@ fn lix_file_update_stage_from_batch(
1301
1336
  lix_file_existing_update_stage_from_batch(
1302
1337
  batch,
1303
1338
  assignment_values,
1304
- version_binding,
1339
+ branch_binding,
1305
1340
  update_columns.descriptor,
1306
1341
  update_columns.data,
1307
1342
  None,
@@ -1311,7 +1346,7 @@ fn lix_file_update_stage_from_batch(
1311
1346
  fn lix_file_path_update_stage_from_batch(
1312
1347
  batch: &RecordBatch,
1313
1348
  assignment_values: &UpdateAssignmentValues,
1314
- version_binding: Option<&str>,
1349
+ branch_binding: Option<&str>,
1315
1350
  update_columns: LixFileUpdateColumns,
1316
1351
  path_resolvers: &mut BTreeMap<String, DirectoryPathResolver>,
1317
1352
  generate_directory_id: &mut dyn FnMut() -> String,
@@ -1324,7 +1359,7 @@ fn lix_file_path_update_stage_from_batch(
1324
1359
  let hidden = update_optional_bool_value(batch, assignment_values, row_index, "hidden")?
1325
1360
  .unwrap_or(false);
1326
1361
  let context =
1327
- file_row_context_from_update(batch, assignment_values, row_index, version_binding)?;
1362
+ file_row_context_from_update(batch, assignment_values, row_index, branch_binding)?;
1328
1363
  let assigned_data = if update_columns.data {
1329
1364
  Some(update_required_binary_value(
1330
1365
  batch,
@@ -1362,7 +1397,7 @@ fn lix_file_path_update_stage_from_batch(
1362
1397
  #[cfg(test)]
1363
1398
  fn lix_file_stage_from_batch_with_options(
1364
1399
  batch: &RecordBatch,
1365
- version_binding: Option<&str>,
1400
+ branch_binding: Option<&str>,
1366
1401
  surface_name: &str,
1367
1402
  reject_read_only_fields: bool,
1368
1403
  include_descriptor_writes: bool,
@@ -1370,7 +1405,7 @@ fn lix_file_stage_from_batch_with_options(
1370
1405
  ) -> Result<LixFileStagedBatch> {
1371
1406
  lix_file_stage_from_batch_with_options_and_path_resolvers(
1372
1407
  batch,
1373
- version_binding,
1408
+ branch_binding,
1374
1409
  surface_name,
1375
1410
  reject_read_only_fields,
1376
1411
  include_descriptor_writes,
@@ -1382,7 +1417,7 @@ fn lix_file_stage_from_batch_with_options(
1382
1417
 
1383
1418
  fn lix_file_stage_from_batch_with_options_and_path_resolvers(
1384
1419
  batch: &RecordBatch,
1385
- version_binding: Option<&str>,
1420
+ branch_binding: Option<&str>,
1386
1421
  surface_name: &str,
1387
1422
  reject_read_only_fields: bool,
1388
1423
  include_descriptor_writes: bool,
@@ -1394,7 +1429,7 @@ fn lix_file_stage_from_batch_with_options_and_path_resolvers(
1394
1429
 
1395
1430
  for row_index in 0..batch.num_rows() {
1396
1431
  if reject_read_only_fields {
1397
- reject_read_only_lix_file_insert_field(batch, row_index, "lixcol_entity_id")?;
1432
+ reject_read_only_lix_file_insert_field(batch, row_index, "lixcol_entity_pk")?;
1398
1433
  reject_read_only_lix_file_insert_field(batch, row_index, "lixcol_schema_key")?;
1399
1434
  reject_read_only_lix_file_insert_field(batch, row_index, "lixcol_change_id")?;
1400
1435
  reject_read_only_lix_file_insert_field(batch, row_index, "lixcol_created_at")?;
@@ -1405,7 +1440,7 @@ fn lix_file_stage_from_batch_with_options_and_path_resolvers(
1405
1440
  let path = optional_string_value(batch, row_index, "path")?;
1406
1441
  let id = optional_string_value(batch, row_index, "id")?;
1407
1442
  let hidden = optional_bool_value(batch, row_index, "hidden")?;
1408
- let context = file_row_context_from_batch(batch, row_index, version_binding)?;
1443
+ let context = file_row_context_from_batch(batch, row_index, branch_binding)?;
1409
1444
  let data = if include_data_writes {
1410
1445
  insert_optional_binary_value(batch, row_index, "data")?
1411
1446
  } else {
@@ -1430,7 +1465,7 @@ fn lix_file_stage_from_batch_with_options_and_path_resolvers(
1430
1465
  ));
1431
1466
  };
1432
1467
  let file_id = id.unwrap_or_else(|| generate_directory_id());
1433
- let mut plan = super::filesystem_planner::plan_file_path_write(
1468
+ let mut plan = crate::sql2::filesystem_planner::plan_file_path_write(
1434
1469
  resolver,
1435
1470
  FilePathWriteInput {
1436
1471
  id: Some(file_id.clone()),
@@ -1524,7 +1559,7 @@ fn stage_lix_file_data_write(
1524
1559
  staged.state_rows.push(row);
1525
1560
  staged.file_data_writes.push(TransactionFileData {
1526
1561
  file_id,
1527
- version_id: context.version_id,
1562
+ branch_id: context.branch_id,
1528
1563
  untracked: context.untracked,
1529
1564
  data,
1530
1565
  });
@@ -1558,19 +1593,19 @@ fn lix_file_insert_origin(surface_name: &str, file_id: &str) -> TransactionWrite
1558
1593
  fn file_row_context_from_batch(
1559
1594
  batch: &RecordBatch,
1560
1595
  row_index: usize,
1561
- version_binding: Option<&str>,
1596
+ branch_binding: Option<&str>,
1562
1597
  ) -> Result<FilesystemRowContext> {
1563
- let explicit_version_id = optional_string_value(batch, row_index, "lixcol_version_id")?;
1564
- let scope = resolve_write_version_scope(
1598
+ let explicit_branch_id = optional_string_value(batch, row_index, "lixcol_branch_id")?;
1599
+ let scope = resolve_write_branch_scope(
1565
1600
  optional_bool_value(batch, row_index, "lixcol_global")?,
1566
- explicit_version_id,
1567
- version_binding,
1568
- "INSERT into lix_file_by_version",
1601
+ explicit_branch_id,
1602
+ branch_binding,
1603
+ "INSERT into lix_file_by_branch",
1569
1604
  "lix_file",
1570
1605
  )?;
1571
1606
 
1572
1607
  Ok(FilesystemRowContext {
1573
- version_id: scope.version_id,
1608
+ branch_id: scope.branch_id,
1574
1609
  global: scope.global,
1575
1610
  untracked: optional_bool_value(batch, row_index, "lixcol_untracked")?.unwrap_or(false),
1576
1611
  file_id: optional_string_value(batch, row_index, "lixcol_file_id")?,
@@ -1582,19 +1617,19 @@ fn file_row_context_from_update(
1582
1617
  batch: &RecordBatch,
1583
1618
  assignment_values: &UpdateAssignmentValues,
1584
1619
  row_index: usize,
1585
- version_binding: Option<&str>,
1620
+ branch_binding: Option<&str>,
1586
1621
  ) -> Result<FilesystemRowContext> {
1587
- let explicit_version_id = optional_string_value(batch, row_index, "lixcol_version_id")?;
1588
- let scope = resolve_write_version_scope(
1622
+ let explicit_branch_id = optional_string_value(batch, row_index, "lixcol_branch_id")?;
1623
+ let scope = resolve_write_branch_scope(
1589
1624
  optional_bool_value(batch, row_index, "lixcol_global")?,
1590
- explicit_version_id,
1591
- version_binding,
1592
- "UPDATE into lix_file_by_version",
1625
+ explicit_branch_id,
1626
+ branch_binding,
1627
+ "UPDATE into lix_file_by_branch",
1593
1628
  "lix_file",
1594
1629
  )?;
1595
1630
 
1596
1631
  Ok(FilesystemRowContext {
1597
- version_id: scope.version_id,
1632
+ branch_id: scope.branch_id,
1598
1633
  global: scope.global,
1599
1634
  untracked: optional_bool_value(batch, row_index, "lixcol_untracked")?.unwrap_or(false),
1600
1635
  file_id: optional_string_value(batch, row_index, "lixcol_file_id")?,
@@ -1610,7 +1645,7 @@ fn file_row_context_from_update(
1610
1645
 
1611
1646
  fn file_path_resolver_key(context: &FilesystemRowContext) -> String {
1612
1647
  filesystem_storage_scope_key(
1613
- &context.version_id,
1648
+ &context.branch_id,
1614
1649
  context.global,
1615
1650
  context.untracked,
1616
1651
  context.file_id.as_deref(),
@@ -1619,7 +1654,7 @@ fn file_path_resolver_key(context: &FilesystemRowContext) -> String {
1619
1654
 
1620
1655
  async fn file_path_resolvers_from_live_state(
1621
1656
  live_state: Arc<dyn LiveStateReader>,
1622
- version_binding: Option<&str>,
1657
+ branch_binding: Option<&str>,
1623
1658
  ) -> std::result::Result<BTreeMap<String, DirectoryPathResolver>, LixError> {
1624
1659
  let rows = live_state
1625
1660
  .scan_rows(&LiveStateScanRequest {
@@ -1628,8 +1663,8 @@ async fn file_path_resolvers_from_live_state(
1628
1663
  DIRECTORY_DESCRIPTOR_SCHEMA_KEY.to_string(),
1629
1664
  FILE_DESCRIPTOR_SCHEMA_KEY.to_string(),
1630
1665
  ],
1631
- version_ids: version_binding
1632
- .map(|version_id| vec![version_id.to_string()])
1666
+ branch_ids: branch_binding
1667
+ .map(|branch_id| vec![branch_id.to_string()])
1633
1668
  .unwrap_or_default(),
1634
1669
  ..Default::default()
1635
1670
  },
@@ -1637,8 +1672,8 @@ async fn file_path_resolvers_from_live_state(
1637
1672
  })
1638
1673
  .await?;
1639
1674
  let mut resolvers = directory_path_resolvers_from_state_rows(rows)?;
1640
- if let Some(version_id) = version_binding {
1641
- let key = filesystem_storage_scope_key(version_id, false, false, None);
1675
+ if let Some(branch_id) = branch_binding {
1676
+ let key = filesystem_storage_scope_key(branch_id, false, false, None);
1642
1677
  resolvers
1643
1678
  .entry(key)
1644
1679
  .or_insert_with(DirectoryPathResolver::default);
@@ -1678,7 +1713,7 @@ async fn lix_file_record_batch(
1678
1713
  )
1679
1714
  })?;
1680
1715
  file_rows.insert(
1681
- (row.version_id.clone(), snapshot.id.clone()),
1716
+ (row.branch_id.clone(), snapshot.id.clone()),
1682
1717
  FileDescriptorRecord {
1683
1718
  id: snapshot.id,
1684
1719
  directory_id: snapshot.directory_id,
@@ -1700,7 +1735,7 @@ async fn lix_file_record_batch(
1700
1735
  )
1701
1736
  })?;
1702
1737
  blob_rows.insert(
1703
- (row.version_id.clone(), snapshot.id.clone()),
1738
+ (row.branch_id.clone(), snapshot.id.clone()),
1704
1739
  BlobRefRecord {
1705
1740
  blob_hash: snapshot.blob_hash,
1706
1741
  },
@@ -1721,7 +1756,7 @@ async fn lix_file_record_batch(
1721
1756
  id: snapshot.id,
1722
1757
  parent_id: snapshot.parent_id,
1723
1758
  name: snapshot.name,
1724
- version_id: row.version_id,
1759
+ branch_id: row.branch_id,
1725
1760
  });
1726
1761
  }
1727
1762
  _ => {}
@@ -1735,7 +1770,7 @@ async fn lix_file_record_batch(
1735
1770
  let mut names = Vec::new();
1736
1771
  let mut hiddens = Vec::new();
1737
1772
  let mut data_values = Vec::new();
1738
- let mut entity_ids = Vec::new();
1773
+ let mut entity_pks = Vec::new();
1739
1774
  let mut schema_keys = Vec::new();
1740
1775
  let mut file_ids = Vec::new();
1741
1776
  let mut globals = Vec::new();
@@ -1745,18 +1780,18 @@ async fn lix_file_record_batch(
1745
1780
  let mut commit_ids = Vec::new();
1746
1781
  let mut untracked_values = Vec::new();
1747
1782
  let mut metadata_values = Vec::new();
1748
- let mut version_ids = Vec::new();
1783
+ let mut branch_ids = Vec::new();
1749
1784
 
1750
- for ((version_id, _), file) in file_rows {
1785
+ for ((branch_id, _), file) in file_rows {
1751
1786
  let directory_path = match file.directory_id.as_ref() {
1752
1787
  Some(directory_id) => {
1753
- let key = (version_id.clone(), directory_id.clone());
1788
+ let key = (branch_id.clone(), directory_id.clone());
1754
1789
  let Some(path) = directory_paths.get(&key).cloned() else {
1755
1790
  return Err(LixError::new(
1756
1791
  LixError::CODE_FOREIGN_KEY,
1757
1792
  format!(
1758
- "lix_file_descriptor '{}' references missing directory_id '{}' in version '{}'",
1759
- file.id, directory_id, version_id
1793
+ "lix_file_descriptor '{}' references missing directory_id '{}' in branch '{}'",
1794
+ file.id, directory_id, branch_id
1760
1795
  ),
1761
1796
  ));
1762
1797
  };
@@ -1769,7 +1804,7 @@ async fn lix_file_record_batch(
1769
1804
  None => format!("/{}", file.name),
1770
1805
  };
1771
1806
  let data = if needs_data {
1772
- match blob_rows.get(&(version_id.clone(), file.id.clone())) {
1807
+ match blob_rows.get(&(branch_id.clone(), file.id.clone())) {
1773
1808
  Some(blob_ref) => load_single_blob_bytes(blob_reader, &blob_ref.blob_hash).await?,
1774
1809
  None => None,
1775
1810
  }
@@ -1783,7 +1818,7 @@ async fn lix_file_record_batch(
1783
1818
  names.push(Some(file.name));
1784
1819
  hiddens.push(Some(file.hidden));
1785
1820
  data_values.push(data);
1786
- entity_ids.push(Some(file.live.entity_id.as_json_array_text()?));
1821
+ entity_pks.push(Some(file.live.entity_pk.as_json_array_text()?));
1787
1822
  schema_keys.push(Some(file.live.schema_key));
1788
1823
  file_ids.push(file.live.file_id);
1789
1824
  globals.push(Some(file.live.global));
@@ -1793,7 +1828,7 @@ async fn lix_file_record_batch(
1793
1828
  commit_ids.push(file.live.commit_id);
1794
1829
  untracked_values.push(Some(file.live.untracked));
1795
1830
  metadata_values.push(file.live.metadata.as_ref().map(serialize_row_metadata));
1796
- version_ids.push(Some(version_id));
1831
+ branch_ids.push(Some(branch_id));
1797
1832
  }
1798
1833
 
1799
1834
  let mut columns = Vec::<ArrayRef>::with_capacity(schema.fields().len());
@@ -1810,7 +1845,7 @@ async fn lix_file_record_batch(
1810
1845
  .map(|value| value.as_deref())
1811
1846
  .collect::<Vec<_>>(),
1812
1847
  )),
1813
- "lixcol_entity_id" => Arc::new(StringArray::from(entity_ids.clone())),
1848
+ "lixcol_entity_pk" => Arc::new(StringArray::from(entity_pks.clone())),
1814
1849
  "lixcol_schema_key" => Arc::new(StringArray::from(schema_keys.clone())),
1815
1850
  "lixcol_file_id" => Arc::new(StringArray::from(file_ids.clone())),
1816
1851
  "lixcol_global" => Arc::new(BooleanArray::from(globals.clone())),
@@ -1820,7 +1855,7 @@ async fn lix_file_record_batch(
1820
1855
  "lixcol_commit_id" => Arc::new(StringArray::from(commit_ids.clone())),
1821
1856
  "lixcol_untracked" => Arc::new(BooleanArray::from(untracked_values.clone())),
1822
1857
  "lixcol_metadata" => Arc::new(StringArray::from(metadata_values.clone())),
1823
- "lixcol_version_id" => Arc::new(StringArray::from(version_ids.clone())),
1858
+ "lixcol_branch_id" => Arc::new(StringArray::from(branch_ids.clone())),
1824
1859
  other => {
1825
1860
  return Err(LixError::new(
1826
1861
  "LIX_ERROR_UNKNOWN",
@@ -1857,19 +1892,19 @@ async fn load_single_blob_bytes(
1857
1892
  fn derive_directory_paths(
1858
1893
  rows: &[DirectoryDescriptorRecord],
1859
1894
  ) -> Result<BTreeMap<(String, String), String>, LixError> {
1860
- let mut by_version = BTreeMap::<String, BTreeMap<String, &DirectoryDescriptorRecord>>::new();
1895
+ let mut by_branch = BTreeMap::<String, BTreeMap<String, &DirectoryDescriptorRecord>>::new();
1861
1896
  for row in rows {
1862
- by_version
1863
- .entry(row.version_id.clone())
1897
+ by_branch
1898
+ .entry(row.branch_id.clone())
1864
1899
  .or_default()
1865
1900
  .insert(row.id.clone(), row);
1866
1901
  }
1867
1902
 
1868
1903
  let mut paths = BTreeMap::<(String, String), String>::new();
1869
- for (version_id, records) in by_version {
1904
+ for (branch_id, records) in by_branch {
1870
1905
  for directory_id in records.keys() {
1871
1906
  derive_directory_path_for(
1872
- &version_id,
1907
+ &branch_id,
1873
1908
  directory_id,
1874
1909
  &records,
1875
1910
  &mut paths,
@@ -1881,17 +1916,17 @@ fn derive_directory_paths(
1881
1916
  }
1882
1917
 
1883
1918
  fn derive_directory_path_for(
1884
- version_id: &str,
1919
+ branch_id: &str,
1885
1920
  directory_id: &str,
1886
1921
  records: &BTreeMap<String, &DirectoryDescriptorRecord>,
1887
1922
  paths: &mut BTreeMap<(String, String), String>,
1888
1923
  visiting: &mut BTreeSet<String>,
1889
1924
  ) -> Result<Option<String>, LixError> {
1890
- if let Some(path) = paths.get(&(version_id.to_string(), directory_id.to_string())) {
1925
+ if let Some(path) = paths.get(&(branch_id.to_string(), directory_id.to_string())) {
1891
1926
  return Ok(Some(path.clone()));
1892
1927
  }
1893
1928
  if !visiting.insert(directory_id.to_string()) {
1894
- return Err(directory_parent_cycle_error(version_id, directory_id));
1929
+ return Err(directory_parent_cycle_error(branch_id, directory_id));
1895
1930
  }
1896
1931
  let Some(row) = records.get(directory_id) else {
1897
1932
  visiting.remove(directory_id);
@@ -1900,7 +1935,7 @@ fn derive_directory_path_for(
1900
1935
  let path = match row.parent_id.as_deref() {
1901
1936
  Some(parent_id) => {
1902
1937
  let Some(parent_path) =
1903
- derive_directory_path_for(version_id, parent_id, records, paths, visiting)?
1938
+ derive_directory_path_for(branch_id, parent_id, records, paths, visiting)?
1904
1939
  else {
1905
1940
  visiting.remove(directory_id);
1906
1941
  return Ok(None);
@@ -1911,17 +1946,17 @@ fn derive_directory_path_for(
1911
1946
  };
1912
1947
  visiting.remove(directory_id);
1913
1948
  paths.insert(
1914
- (version_id.to_string(), directory_id.to_string()),
1949
+ (branch_id.to_string(), directory_id.to_string()),
1915
1950
  path.clone(),
1916
1951
  );
1917
1952
  Ok(Some(path))
1918
1953
  }
1919
1954
 
1920
- fn directory_parent_cycle_error(version_id: &str, directory_id: &str) -> LixError {
1955
+ fn directory_parent_cycle_error(branch_id: &str, directory_id: &str) -> LixError {
1921
1956
  LixError::new(
1922
1957
  LixError::CODE_CONSTRAINT_VIOLATION,
1923
1958
  format!(
1924
- "lix_directory_descriptor parent_id cycle in version '{version_id}' while resolving directory '{directory_id}'"
1959
+ "lix_directory_descriptor parent_id cycle in branch '{branch_id}' while resolving directory '{directory_id}'"
1925
1960
  ),
1926
1961
  )
1927
1962
  }
@@ -1942,7 +1977,7 @@ fn projected_schema(base_schema: &SchemaRef, projection: Option<&Vec<usize>>) ->
1942
1977
  }
1943
1978
 
1944
1979
  fn lix_file_scan_request(
1945
- version_binding: Option<&str>,
1980
+ branch_binding: Option<&str>,
1946
1981
  projected_schema: Option<&Schema>,
1947
1982
  limit: Option<usize>,
1948
1983
  ) -> LiveStateScanRequest {
@@ -1953,8 +1988,8 @@ fn lix_file_scan_request(
1953
1988
  BLOB_REF_SCHEMA_KEY.to_string(),
1954
1989
  DIRECTORY_DESCRIPTOR_SCHEMA_KEY.to_string(),
1955
1990
  ],
1956
- version_ids: version_binding
1957
- .map(|version_id| vec![version_id.to_string()])
1991
+ branch_ids: branch_binding
1992
+ .map(|branch_id| vec![branch_id.to_string()])
1958
1993
  .unwrap_or_default(),
1959
1994
  ..LiveStateFilter::default()
1960
1995
  },
@@ -2003,16 +2038,16 @@ async fn scan_lix_file_live_rows(
2003
2038
  FILE_DESCRIPTOR_SCHEMA_KEY.to_string(),
2004
2039
  BLOB_REF_SCHEMA_KEY.to_string(),
2005
2040
  ];
2006
- file_request.filter.entity_ids = target_file_ids
2041
+ file_request.filter.entity_pks = target_file_ids
2007
2042
  .iter()
2008
- .map(|file_id| EntityIdentity::single(file_id.clone()))
2043
+ .map(|file_id| EntityPk::single(file_id.clone()))
2009
2044
  .collect();
2010
2045
 
2011
2046
  let mut rows = live_state.scan_rows(&file_request).await?;
2012
2047
 
2013
2048
  let mut directory_request = request.clone();
2014
2049
  directory_request.filter.schema_keys = vec![DIRECTORY_DESCRIPTOR_SCHEMA_KEY.to_string()];
2015
- directory_request.filter.entity_ids.clear();
2050
+ directory_request.filter.entity_pks.clear();
2016
2051
  directory_request.limit = None;
2017
2052
  rows.extend(live_state.scan_rows(&directory_request).await?);
2018
2053
 
@@ -2400,9 +2435,9 @@ fn update_optional_metadata_value(
2400
2435
  update_optional_string_value(batch, assignment_values, row_index, column_name)?
2401
2436
  .map(|value| {
2402
2437
  let metadata = parse_row_metadata_value(&value, context)
2403
- .map_err(super::error::lix_error_to_datafusion_error)?;
2438
+ .map_err(crate::sql2::error::lix_error_to_datafusion_error)?;
2404
2439
  TransactionJson::from_value(metadata, &format!("{context} metadata"))
2405
- .map_err(super::error::lix_error_to_datafusion_error)
2440
+ .map_err(crate::sql2::error::lix_error_to_datafusion_error)
2406
2441
  })
2407
2442
  .transpose()
2408
2443
  }
@@ -2479,9 +2514,9 @@ fn optional_metadata_value(
2479
2514
  optional_string_value(batch, row_index, column_name)?
2480
2515
  .map(|value| {
2481
2516
  let metadata = parse_row_metadata_value(&value, context)
2482
- .map_err(super::error::lix_error_to_datafusion_error)?;
2517
+ .map_err(crate::sql2::error::lix_error_to_datafusion_error)?;
2483
2518
  TransactionJson::from_value(metadata, &format!("{context} metadata"))
2484
- .map_err(super::error::lix_error_to_datafusion_error)
2519
+ .map_err(crate::sql2::error::lix_error_to_datafusion_error)
2485
2520
  })
2486
2521
  .transpose()
2487
2522
  }
@@ -2553,7 +2588,7 @@ fn optional_scalar_value(
2553
2588
  })
2554
2589
  }
2555
2590
 
2556
- fn lix_file_schema() -> SchemaRef {
2591
+ pub(super) fn lix_file_schema() -> SchemaRef {
2557
2592
  Arc::new(Schema::new(vec![
2558
2593
  Field::new("id", DataType::Utf8, true),
2559
2594
  Field::new("path", DataType::Utf8, false),
@@ -2561,7 +2596,7 @@ fn lix_file_schema() -> SchemaRef {
2561
2596
  Field::new("name", DataType::Utf8, false),
2562
2597
  Field::new("hidden", DataType::Boolean, true),
2563
2598
  Field::new("data", DataType::Binary, true),
2564
- json_field("lixcol_entity_id", false),
2599
+ json_field("lixcol_entity_pk", false),
2565
2600
  Field::new("lixcol_schema_key", DataType::Utf8, false),
2566
2601
  Field::new("lixcol_file_id", DataType::Utf8, true),
2567
2602
  Field::new("lixcol_global", DataType::Boolean, true),
@@ -2574,22 +2609,22 @@ fn lix_file_schema() -> SchemaRef {
2574
2609
  ]))
2575
2610
  }
2576
2611
 
2577
- fn lix_file_by_version_schema() -> SchemaRef {
2612
+ pub(super) fn lix_file_by_branch_schema() -> SchemaRef {
2578
2613
  let mut fields = lix_file_schema()
2579
2614
  .fields()
2580
2615
  .iter()
2581
2616
  .map(|field| field.as_ref().clone())
2582
2617
  .collect::<Vec<_>>();
2583
- fields.push(Field::new("lixcol_version_id", DataType::Utf8, false));
2618
+ fields.push(Field::new("lixcol_branch_id", DataType::Utf8, false));
2584
2619
  Arc::new(Schema::new(fields))
2585
2620
  }
2586
2621
 
2587
2622
  fn datafusion_error_to_lix_error(error: DataFusionError) -> LixError {
2588
- super::error::datafusion_error_to_lix_error(error)
2623
+ crate::sql2::error::datafusion_error_to_lix_error(error)
2589
2624
  }
2590
2625
 
2591
2626
  fn lix_error_to_datafusion_error(error: LixError) -> DataFusionError {
2592
- super::error::lix_error_to_datafusion_error(error)
2627
+ crate::sql2::error::lix_error_to_datafusion_error(error)
2593
2628
  }
2594
2629
 
2595
2630
  #[cfg(test)]
@@ -2624,8 +2659,8 @@ mod tests {
2624
2659
  use super::{
2625
2660
  derive_directory_path_for, lix_file_delete_stage_from_batch,
2626
2661
  lix_file_insert_stage_from_batch, lix_file_insert_stage_from_batch_with_path_resolvers,
2627
- lix_file_write_rows_from_batch, DirectoryDescriptorRecord, LixFileInsertSink,
2628
- VersionBinding,
2662
+ lix_file_write_rows_from_batch, BranchBinding, DirectoryDescriptorRecord,
2663
+ LixFileInsertSink,
2629
2664
  };
2630
2665
 
2631
2666
  fn test_id_generator(ids: &'static [&'static str]) -> impl FnMut() -> String {
@@ -2755,7 +2790,7 @@ mod tests {
2755
2790
 
2756
2791
  fn lix_file_update_stage_from_batch_for_test(
2757
2792
  batch: &RecordBatch,
2758
- version_binding: Option<&str>,
2793
+ branch_binding: Option<&str>,
2759
2794
  update_columns: super::LixFileUpdateColumns,
2760
2795
  path_resolvers: Option<&mut BTreeMap<String, super::DirectoryPathResolver>>,
2761
2796
  generate_directory_id: &mut dyn FnMut() -> String,
@@ -2774,7 +2809,7 @@ mod tests {
2774
2809
  super::lix_file_update_stage_from_batch(
2775
2810
  batch,
2776
2811
  &assignment_values,
2777
- version_binding,
2812
+ branch_binding,
2778
2813
  update_columns,
2779
2814
  path_resolvers,
2780
2815
  generate_directory_id,
@@ -2802,8 +2837,8 @@ mod tests {
2802
2837
 
2803
2838
  #[async_trait]
2804
2839
  impl SqlWriteExecutionContext for CapturingWriteContext {
2805
- fn active_version_id(&self) -> &str {
2806
- "version-b"
2840
+ fn active_branch_id(&self) -> &str {
2841
+ "branch-b"
2807
2842
  }
2808
2843
 
2809
2844
  fn functions(&self) -> FunctionProviderHandle {
@@ -2828,14 +2863,11 @@ mod tests {
2828
2863
  Ok(self.rows.clone())
2829
2864
  }
2830
2865
 
2831
- async fn load_version_head(
2832
- &mut self,
2833
- version_id: &str,
2834
- ) -> Result<Option<String>, LixError> {
2835
- if version_id == "ghost-version" {
2866
+ async fn load_branch_head(&mut self, branch_id: &str) -> Result<Option<String>, LixError> {
2867
+ if branch_id == "ghost-branch" {
2836
2868
  return Ok(None);
2837
2869
  }
2838
- Ok(Some(format!("commit-{version_id}")))
2870
+ Ok(Some(format!("commit-{branch_id}")))
2839
2871
  }
2840
2872
 
2841
2873
  async fn stage_write(
@@ -2870,20 +2902,20 @@ mod tests {
2870
2902
  }
2871
2903
 
2872
2904
  fn live_directory_row(
2873
- entity_id: &str,
2874
- version_id: &str,
2905
+ entity_pk: &str,
2906
+ branch_id: &str,
2875
2907
  snapshot_content: &str,
2876
2908
  ) -> MaterializedLiveStateRow {
2877
2909
  MaterializedLiveStateRow {
2878
- entity_id: crate::entity_identity::EntityIdentity::single(entity_id),
2910
+ entity_pk: crate::entity_pk::EntityPk::single(entity_pk),
2879
2911
  schema_key: super::DIRECTORY_DESCRIPTOR_SCHEMA_KEY.to_string(),
2880
2912
  file_id: None,
2881
2913
  snapshot_content: Some(snapshot_content.to_string()),
2882
2914
  metadata: None,
2883
2915
  deleted: false,
2884
- version_id: version_id.to_string(),
2885
- change_id: Some(format!("change-{entity_id}")),
2886
- commit_id: Some(format!("commit-{entity_id}")),
2916
+ branch_id: branch_id.to_string(),
2917
+ change_id: Some(format!("change-{entity_pk}")),
2918
+ commit_id: Some(format!("commit-{entity_pk}")),
2887
2919
  global: false,
2888
2920
  untracked: false,
2889
2921
  created_at: "2026-04-23T00:00:00Z".to_string(),
@@ -2892,20 +2924,20 @@ mod tests {
2892
2924
  }
2893
2925
 
2894
2926
  fn live_file_row(
2895
- entity_id: &str,
2896
- version_id: &str,
2927
+ entity_pk: &str,
2928
+ branch_id: &str,
2897
2929
  snapshot_content: &str,
2898
2930
  ) -> MaterializedLiveStateRow {
2899
2931
  MaterializedLiveStateRow {
2900
- entity_id: crate::entity_identity::EntityIdentity::single(entity_id),
2932
+ entity_pk: crate::entity_pk::EntityPk::single(entity_pk),
2901
2933
  schema_key: super::FILE_DESCRIPTOR_SCHEMA_KEY.to_string(),
2902
2934
  file_id: None,
2903
2935
  snapshot_content: Some(snapshot_content.to_string()),
2904
2936
  metadata: None,
2905
2937
  deleted: false,
2906
- version_id: version_id.to_string(),
2907
- change_id: Some(format!("change-{entity_id}")),
2908
- commit_id: Some(format!("commit-{entity_id}")),
2938
+ branch_id: branch_id.to_string(),
2939
+ change_id: Some(format!("change-{entity_pk}")),
2940
+ commit_id: Some(format!("commit-{entity_pk}")),
2909
2941
  global: false,
2910
2942
  untracked: false,
2911
2943
  created_at: "2026-04-23T00:00:00Z".to_string(),
@@ -2917,7 +2949,7 @@ mod tests {
2917
2949
  Arc::new(StringArray::from(values)) as ArrayRef
2918
2950
  }
2919
2951
 
2920
- fn file_insert_batch(include_version: bool, global: bool) -> RecordBatch {
2952
+ fn file_insert_batch(include_branch: bool, global: bool) -> RecordBatch {
2921
2953
  let mut fields = vec![
2922
2954
  Field::new("id", DataType::Utf8, false),
2923
2955
  Field::new("directory_id", DataType::Utf8, true),
@@ -2934,9 +2966,9 @@ mod tests {
2934
2966
  Arc::new(BooleanArray::from(vec![global])) as ArrayRef,
2935
2967
  string_column(vec![Some("{\"source\":\"file\"}")]),
2936
2968
  ];
2937
- if include_version {
2938
- fields.push(Field::new("lixcol_version_id", DataType::Utf8, false));
2939
- columns.push(string_column(vec![Some("version-b")]));
2969
+ if include_branch {
2970
+ fields.push(Field::new("lixcol_branch_id", DataType::Utf8, false));
2971
+ columns.push(string_column(vec![Some("branch-b")]));
2940
2972
  }
2941
2973
  RecordBatch::try_new(Arc::new(Schema::new(fields)), columns).expect("file insert batch")
2942
2974
  }
@@ -2949,7 +2981,7 @@ mod tests {
2949
2981
  Field::new("name", DataType::Utf8, false),
2950
2982
  Field::new("hidden", DataType::Boolean, false),
2951
2983
  Field::new("data", DataType::Binary, true),
2952
- Field::new("lixcol_version_id", DataType::Utf8, false),
2984
+ Field::new("lixcol_branch_id", DataType::Utf8, false),
2953
2985
  ])),
2954
2986
  vec![
2955
2987
  string_column(vec![Some("file-readme")]),
@@ -2957,7 +2989,7 @@ mod tests {
2957
2989
  string_column(vec![Some("readme.md")]),
2958
2990
  Arc::new(BooleanArray::from(vec![false])) as ArrayRef,
2959
2991
  Arc::new(BinaryArray::from_vec(vec![b"hello"])) as ArrayRef,
2960
- string_column(vec![Some("version-b")]),
2992
+ string_column(vec![Some("branch-b")]),
2961
2993
  ],
2962
2994
  )
2963
2995
  .expect("file data batch")
@@ -2970,14 +3002,14 @@ mod tests {
2970
3002
  Field::new("path", DataType::Utf8, false),
2971
3003
  Field::new("hidden", DataType::Boolean, false),
2972
3004
  Field::new("data", DataType::Binary, true),
2973
- Field::new("lixcol_version_id", DataType::Utf8, false),
3005
+ Field::new("lixcol_branch_id", DataType::Utf8, false),
2974
3006
  ])),
2975
3007
  vec![
2976
3008
  string_column(vec![Some("file-readme")]),
2977
3009
  string_column(vec![Some("/docs/guides/readme.md")]),
2978
3010
  Arc::new(BooleanArray::from(vec![false])) as ArrayRef,
2979
3011
  Arc::new(BinaryArray::from_vec(vec![b"hello"])) as ArrayRef,
2980
- string_column(vec![Some("version-b")]),
3012
+ string_column(vec![Some("branch-b")]),
2981
3013
  ],
2982
3014
  )
2983
3015
  .expect("file path data batch")
@@ -2990,14 +3022,14 @@ mod tests {
2990
3022
  Field::new("path", DataType::Utf8, false),
2991
3023
  Field::new("hidden", DataType::Boolean, false),
2992
3024
  Field::new("data", DataType::Binary, true),
2993
- Field::new("lixcol_version_id", DataType::Utf8, false),
3025
+ Field::new("lixcol_branch_id", DataType::Utf8, false),
2994
3026
  ])),
2995
3027
  vec![
2996
3028
  string_column(vec![Some("file-readme")]),
2997
3029
  string_column(vec![Some("/docs/renamed.md")]),
2998
3030
  Arc::new(BooleanArray::from(vec![false])) as ArrayRef,
2999
3031
  Arc::new(BinaryArray::from_vec(vec![b"hello"])) as ArrayRef,
3000
- string_column(vec![Some("version-b")]),
3032
+ string_column(vec![Some("branch-b")]),
3001
3033
  ],
3002
3034
  )
3003
3035
  .expect("file path update batch")
@@ -3007,11 +3039,11 @@ mod tests {
3007
3039
  RecordBatch::try_new(
3008
3040
  Arc::new(Schema::new(vec![
3009
3041
  Field::new("id", DataType::Utf8, false),
3010
- Field::new("lixcol_version_id", DataType::Utf8, false),
3042
+ Field::new("lixcol_branch_id", DataType::Utf8, false),
3011
3043
  ])),
3012
3044
  vec![
3013
3045
  string_column(vec![Some("file-readme")]),
3014
- string_column(vec![Some("version-b")]),
3046
+ string_column(vec![Some("branch-b")]),
3015
3047
  ],
3016
3048
  )
3017
3049
  .expect("file delete batch")
@@ -3023,13 +3055,13 @@ mod tests {
3023
3055
  id: "dir-docs".to_string(),
3024
3056
  parent_id: None,
3025
3057
  name: "docs".to_string(),
3026
- version_id: "version-a".to_string(),
3058
+ branch_id: "branch-a".to_string(),
3027
3059
  };
3028
3060
  let child = DirectoryDescriptorRecord {
3029
3061
  id: "dir-guides".to_string(),
3030
3062
  parent_id: Some("dir-docs".to_string()),
3031
3063
  name: "guides".to_string(),
3032
- version_id: "version-a".to_string(),
3064
+ branch_id: "branch-a".to_string(),
3033
3065
  };
3034
3066
  let mut records = BTreeMap::new();
3035
3067
  records.insert(root.id.clone(), &root);
@@ -3038,7 +3070,7 @@ mod tests {
3038
3070
 
3039
3071
  assert_eq!(
3040
3072
  derive_directory_path_for(
3041
- "version-a",
3073
+ "branch-a",
3042
3074
  "dir-guides",
3043
3075
  &records,
3044
3076
  &mut paths,
@@ -3057,7 +3089,7 @@ mod tests {
3057
3089
  &blob_reader,
3058
3090
  vec![live_file_row(
3059
3091
  "file-readme",
3060
- "version-b",
3092
+ "branch-b",
3061
3093
  "{\"id\":\"file-readme\",\"directory_id\":\"missing-dir\",\"name\":\"readme.md\",\"hidden\":false}",
3062
3094
  )],
3063
3095
  )
@@ -3076,13 +3108,11 @@ mod tests {
3076
3108
 
3077
3109
  assert_eq!(rows.len(), 1);
3078
3110
  assert_eq!(
3079
- rows[0].entity_id.as_ref(),
3080
- Some(&crate::entity_identity::EntityIdentity::single(
3081
- "file-readme"
3082
- ))
3111
+ rows[0].entity_pk.as_ref(),
3112
+ Some(&crate::entity_pk::EntityPk::single("file-readme"))
3083
3113
  );
3084
3114
  assert_eq!(rows[0].schema_key, "lix_file_descriptor");
3085
- assert_eq!(rows[0].version_id, "version-b");
3115
+ assert_eq!(rows[0].branch_id, "branch-b");
3086
3116
  assert_eq!(
3087
3117
  rows[0].metadata.as_ref(),
3088
3118
  Some(&TransactionJson::from_value_for_test(
@@ -3097,38 +3127,38 @@ mod tests {
3097
3127
  }
3098
3128
 
3099
3129
  #[test]
3100
- fn active_file_insert_defaults_version_id() {
3130
+ fn active_file_insert_defaults_branch_id() {
3101
3131
  let batch = file_insert_batch(false, false);
3102
3132
 
3103
3133
  let rows =
3104
- lix_file_write_rows_from_batch(&batch, Some("version-a")).expect("decode file insert");
3134
+ lix_file_write_rows_from_batch(&batch, Some("branch-a")).expect("decode file insert");
3105
3135
 
3106
3136
  assert_eq!(rows.len(), 1);
3107
- assert_eq!(rows[0].version_id, "version-a");
3137
+ assert_eq!(rows[0].branch_id, "branch-a");
3108
3138
  }
3109
3139
 
3110
3140
  #[test]
3111
- fn by_version_file_insert_requires_version_id_for_non_global_rows() {
3141
+ fn by_branch_file_insert_requires_branch_id_for_non_global_rows() {
3112
3142
  let batch = file_insert_batch(false, false);
3113
3143
 
3114
3144
  let error =
3115
- lix_file_write_rows_from_batch(&batch, None).expect_err("version id is required");
3145
+ lix_file_write_rows_from_batch(&batch, None).expect_err("branch id is required");
3116
3146
 
3117
3147
  assert!(
3118
- error.to_string().contains("requires lixcol_version_id"),
3148
+ error.to_string().contains("requires lixcol_branch_id"),
3119
3149
  "unexpected error: {error}"
3120
3150
  );
3121
3151
  }
3122
3152
 
3123
3153
  #[test]
3124
- fn file_insert_rejects_global_with_non_global_version_id() {
3154
+ fn file_insert_rejects_global_with_non_global_branch_id() {
3125
3155
  let error = lix_file_write_rows_from_batch(&file_insert_batch(true, true), None)
3126
- .expect_err("global file write should reject conflicting version id");
3156
+ .expect_err("global file write should reject conflicting branch id");
3127
3157
 
3128
3158
  assert!(
3129
3159
  error
3130
3160
  .to_string()
3131
- .contains("cannot set lixcol_global=true with non-global lixcol_version_id"),
3161
+ .contains("cannot set lixcol_global=true with non-global lixcol_branch_id"),
3132
3162
  "unexpected error: {error}"
3133
3163
  );
3134
3164
  }
@@ -3146,7 +3176,7 @@ mod tests {
3146
3176
  fn file_path_update_stages_descriptor_from_new_path() {
3147
3177
  let mut resolvers = BTreeMap::new();
3148
3178
  resolvers.insert(
3149
- super::filesystem_storage_scope_key("version-b", false, false, None),
3179
+ super::filesystem_storage_scope_key("branch-b", false, false, None),
3150
3180
  super::DirectoryPathResolver::from_existing([(
3151
3181
  "/docs/".to_string(),
3152
3182
  "dir-docs".to_string(),
@@ -3186,7 +3216,7 @@ mod tests {
3186
3216
  fn file_path_update_preserves_existing_data_unless_data_is_assigned() {
3187
3217
  let mut resolvers = BTreeMap::new();
3188
3218
  resolvers.insert(
3189
- super::filesystem_storage_scope_key("version-b", false, false, None),
3219
+ super::filesystem_storage_scope_key("branch-b", false, false, None),
3190
3220
  super::DirectoryPathResolver::from_existing([(
3191
3221
  "/docs/".to_string(),
3192
3222
  "dir-docs".to_string(),
@@ -3226,11 +3256,11 @@ mod tests {
3226
3256
  Arc::new(RowsLiveStateReader {
3227
3257
  rows: vec![live_directory_row(
3228
3258
  "dir-docs",
3229
- "version-b",
3259
+ "branch-b",
3230
3260
  "{\"id\":\"dir-docs\",\"parent_id\":null,\"name\":\"docs\"}",
3231
3261
  )],
3232
3262
  }) as Arc<dyn LiveStateReader>,
3233
- Some("version-b"),
3263
+ Some("branch-b"),
3234
3264
  )
3235
3265
  .await
3236
3266
  .expect("directory state should seed path resolver");
@@ -3269,7 +3299,7 @@ mod tests {
3269
3299
  async fn file_path_update_stages_only_missing_parent_directories() {
3270
3300
  let mut resolvers = super::file_path_resolvers_from_live_state(
3271
3301
  Arc::new(RowsLiveStateReader::default()) as Arc<dyn LiveStateReader>,
3272
- Some("version-b"),
3302
+ Some("branch-b"),
3273
3303
  )
3274
3304
  .await
3275
3305
  .expect("empty directory state should seed path resolver");
@@ -3304,10 +3334,8 @@ mod tests {
3304
3334
  .find(|row| row.schema_key == "lix_directory_descriptor")
3305
3335
  .expect("missing /docs/ directory should be staged");
3306
3336
  assert_eq!(
3307
- directory.entity_id.as_ref(),
3308
- Some(&crate::entity_identity::EntityIdentity::single(
3309
- "dir-generated-docs"
3310
- ))
3337
+ directory.entity_pk.as_ref(),
3338
+ Some(&crate::entity_pk::EntityPk::single("dir-generated-docs"))
3311
3339
  );
3312
3340
 
3313
3341
  let descriptor = staged
@@ -3323,7 +3351,7 @@ mod tests {
3323
3351
  fn file_path_update_with_data_assignment_stages_blob_ref_and_payload() {
3324
3352
  let mut resolvers = BTreeMap::new();
3325
3353
  resolvers.insert(
3326
- super::filesystem_storage_scope_key("version-b", false, false, None),
3354
+ super::filesystem_storage_scope_key("branch-b", false, false, None),
3327
3355
  super::DirectoryPathResolver::from_existing([(
3328
3356
  "/docs/".to_string(),
3329
3357
  "dir-docs".to_string(),
@@ -3398,15 +3426,13 @@ mod tests {
3398
3426
  .find(|row| row.schema_key == "lix_binary_blob_ref")
3399
3427
  .expect("data insert should stage blob ref row");
3400
3428
  assert_eq!(
3401
- blob_ref_row.entity_id.as_ref(),
3402
- Some(&crate::entity_identity::EntityIdentity::single(
3403
- "file-readme"
3404
- ))
3429
+ blob_ref_row.entity_pk.as_ref(),
3430
+ Some(&crate::entity_pk::EntityPk::single("file-readme"))
3405
3431
  );
3406
3432
  assert_eq!(blob_ref_row.file_id.as_deref(), Some("file-readme"));
3407
3433
  assert_eq!(staged.file_data_writes.len(), 1);
3408
3434
  assert_eq!(staged.file_data_writes[0].file_id, "file-readme");
3409
- assert_eq!(staged.file_data_writes[0].version_id, "version-b");
3435
+ assert_eq!(staged.file_data_writes[0].branch_id, "branch-b");
3410
3436
  assert_eq!(staged.file_data_writes[0].data, b"hello");
3411
3437
  }
3412
3438
 
@@ -3428,10 +3454,8 @@ mod tests {
3428
3454
  .find(|row| row.schema_key == "lix_file_descriptor")
3429
3455
  .expect("file descriptor tombstone should be staged");
3430
3456
  assert_eq!(
3431
- descriptor.entity_id.as_ref(),
3432
- Some(&crate::entity_identity::EntityIdentity::single(
3433
- "file-readme"
3434
- ))
3457
+ descriptor.entity_pk.as_ref(),
3458
+ Some(&crate::entity_pk::EntityPk::single("file-readme"))
3435
3459
  );
3436
3460
  assert_eq!(descriptor.file_id, None);
3437
3461
  assert_eq!(descriptor.snapshot, None);
@@ -3442,10 +3466,8 @@ mod tests {
3442
3466
  .find(|row| row.schema_key == "lix_binary_blob_ref")
3443
3467
  .expect("blob ref tombstone should be staged");
3444
3468
  assert_eq!(
3445
- blob_ref.entity_id.as_ref(),
3446
- Some(&crate::entity_identity::EntityIdentity::single(
3447
- "file-readme"
3448
- ))
3469
+ blob_ref.entity_pk.as_ref(),
3470
+ Some(&crate::entity_pk::EntityPk::single("file-readme"))
3449
3471
  );
3450
3472
  assert_eq!(blob_ref.file_id.as_deref(), Some("file-readme"));
3451
3473
  assert_eq!(blob_ref.snapshot, None);
@@ -3461,10 +3483,8 @@ mod tests {
3461
3483
  assert_eq!(staged.state_rows.len(), 1);
3462
3484
  assert_eq!(staged.state_rows[0].schema_key, "lix_file_descriptor");
3463
3485
  assert_eq!(
3464
- staged.state_rows[0].entity_id.as_ref(),
3465
- Some(&crate::entity_identity::EntityIdentity::single(
3466
- "file-readme"
3467
- ))
3486
+ staged.state_rows[0].entity_pk.as_ref(),
3487
+ Some(&crate::entity_pk::EntityPk::single("file-readme"))
3468
3488
  );
3469
3489
  assert_eq!(staged.state_rows[0].snapshot, None);
3470
3490
  }
@@ -3473,7 +3493,7 @@ mod tests {
3473
3493
  fn file_path_insert_reuses_existing_parent_directory() {
3474
3494
  let mut resolvers = BTreeMap::new();
3475
3495
  resolvers.insert(
3476
- super::filesystem_storage_scope_key("version-b", false, false, None),
3496
+ super::filesystem_storage_scope_key("branch-b", false, false, None),
3477
3497
  super::DirectoryPathResolver::from_existing([
3478
3498
  ("/docs/".to_string(), "dir-docs".to_string()),
3479
3499
  ("/docs/guides/".to_string(), "dir-guides".to_string()),
@@ -3544,10 +3564,9 @@ mod tests {
3544
3564
  let mut write_context = CapturingWriteContext::default();
3545
3565
  let write_ctx = SqlWriteContext::new(&mut write_context);
3546
3566
  let sink = LixFileInsertSink::new(
3547
- batch.schema(),
3548
3567
  write_ctx,
3549
3568
  test_functions(),
3550
- VersionBinding::explicit(),
3569
+ BranchBinding::explicit(),
3551
3570
  false,
3552
3571
  );
3553
3572
 
@@ -3564,10 +3583,8 @@ mod tests {
3564
3583
  assert_eq!(*mode, TransactionWriteMode::Insert);
3565
3584
  assert_eq!(rows.len(), 1);
3566
3585
  assert_eq!(
3567
- rows[0].entity_id.as_ref(),
3568
- Some(&crate::entity_identity::EntityIdentity::single(
3569
- "file-readme"
3570
- ))
3586
+ rows[0].entity_pk.as_ref(),
3587
+ Some(&crate::entity_pk::EntityPk::single("file-readme"))
3571
3588
  );
3572
3589
  assert_eq!(rows[0].schema_key, "lix_file_descriptor");
3573
3590
  }
@@ -3580,13 +3597,8 @@ mod tests {
3580
3597
  let batch = data_insert_batch();
3581
3598
  let mut write_context = CapturingWriteContext::default();
3582
3599
  let write_ctx = SqlWriteContext::new(&mut write_context);
3583
- let sink = LixFileInsertSink::new(
3584
- batch.schema(),
3585
- write_ctx,
3586
- test_functions(),
3587
- VersionBinding::explicit(),
3588
- true,
3589
- );
3600
+ let sink =
3601
+ LixFileInsertSink::new(write_ctx, test_functions(), BranchBinding::explicit(), true);
3590
3602
 
3591
3603
  let count = sink
3592
3604
  .write_batches(vec![batch], &Arc::new(TaskContext::default()))
@@ -3628,25 +3640,20 @@ mod tests {
3628
3640
  rows: vec![
3629
3641
  live_directory_row(
3630
3642
  "dir-docs",
3631
- "version-b",
3643
+ "branch-b",
3632
3644
  "{\"id\":\"dir-docs\",\"parent_id\":null,\"name\":\"docs\"}",
3633
3645
  ),
3634
3646
  live_directory_row(
3635
3647
  "dir-guides",
3636
- "version-b",
3648
+ "branch-b",
3637
3649
  "{\"id\":\"dir-guides\",\"parent_id\":\"dir-docs\",\"name\":\"guides\"}",
3638
3650
  ),
3639
3651
  ],
3640
3652
  writes: Vec::new(),
3641
3653
  };
3642
3654
  let write_ctx = SqlWriteContext::new(&mut write_context);
3643
- let sink = LixFileInsertSink::new(
3644
- batch.schema(),
3645
- write_ctx,
3646
- test_functions(),
3647
- VersionBinding::explicit(),
3648
- true,
3649
- );
3655
+ let sink =
3656
+ LixFileInsertSink::new(write_ctx, test_functions(), BranchBinding::explicit(), true);
3650
3657
 
3651
3658
  let count = sink
3652
3659
  .write_batches(vec![batch], &Arc::new(TaskContext::default()))