@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
@@ -2,10 +2,8 @@ mod context;
2
2
  mod types;
3
3
  mod walker;
4
4
 
5
- #[allow(unused_imports)]
6
5
  pub(crate) use context::{CommitGraphContext, CommitGraphStoreReader};
7
- #[allow(unused_imports)]
8
6
  pub(crate) use types::{
9
- CommitGraphChangeHistoryEntry, CommitGraphChangeHistoryRequest, CommitGraphCommit,
10
- CommitGraphEdge, CommitGraphReader, ReachableCommitGraphCommit,
7
+ CommitGraphChange, CommitGraphChangeHistoryEntry, CommitGraphChangeHistoryRequest,
8
+ CommitGraphCommit, CommitGraphEdge, CommitGraphReader, ReachableCommitGraphCommit,
11
9
  };
@@ -1,18 +1,28 @@
1
- use crate::commit_store::{Change, LocatedChange};
2
- use crate::entity_identity::EntityIdentity;
1
+ use crate::entity_pk::EntityPk;
2
+ use crate::json_store::JsonRef;
3
3
  use crate::LixError;
4
4
 
5
+ #[derive(Debug, Clone, PartialEq, Eq)]
6
+ pub(crate) struct CommitGraphChange {
7
+ pub(crate) id: String,
8
+ pub(crate) entity_pk: EntityPk,
9
+ pub(crate) schema_key: String,
10
+ pub(crate) file_id: Option<String>,
11
+ pub(crate) snapshot_ref: Option<JsonRef>,
12
+ pub(crate) metadata_ref: Option<JsonRef>,
13
+ pub(crate) created_at: String,
14
+ }
15
+
5
16
  /// Parsed `lix_commit` entity from the changelog.
6
17
  ///
7
- /// Commits are stored as ordinary canonical changes. The graph reader parses
8
- /// their snapshot so traversal code can work with explicit parent ids and the
9
- /// ordered canonical changes introduced relative to the first parent. A merge
10
- /// commit may reference existing changes from another parent instead of owning
11
- /// newly minted copies.
18
+ /// The graph reader projects direct changelog commit records into explicit
19
+ /// parent ids plus the commit's referenced canonical changes. A merge commit
20
+ /// points at selected existing change ids; it does not mint row/entity changes
21
+ /// for the merge itself.
12
22
  #[derive(Debug, Clone, PartialEq, Eq)]
13
23
  pub(crate) struct CommitGraphCommit {
14
- pub(crate) canonical_change: Change,
15
- pub(crate) change: Change,
24
+ pub(crate) canonical_change: CommitGraphChange,
25
+ pub(crate) change: CommitGraphChange,
16
26
  pub(crate) commit_id: String,
17
27
  pub(crate) change_ids: Vec<String>,
18
28
  pub(crate) author_account_ids: Vec<String>,
@@ -37,7 +47,7 @@ pub(crate) struct CommitGraphEdge {
37
47
  /// Filter for canonical change history from a chosen traversal start commit.
38
48
  #[derive(Debug, Clone, Default, PartialEq, Eq)]
39
49
  pub(crate) struct CommitGraphChangeHistoryRequest {
40
- pub(crate) entity_ids: Vec<EntityIdentity>,
50
+ pub(crate) entity_pks: Vec<EntityPk>,
41
51
  pub(crate) schema_keys: Vec<String>,
42
52
  pub(crate) file_ids: Vec<String>,
43
53
  pub(crate) min_depth: Option<u32>,
@@ -48,10 +58,10 @@ pub(crate) struct CommitGraphChangeHistoryRequest {
48
58
  /// Canonical change observed while walking commit history from a start commit.
49
59
  ///
50
60
  /// `start_commit_id` is the traversal anchor requested by the caller. It is not
51
- /// necessarily a graph root or a version head.
61
+ /// necessarily a graph root or a branch head.
52
62
  #[derive(Debug, Clone, PartialEq, Eq)]
53
63
  pub(crate) struct CommitGraphChangeHistoryEntry {
54
- pub(crate) located_change: LocatedChange,
64
+ pub(crate) change: CommitGraphChange,
55
65
  pub(crate) observed_commit_id: String,
56
66
  pub(crate) start_commit_id: String,
57
67
  pub(crate) depth: u32,
@@ -61,46 +71,16 @@ pub(crate) struct CommitGraphChangeHistoryEntry {
61
71
  ///
62
72
  /// SQL surfaces consume this trait so they depend on graph semantics, not on
63
73
  /// changelog storage or traversal details.
64
- #[allow(dead_code)]
65
74
  #[async_trait::async_trait]
66
75
  pub(crate) trait CommitGraphReader: Send + Sync {
67
- #[allow(dead_code)]
68
76
  async fn load_commit(&mut self, commit_id: &str)
69
77
  -> Result<Option<CommitGraphCommit>, LixError>;
70
78
 
71
- async fn all_commits(&mut self) -> Result<Vec<CommitGraphCommit>, LixError>;
72
-
73
79
  async fn reachable_commits(
74
80
  &mut self,
75
81
  head_commit_id: &str,
76
82
  ) -> Result<Vec<ReachableCommitGraphCommit>, LixError>;
77
83
 
78
- /// Returns the best common ancestors shared by two commit heads.
79
- ///
80
- /// This is intentionally not called "lowest common ancestor": commit
81
- /// history is a DAG, not a tree, and some histories have multiple equally
82
- /// good common ancestors. Merge policy can require exactly one base later.
83
- #[allow(dead_code)]
84
- async fn best_common_ancestors(
85
- &mut self,
86
- left_commit_id: &str,
87
- right_commit_id: &str,
88
- ) -> Result<Vec<CommitGraphCommit>, LixError>;
89
-
90
- /// Resolves the single commit base to use for a three-way merge.
91
- ///
92
- /// This is merge policy, not raw graph math: no common history and multiple
93
- /// best common ancestors are both errors until merge has explicit support
94
- /// for those cases.
95
- #[allow(dead_code)]
96
- async fn merge_base(
97
- &mut self,
98
- left_commit_id: &str,
99
- right_commit_id: &str,
100
- ) -> Result<CommitGraphCommit, LixError>;
101
-
102
- fn commit_edges(&self, commits: &[CommitGraphCommit]) -> Vec<CommitGraphEdge>;
103
-
104
84
  async fn change_history_from_commit(
105
85
  &mut self,
106
86
  start_commit_id: &str,
@@ -1,7 +1,7 @@
1
1
  use std::collections::{BTreeMap, BTreeSet};
2
2
 
3
3
  use crate::commit_graph::{CommitGraphCommit, CommitGraphStoreReader, ReachableCommitGraphCommit};
4
- use crate::storage::StorageReader;
4
+ use crate::storage::StorageRead;
5
5
  use crate::LixError;
6
6
 
7
7
  /// Walks parent links from `head_commit_id` and returns reachable commits
@@ -15,7 +15,7 @@ pub(crate) async fn walk_reachable_commits<S>(
15
15
  head_commit_id: &str,
16
16
  ) -> Result<Vec<ReachableCommitGraphCommit>, LixError>
17
17
  where
18
- S: StorageReader,
18
+ S: StorageRead + Send + Sync,
19
19
  {
20
20
  let mut loader = CommitTraversalLoader::new(reader);
21
21
  let mut visiting = BTreeSet::new();
@@ -67,7 +67,7 @@ pub(crate) async fn best_common_ancestors<S>(
67
67
  right_commit_id: &str,
68
68
  ) -> Result<Vec<CommitGraphCommit>, LixError>
69
69
  where
70
- S: StorageReader,
70
+ S: StorageRead + Send + Sync,
71
71
  {
72
72
  let left_reachable = walk_reachable_commits(reader, left_commit_id).await?;
73
73
  let right_reachable = walk_reachable_commits(reader, right_commit_id).await?;
@@ -104,7 +104,7 @@ async fn has_descendant_in_set<S>(
104
104
  candidate_descendant_ids: &BTreeSet<String>,
105
105
  ) -> Result<bool, LixError>
106
106
  where
107
- S: StorageReader,
107
+ S: StorageRead + Send + Sync,
108
108
  {
109
109
  for candidate_descendant_id in candidate_descendant_ids {
110
110
  if candidate_descendant_id == commit_id {
@@ -123,7 +123,7 @@ where
123
123
 
124
124
  struct CommitTraversalLoader<'a, S>
125
125
  where
126
- S: StorageReader,
126
+ S: StorageRead + Send + Sync,
127
127
  {
128
128
  reader: &'a mut CommitGraphStoreReader<S>,
129
129
  loaded: BTreeMap<String, CommitGraphCommit>,
@@ -131,7 +131,7 @@ where
131
131
 
132
132
  impl<'a, S> CommitTraversalLoader<'a, S>
133
133
  where
134
- S: StorageReader,
134
+ S: StorageRead + Send + Sync,
135
135
  {
136
136
  fn new(reader: &'a mut CommitGraphStoreReader<S>) -> Self {
137
137
  Self {
@@ -218,22 +218,22 @@ struct TraversalFrame {
218
218
 
219
219
  #[cfg(test)]
220
220
  mod tests {
221
- use std::sync::Arc;
222
-
223
221
  use serde_json::json;
224
222
 
225
- use crate::backend::testing::UnitTestBackend;
223
+ use crate::changelog::{
224
+ ChangelogAppend, ChangelogContext, ChangelogWriter, CommitChangeRefSet, CommitRecord,
225
+ };
226
+ use crate::commit_graph::CommitGraphChange;
226
227
  use crate::commit_graph::CommitGraphContext;
227
- use crate::commit_store::{Change, CommitDraftRef, CommitStoreContext};
228
- use crate::storage::{StorageContext, StorageWriteSet};
228
+ use crate::storage::StorageContext;
229
+ use crate::storage::{InMemoryStorageBackend, StorageReadOptions, StorageWriteOptions};
229
230
  use crate::LixError;
230
231
 
231
232
  #[tokio::test]
232
233
  async fn reachable_commits_returns_commits_nearest_first() {
233
- let backend = Arc::new(UnitTestBackend::new());
234
- let storage = StorageContext::new(backend.clone());
234
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
235
235
  append_changes(
236
- storage.clone(),
236
+ &storage,
237
237
  &[
238
238
  commit_change("commit-root-change", "commit-root", &[], &[]),
239
239
  commit_change(
@@ -248,7 +248,10 @@ mod tests {
248
248
  .await;
249
249
 
250
250
  let graph = CommitGraphContext::new();
251
- let mut reader = graph.reader(storage);
251
+ let read = storage
252
+ .begin_read(StorageReadOptions::default())
253
+ .expect("read should open");
254
+ let mut reader = graph.reader(read);
252
255
  let commits = reader
253
256
  .reachable_commits("commit-head")
254
257
  .await
@@ -265,10 +268,9 @@ mod tests {
265
268
 
266
269
  #[tokio::test]
267
270
  async fn reachable_commits_errors_on_missing_parent_commit() {
268
- let backend = Arc::new(UnitTestBackend::new());
269
- let storage = StorageContext::new(backend.clone());
270
- append_changes(
271
- storage.clone(),
271
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
272
+ let error = append_changes_result(
273
+ &storage,
272
274
  &[commit_change(
273
275
  "commit-head-change",
274
276
  "commit-head",
@@ -276,24 +278,17 @@ mod tests {
276
278
  &["missing-parent"],
277
279
  )],
278
280
  )
279
- .await;
280
-
281
- let graph = CommitGraphContext::new();
282
- let mut reader = graph.reader(storage);
283
- let error = reader
284
- .reachable_commits("commit-head")
285
- .await
286
- .expect_err("missing parent should fail");
281
+ .await
282
+ .expect_err("changelog should reject missing parent");
287
283
 
288
284
  assert!(error.message.contains("missing-parent"));
289
285
  }
290
286
 
291
287
  #[tokio::test]
292
288
  async fn reachable_commits_errors_on_cycle() {
293
- let backend = Arc::new(UnitTestBackend::new());
294
- let storage = StorageContext::new(backend.clone());
289
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
295
290
  append_changes(
296
- storage.clone(),
291
+ &storage,
297
292
  &[
298
293
  commit_change("commit-a-change", "commit-a", &[], &["commit-b"]),
299
294
  commit_change("commit-b-change", "commit-b", &[], &["commit-a"]),
@@ -302,21 +297,23 @@ mod tests {
302
297
  .await;
303
298
 
304
299
  let graph = CommitGraphContext::new();
305
- let mut reader = graph.reader(storage);
300
+ let read = storage
301
+ .begin_read(StorageReadOptions::default())
302
+ .expect("read should open");
303
+ let mut reader = graph.reader(read);
306
304
  let error = reader
307
305
  .reachable_commits("commit-a")
308
306
  .await
309
- .expect_err("cycle should fail");
307
+ .expect_err("walker should reject parent cycles");
310
308
 
311
309
  assert!(error.message.contains("cycle"));
312
310
  }
313
311
 
314
312
  #[tokio::test]
315
313
  async fn reachable_commits_dedupes_shared_ancestors_in_diamond() {
316
- let backend = Arc::new(UnitTestBackend::new());
317
- let storage = StorageContext::new(backend.clone());
314
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
318
315
  append_changes(
319
- storage.clone(),
316
+ &storage,
320
317
  &[
321
318
  commit_change("commit-root-change", "commit-root", &[], &[]),
322
319
  commit_change("commit-left-change", "commit-left", &[], &["commit-root"]),
@@ -332,7 +329,10 @@ mod tests {
332
329
  .await;
333
330
 
334
331
  let graph = CommitGraphContext::new();
335
- let mut reader = graph.reader(storage);
332
+ let read = storage
333
+ .begin_read(StorageReadOptions::default())
334
+ .expect("read should open");
335
+ let mut reader = graph.reader(read);
336
336
  let commits = reader
337
337
  .reachable_commits("commit-head")
338
338
  .await
@@ -354,10 +354,9 @@ mod tests {
354
354
 
355
355
  #[tokio::test]
356
356
  async fn reachable_commits_keeps_nearest_depth_for_multiple_paths() {
357
- let backend = Arc::new(UnitTestBackend::new());
358
- let storage = StorageContext::new(backend.clone());
357
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
359
358
  append_changes(
360
- storage.clone(),
359
+ &storage,
361
360
  &[
362
361
  commit_change("commit-root-change", "commit-root", &[], &[]),
363
362
  commit_change(
@@ -377,7 +376,10 @@ mod tests {
377
376
  .await;
378
377
 
379
378
  let graph = CommitGraphContext::new();
380
- let mut reader = graph.reader(storage);
379
+ let read = storage
380
+ .begin_read(StorageReadOptions::default())
381
+ .expect("read should open");
382
+ let mut reader = graph.reader(read);
381
383
  let commits = reader
382
384
  .reachable_commits("commit-head")
383
385
  .await
@@ -394,10 +396,9 @@ mod tests {
394
396
 
395
397
  #[tokio::test]
396
398
  async fn reachable_commits_orders_same_depth_commits_by_id() {
397
- let backend = Arc::new(UnitTestBackend::new());
398
- let storage = StorageContext::new(backend.clone());
399
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
399
400
  append_changes(
400
- storage.clone(),
401
+ &storage,
401
402
  &[
402
403
  commit_change("commit-z-change", "commit-z", &[], &[]),
403
404
  commit_change("commit-a-change", "commit-a", &[], &[]),
@@ -412,7 +413,10 @@ mod tests {
412
413
  .await;
413
414
 
414
415
  let graph = CommitGraphContext::new();
415
- let mut reader = graph.reader(storage);
416
+ let read = storage
417
+ .begin_read(StorageReadOptions::default())
418
+ .expect("read should open");
419
+ let mut reader = graph.reader(read);
416
420
  let commits = reader
417
421
  .reachable_commits("commit-head")
418
422
  .await
@@ -429,10 +433,12 @@ mod tests {
429
433
 
430
434
  #[tokio::test]
431
435
  async fn reachable_commits_errors_on_missing_head_commit() {
432
- let backend = Arc::new(UnitTestBackend::new());
433
- let storage = StorageContext::new(backend.clone());
436
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
434
437
  let graph = CommitGraphContext::new();
435
- let mut reader = graph.reader(storage);
438
+ let read = storage
439
+ .begin_read(StorageReadOptions::default())
440
+ .expect("read should open");
441
+ let mut reader = graph.reader(read);
436
442
 
437
443
  let error = reader
438
444
  .reachable_commits("missing-head")
@@ -444,10 +450,9 @@ mod tests {
444
450
 
445
451
  #[tokio::test]
446
452
  async fn best_common_ancestors_returns_nearest_common_commit_in_simple_graph() {
447
- let backend = Arc::new(UnitTestBackend::new());
448
- let storage = StorageContext::new(backend.clone());
453
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
449
454
  append_changes(
450
- storage.clone(),
455
+ &storage,
451
456
  &[
452
457
  commit_change("commit-a-change", "commit-a", &[], &[]),
453
458
  commit_change("commit-b-change", "commit-b", &[], &["commit-a"]),
@@ -458,7 +463,10 @@ mod tests {
458
463
  .await;
459
464
 
460
465
  let graph = CommitGraphContext::new();
461
- let mut reader = graph.reader(storage);
466
+ let read = storage
467
+ .begin_read(StorageReadOptions::default())
468
+ .expect("read should open");
469
+ let mut reader = graph.reader(read);
462
470
  let ancestors = reader
463
471
  .best_common_ancestors("commit-c", "commit-d")
464
472
  .await
@@ -475,10 +483,9 @@ mod tests {
475
483
 
476
484
  #[tokio::test]
477
485
  async fn best_common_ancestors_returns_shared_fork_in_diamond_graph() {
478
- let backend = Arc::new(UnitTestBackend::new());
479
- let storage = StorageContext::new(backend.clone());
486
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
480
487
  append_changes(
481
- storage.clone(),
488
+ &storage,
482
489
  &[
483
490
  commit_change("commit-root-change", "commit-root", &[], &[]),
484
491
  commit_change("commit-left-change", "commit-left", &[], &["commit-root"]),
@@ -500,7 +507,10 @@ mod tests {
500
507
  .await;
501
508
 
502
509
  let graph = CommitGraphContext::new();
503
- let mut reader = graph.reader(storage);
510
+ let read = storage
511
+ .begin_read(StorageReadOptions::default())
512
+ .expect("read should open");
513
+ let mut reader = graph.reader(read);
504
514
  let ancestors = reader
505
515
  .best_common_ancestors("commit-left-head", "commit-right-head")
506
516
  .await
@@ -517,10 +527,9 @@ mod tests {
517
527
 
518
528
  #[tokio::test]
519
529
  async fn best_common_ancestors_returns_parent_when_one_side_is_ancestor() {
520
- let backend = Arc::new(UnitTestBackend::new());
521
- let storage = StorageContext::new(backend.clone());
530
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
522
531
  append_changes(
523
- storage.clone(),
532
+ &storage,
524
533
  &[
525
534
  commit_change("commit-a-change", "commit-a", &[], &[]),
526
535
  commit_change("commit-b-change", "commit-b", &[], &["commit-a"]),
@@ -530,7 +539,10 @@ mod tests {
530
539
  .await;
531
540
 
532
541
  let graph = CommitGraphContext::new();
533
- let mut reader = graph.reader(storage);
542
+ let read = storage
543
+ .begin_read(StorageReadOptions::default())
544
+ .expect("read should open");
545
+ let mut reader = graph.reader(read);
534
546
  let ancestors = reader
535
547
  .best_common_ancestors("commit-b", "commit-c")
536
548
  .await
@@ -547,10 +559,9 @@ mod tests {
547
559
 
548
560
  #[tokio::test]
549
561
  async fn best_common_ancestors_returns_multiple_bases_for_criss_cross_graph() {
550
- let backend = Arc::new(UnitTestBackend::new());
551
- let storage = StorageContext::new(backend.clone());
562
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
552
563
  append_changes(
553
- storage.clone(),
564
+ &storage,
554
565
  &[
555
566
  commit_change("commit-root-change", "commit-root", &[], &[]),
556
567
  commit_change("commit-left-change", "commit-left", &[], &["commit-root"]),
@@ -572,7 +583,10 @@ mod tests {
572
583
  .await;
573
584
 
574
585
  let graph = CommitGraphContext::new();
575
- let mut reader = graph.reader(storage);
586
+ let read = storage
587
+ .begin_read(StorageReadOptions::default())
588
+ .expect("read should open");
589
+ let mut reader = graph.reader(read);
576
590
  let ancestors = reader
577
591
  .best_common_ancestors("commit-head-left", "commit-head-right")
578
592
  .await
@@ -589,10 +603,9 @@ mod tests {
589
603
 
590
604
  #[tokio::test]
591
605
  async fn merge_base_returns_single_best_common_ancestor() {
592
- let backend = Arc::new(UnitTestBackend::new());
593
- let storage = StorageContext::new(backend.clone());
606
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
594
607
  append_changes(
595
- storage.clone(),
608
+ &storage,
596
609
  &[
597
610
  commit_change("commit-a-change", "commit-a", &[], &[]),
598
611
  commit_change("commit-b-change", "commit-b", &[], &["commit-a"]),
@@ -603,7 +616,10 @@ mod tests {
603
616
  .await;
604
617
 
605
618
  let graph = CommitGraphContext::new();
606
- let mut reader = graph.reader(storage);
619
+ let read = storage
620
+ .begin_read(StorageReadOptions::default())
621
+ .expect("read should open");
622
+ let mut reader = graph.reader(read);
607
623
  let base = reader
608
624
  .merge_base("commit-c", "commit-d")
609
625
  .await
@@ -614,10 +630,9 @@ mod tests {
614
630
 
615
631
  #[tokio::test]
616
632
  async fn merge_base_errors_when_histories_have_no_common_commit() {
617
- let backend = Arc::new(UnitTestBackend::new());
618
- let storage = StorageContext::new(backend.clone());
633
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
619
634
  append_changes(
620
- storage.clone(),
635
+ &storage,
621
636
  &[
622
637
  commit_change("commit-left-change", "commit-left", &[], &[]),
623
638
  commit_change("commit-right-change", "commit-right", &[], &[]),
@@ -626,7 +641,10 @@ mod tests {
626
641
  .await;
627
642
 
628
643
  let graph = CommitGraphContext::new();
629
- let mut reader = graph.reader(storage);
644
+ let read = storage
645
+ .begin_read(StorageReadOptions::default())
646
+ .expect("read should open");
647
+ let mut reader = graph.reader(read);
630
648
  let error = reader
631
649
  .merge_base("commit-left", "commit-right")
632
650
  .await
@@ -637,10 +655,9 @@ mod tests {
637
655
 
638
656
  #[tokio::test]
639
657
  async fn merge_base_errors_when_best_common_ancestor_is_ambiguous() {
640
- let backend = Arc::new(UnitTestBackend::new());
641
- let storage = StorageContext::new(backend.clone());
658
+ let storage = StorageContext::new(InMemoryStorageBackend::new());
642
659
  append_changes(
643
- storage.clone(),
660
+ &storage,
644
661
  &[
645
662
  commit_change("commit-root-change", "commit-root", &[], &[]),
646
663
  commit_change("commit-left-change", "commit-left", &[], &["commit-root"]),
@@ -662,7 +679,10 @@ mod tests {
662
679
  .await;
663
680
 
664
681
  let graph = CommitGraphContext::new();
665
- let mut reader = graph.reader(storage);
682
+ let read = storage
683
+ .begin_read(StorageReadOptions::default())
684
+ .expect("read should open");
685
+ let mut reader = graph.reader(read);
666
686
  let error = reader
667
687
  .merge_base("commit-head-left", "commit-head-right")
668
688
  .await
@@ -694,43 +714,53 @@ mod tests {
694
714
 
695
715
  #[derive(Clone)]
696
716
  struct TestCommitChange {
697
- change: Change,
717
+ change: CommitGraphChange,
698
718
  parent_commit_ids: Vec<String>,
699
719
  }
700
720
 
701
- async fn append_changes(storage: StorageContext, changes: &[TestCommitChange]) {
702
- let mut tx = storage
703
- .begin_write_transaction()
721
+ async fn append_changes(storage: &StorageContext, changes: &[TestCommitChange]) {
722
+ append_changes_result(storage, changes)
704
723
  .await
705
- .expect("transaction should open");
706
- let mut writes = StorageWriteSet::new();
707
- let commit_store = CommitStoreContext::new();
724
+ .expect("changelog fixture should append");
725
+ }
726
+
727
+ async fn append_changes_result(
728
+ storage: &StorageContext,
729
+ changes: &[TestCommitChange],
730
+ ) -> Result<(), LixError> {
731
+ let mut read = storage
732
+ .begin_read(StorageReadOptions::default())
733
+ .expect("read should open");
734
+ let mut writes = storage.new_write_set();
735
+ let mut append = ChangelogAppend::default();
708
736
  for change in changes {
709
737
  let commit_id = change
710
738
  .change
711
- .entity_id
739
+ .entity_pk
712
740
  .as_single_string()
713
741
  .expect("commit fixture should have single id")
714
742
  .to_string();
715
- let author_account_ids = Vec::new();
716
- let commit = CommitDraftRef {
717
- id: &commit_id,
718
- change_id: &change.change.id,
719
- parent_ids: &change.parent_commit_ids,
720
- author_account_ids: &author_account_ids,
721
- created_at: &change.change.created_at,
722
- };
723
- commit_store
724
- .writer(tx.as_mut(), &mut writes)
725
- .stage_commit_draft(commit, Vec::new(), Vec::new())
726
- .await
727
- .expect("commit-store fixture should append");
743
+ append.commits.push(CommitRecord {
744
+ format_version: 1,
745
+ commit_id: commit_id.clone(),
746
+ parent_commit_ids: change.parent_commit_ids.clone(),
747
+ change_id: change.change.id.clone(),
748
+ author_account_ids: Vec::new(),
749
+ created_at: change.change.created_at.clone(),
750
+ });
751
+ append.commit_change_refs.push(CommitChangeRefSet {
752
+ commit_id: commit_id.clone(),
753
+ entries: Vec::new(),
754
+ });
728
755
  }
729
- writes
730
- .apply(&mut tx.as_mut())
731
- .await
732
- .expect("writes should apply");
733
- tx.commit().await.expect("commit should succeed");
756
+ ChangelogContext::new()
757
+ .writer(&mut read, &mut writes)
758
+ .stage_append(append)
759
+ .await?;
760
+ storage
761
+ .commit_write_set(writes, StorageWriteOptions::default())
762
+ .expect("commit should succeed");
763
+ Ok(())
734
764
  }
735
765
 
736
766
  fn commit_change(
@@ -741,9 +771,9 @@ mod tests {
741
771
  ) -> TestCommitChange {
742
772
  let _ = change_ids;
743
773
  TestCommitChange {
744
- change: Change {
774
+ change: CommitGraphChange {
745
775
  id: change_id.to_string(),
746
- entity_id: crate::entity_identity::EntityIdentity::single(commit_id),
776
+ entity_pk: crate::entity_pk::EntityPk::single(commit_id),
747
777
  schema_key: "lix_commit".to_string(),
748
778
  file_id: None,
749
779
  snapshot_ref: None,