@lix-js/sdk 0.6.0-preview.2 → 0.6.0-preview.4

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 (169) hide show
  1. package/SKILL.md +46 -8
  2. package/dist/engine-wasm/wasm/lix_engine.d.ts +25 -1
  3. package/dist/engine-wasm/wasm/lix_engine.js +60 -2
  4. package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
  5. package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +5 -0
  6. package/dist/generated/builtin-schemas.d.ts +87 -162
  7. package/dist/generated/builtin-schemas.js +139 -236
  8. package/dist/open-lix.d.ts +10 -3
  9. package/dist/open-lix.js +39 -0
  10. package/dist-engine-src/src/binary_cas/types.rs +0 -6
  11. package/dist-engine-src/src/catalog/context.rs +412 -0
  12. package/dist-engine-src/src/catalog/mod.rs +10 -0
  13. package/dist-engine-src/src/catalog/schema.rs +4 -0
  14. package/dist-engine-src/src/catalog/snapshot.rs +1114 -0
  15. package/dist-engine-src/src/cel/mod.rs +1 -1
  16. package/dist-engine-src/src/cel/provider.rs +1 -1
  17. package/dist-engine-src/src/commit_graph/context.rs +328 -1015
  18. package/dist-engine-src/src/commit_graph/mod.rs +2 -3
  19. package/dist-engine-src/src/commit_graph/types.rs +7 -43
  20. package/dist-engine-src/src/commit_graph/walker.rs +57 -81
  21. package/dist-engine-src/src/commit_store/codec.rs +887 -0
  22. package/dist-engine-src/src/commit_store/context.rs +944 -0
  23. package/dist-engine-src/src/commit_store/materialization.rs +84 -0
  24. package/dist-engine-src/src/commit_store/mod.rs +16 -0
  25. package/dist-engine-src/src/commit_store/storage.rs +600 -0
  26. package/dist-engine-src/src/commit_store/types.rs +215 -0
  27. package/dist-engine-src/src/common/identity.rs +15 -5
  28. package/dist-engine-src/src/common/json_pointer.rs +67 -0
  29. package/dist-engine-src/src/common/metadata.rs +17 -12
  30. package/dist-engine-src/src/common/mod.rs +5 -5
  31. package/dist-engine-src/src/domain.rs +324 -0
  32. package/dist-engine-src/src/engine.rs +29 -43
  33. package/dist-engine-src/src/entity_identity.rs +238 -118
  34. package/dist-engine-src/src/functions/context.rs +17 -52
  35. package/dist-engine-src/src/functions/deterministic.rs +1 -1
  36. package/dist-engine-src/src/functions/mod.rs +1 -1
  37. package/dist-engine-src/src/functions/provider.rs +4 -4
  38. package/dist-engine-src/src/functions/state.rs +39 -66
  39. package/dist-engine-src/src/functions/types.rs +1 -1
  40. package/dist-engine-src/src/init.rs +204 -151
  41. package/dist-engine-src/src/json_store/context.rs +354 -60
  42. package/dist-engine-src/src/json_store/encoded.rs +6 -6
  43. package/dist-engine-src/src/json_store/mod.rs +4 -1
  44. package/dist-engine-src/src/json_store/store.rs +884 -11
  45. package/dist-engine-src/src/json_store/types.rs +166 -1
  46. package/dist-engine-src/src/lib.rs +11 -10
  47. package/dist-engine-src/src/live_state/context.rs +608 -830
  48. package/dist-engine-src/src/live_state/mod.rs +3 -3
  49. package/dist-engine-src/src/live_state/overlay.rs +7 -7
  50. package/dist-engine-src/src/live_state/reader.rs +5 -5
  51. package/dist-engine-src/src/live_state/types.rs +19 -36
  52. package/dist-engine-src/src/live_state/visibility.rs +19 -14
  53. package/dist-engine-src/src/plugin/archive.rs +3 -6
  54. package/dist-engine-src/src/plugin/install.rs +0 -18
  55. package/dist-engine-src/src/plugin/plugin_manifest.json +0 -1
  56. package/dist-engine-src/src/schema/annotations/defaults.rs +2 -7
  57. package/dist-engine-src/src/schema/builtin/lix_account.json +0 -1
  58. package/dist-engine-src/src/schema/builtin/lix_active_account.json +0 -1
  59. package/dist-engine-src/src/schema/builtin/lix_binary_blob_ref.json +0 -1
  60. package/dist-engine-src/src/schema/builtin/lix_change.json +11 -10
  61. package/dist-engine-src/src/schema/builtin/lix_change_author.json +0 -1
  62. package/dist-engine-src/src/schema/builtin/lix_commit.json +8 -46
  63. package/dist-engine-src/src/schema/builtin/lix_commit_edge.json +29 -22
  64. package/dist-engine-src/src/schema/builtin/lix_directory_descriptor.json +0 -1
  65. package/dist-engine-src/src/schema/builtin/lix_file_descriptor.json +0 -1
  66. package/dist-engine-src/src/schema/builtin/lix_key_value.json +0 -1
  67. package/dist-engine-src/src/schema/builtin/lix_label.json +10 -3
  68. package/dist-engine-src/src/schema/builtin/lix_label_assignment.json +74 -0
  69. package/dist-engine-src/src/schema/builtin/lix_registered_schema.json +2 -8
  70. package/dist-engine-src/src/schema/builtin/lix_version_descriptor.json +0 -1
  71. package/dist-engine-src/src/schema/builtin/lix_version_ref.json +0 -1
  72. package/dist-engine-src/src/schema/builtin/mod.rs +10 -59
  73. package/dist-engine-src/src/schema/compatibility.rs +787 -0
  74. package/dist-engine-src/src/schema/definition.json +47 -17
  75. package/dist-engine-src/src/schema/definition.rs +202 -96
  76. package/dist-engine-src/src/schema/key.rs +9 -77
  77. package/dist-engine-src/src/schema/mod.rs +4 -4
  78. package/dist-engine-src/src/schema/tests.rs +133 -92
  79. package/dist-engine-src/src/session/context.rs +86 -48
  80. package/dist-engine-src/src/session/create_version.rs +22 -14
  81. package/dist-engine-src/src/session/execute.rs +117 -23
  82. package/dist-engine-src/src/session/merge/apply.rs +4 -4
  83. package/dist-engine-src/src/session/merge/conflicts.rs +3 -2
  84. package/dist-engine-src/src/session/merge/stats.rs +1 -1
  85. package/dist-engine-src/src/session/merge/version.rs +35 -45
  86. package/dist-engine-src/src/session/mod.rs +9 -7
  87. package/dist-engine-src/src/session/optimization9_sql2_bench.rs +100 -0
  88. package/dist-engine-src/src/session/switch_version.rs +17 -28
  89. package/dist-engine-src/src/session/transaction.rs +76 -0
  90. package/dist-engine-src/src/sql2/change_provider.rs +14 -20
  91. package/dist-engine-src/src/sql2/classify.rs +75 -48
  92. package/dist-engine-src/src/sql2/context.rs +22 -18
  93. package/dist-engine-src/src/sql2/directory_history_provider.rs +28 -20
  94. package/dist-engine-src/src/sql2/directory_provider.rs +131 -83
  95. package/dist-engine-src/src/sql2/entity_history_provider.rs +10 -14
  96. package/dist-engine-src/src/sql2/entity_provider.rs +680 -169
  97. package/dist-engine-src/src/sql2/error.rs +24 -5
  98. package/dist-engine-src/src/sql2/execute.rs +426 -272
  99. package/dist-engine-src/src/sql2/file_history_provider.rs +29 -21
  100. package/dist-engine-src/src/sql2/file_provider.rs +533 -108
  101. package/dist-engine-src/src/sql2/filesystem_planner.rs +58 -94
  102. package/dist-engine-src/src/sql2/filesystem_visibility.rs +37 -23
  103. package/dist-engine-src/src/sql2/history_projection.rs +3 -27
  104. package/dist-engine-src/src/sql2/history_provider.rs +11 -17
  105. package/dist-engine-src/src/sql2/history_route.rs +22 -8
  106. package/dist-engine-src/src/sql2/lix_state_provider.rs +178 -96
  107. package/dist-engine-src/src/sql2/mod.rs +8 -4
  108. package/dist-engine-src/src/sql2/predicate_typecheck.rs +246 -0
  109. package/dist-engine-src/src/sql2/public_bind/assignment.rs +46 -0
  110. package/dist-engine-src/src/sql2/public_bind/capability.rs +41 -0
  111. package/dist-engine-src/src/sql2/public_bind/dml.rs +172 -0
  112. package/dist-engine-src/src/sql2/public_bind/mod.rs +26 -0
  113. package/dist-engine-src/src/sql2/public_bind/table.rs +168 -0
  114. package/dist-engine-src/src/sql2/read_only.rs +10 -12
  115. package/dist-engine-src/src/sql2/session.rs +7 -10
  116. package/dist-engine-src/src/sql2/udfs/lix_timestamp.rs +76 -0
  117. package/dist-engine-src/src/sql2/udfs/mod.rs +8 -1
  118. package/dist-engine-src/src/sql2/udfs/public_call.rs +238 -0
  119. package/dist-engine-src/src/sql2/version_provider.rs +46 -31
  120. package/dist-engine-src/src/sql2/version_scope.rs +4 -4
  121. package/dist-engine-src/src/storage_bench.rs +1782 -325
  122. package/dist-engine-src/src/test_support.rs +183 -36
  123. package/dist-engine-src/src/tracked_state/by_file_index.rs +20 -24
  124. package/dist-engine-src/src/tracked_state/codec.rs +1519 -181
  125. package/dist-engine-src/src/tracked_state/context.rs +1155 -271
  126. package/dist-engine-src/src/tracked_state/diff.rs +249 -57
  127. package/dist-engine-src/src/tracked_state/materialization.rs +365 -103
  128. package/dist-engine-src/src/tracked_state/materializer.rs +488 -0
  129. package/dist-engine-src/src/tracked_state/merge.rs +37 -19
  130. package/dist-engine-src/src/tracked_state/mod.rs +8 -7
  131. package/dist-engine-src/src/tracked_state/storage.rs +138 -6
  132. package/dist-engine-src/src/tracked_state/tree.rs +695 -252
  133. package/dist-engine-src/src/tracked_state/types.rs +176 -6
  134. package/dist-engine-src/src/transaction/commit.rs +695 -435
  135. package/dist-engine-src/src/transaction/context.rs +551 -310
  136. package/dist-engine-src/src/transaction/live_state_overlay.rs +9 -8
  137. package/dist-engine-src/src/transaction/mod.rs +2 -0
  138. package/dist-engine-src/src/transaction/normalization.rs +311 -447
  139. package/dist-engine-src/src/transaction/prep.rs +37 -0
  140. package/dist-engine-src/src/transaction/schema_resolver.rs +93 -71
  141. package/dist-engine-src/src/transaction/staging.rs +701 -406
  142. package/dist-engine-src/src/transaction/types.rs +231 -122
  143. package/dist-engine-src/src/transaction/validation.rs +2717 -1698
  144. package/dist-engine-src/src/untracked_state/codec.rs +40 -96
  145. package/dist-engine-src/src/untracked_state/context.rs +21 -5
  146. package/dist-engine-src/src/untracked_state/materialization.rs +10 -104
  147. package/dist-engine-src/src/untracked_state/mod.rs +3 -5
  148. package/dist-engine-src/src/untracked_state/storage.rs +105 -57
  149. package/dist-engine-src/src/untracked_state/types.rs +63 -13
  150. package/dist-engine-src/src/version/context.rs +1 -13
  151. package/dist-engine-src/src/version/lifecycle.rs +221 -0
  152. package/dist-engine-src/src/version/mod.rs +3 -2
  153. package/dist-engine-src/src/version/refs.rs +12 -103
  154. package/dist-engine-src/src/version/stage_rows.rs +15 -19
  155. package/package.json +1 -1
  156. package/dist-engine-src/src/changelog/codec.rs +0 -321
  157. package/dist-engine-src/src/changelog/context.rs +0 -92
  158. package/dist-engine-src/src/changelog/materialization.rs +0 -121
  159. package/dist-engine-src/src/changelog/mod.rs +0 -13
  160. package/dist-engine-src/src/changelog/reader.rs +0 -20
  161. package/dist-engine-src/src/changelog/storage.rs +0 -220
  162. package/dist-engine-src/src/changelog/types.rs +0 -38
  163. package/dist-engine-src/src/schema/builtin/lix_change_set.json +0 -18
  164. package/dist-engine-src/src/schema/builtin/lix_change_set_element.json +0 -75
  165. package/dist-engine-src/src/schema/builtin/lix_entity_label.json +0 -63
  166. package/dist-engine-src/src/schema_registry.rs +0 -294
  167. package/dist-engine-src/src/sql2/commit_derived_provider.rs +0 -591
  168. package/dist-engine-src/src/tracked_state/rebuild.rs +0 -771
  169. package/dist-engine-src/src/tracked_state/tree_types.rs +0 -176
@@ -1,7 +1,7 @@
1
- use serde_json::json;
1
+ use serde_json::{json, Value as JsonValue};
2
2
 
3
- use crate::transaction::types::StageWrite;
4
- use crate::version::VersionRefReader;
3
+ use crate::transaction::types::TransactionWrite;
4
+ use crate::version::{VersionLifecycle, VersionOperation, VersionReferenceRole};
5
5
  use crate::LixError;
6
6
 
7
7
  use super::analysis::{analyze, MergeCommits, MergeOutcome};
@@ -67,7 +67,7 @@ pub struct MergeVersionPreview {
67
67
  pub struct MergeConflict {
68
68
  pub kind: MergeConflictKind,
69
69
  pub schema_key: String,
70
- pub entity_id: String,
70
+ pub entity_id: JsonValue,
71
71
  pub file_id: Option<String>,
72
72
  pub target: MergeConflictSide,
73
73
  pub source: MergeConflictSide,
@@ -117,26 +117,21 @@ impl SessionContext {
117
117
 
118
118
  let (target_head, source_head) = {
119
119
  let reader = transaction.version_ref_reader();
120
- let target_head = reader
121
- .load_head_commit_id(&active_version_id)
122
- .await?
123
- .ok_or_else(|| {
124
- LixError::version_not_found(
125
- active_version_id.clone(),
126
- "merge_version_preview",
127
- "target",
128
- )
129
- })?;
130
- let source_head = reader
131
- .load_head_commit_id(&source_version_id)
132
- .await?
133
- .ok_or_else(|| {
134
- LixError::version_not_found(
135
- source_version_id.clone(),
136
- "merge_version_preview",
137
- "source",
138
- )
139
- })?;
120
+ let lifecycle = VersionLifecycle::new(&reader);
121
+ let target_head = lifecycle
122
+ .require_existing_commit_id(
123
+ &active_version_id,
124
+ VersionOperation::MergeVersionPreview,
125
+ VersionReferenceRole::Target,
126
+ )
127
+ .await?;
128
+ let source_head = lifecycle
129
+ .require_existing_commit_id(
130
+ &source_version_id,
131
+ VersionOperation::MergeVersionPreview,
132
+ VersionReferenceRole::Source,
133
+ )
134
+ .await?;
140
135
  (target_head, source_head)
141
136
  };
142
137
 
@@ -189,26 +184,21 @@ impl SessionContext {
189
184
 
190
185
  let (target_head, source_head) = {
191
186
  let reader = transaction.version_ref_reader();
192
- let target_head = reader
193
- .load_head_commit_id(&active_version_id)
194
- .await?
195
- .ok_or_else(|| {
196
- LixError::version_not_found(
197
- active_version_id.clone(),
198
- "merge_version",
199
- "target",
200
- )
201
- })?;
202
- let source_head = reader
203
- .load_head_commit_id(&source_version_id)
204
- .await?
205
- .ok_or_else(|| {
206
- LixError::version_not_found(
207
- source_version_id.clone(),
208
- "merge_version",
209
- "source",
210
- )
211
- })?;
187
+ let lifecycle = VersionLifecycle::new(&reader);
188
+ let target_head = lifecycle
189
+ .require_existing_commit_id(
190
+ &active_version_id,
191
+ VersionOperation::MergeVersion,
192
+ VersionReferenceRole::Target,
193
+ )
194
+ .await?;
195
+ let source_head = lifecycle
196
+ .require_existing_commit_id(
197
+ &source_version_id,
198
+ VersionOperation::MergeVersion,
199
+ VersionReferenceRole::Source,
200
+ )
201
+ .await?;
212
202
  (target_head, source_head)
213
203
  };
214
204
 
@@ -300,7 +290,7 @@ impl SessionContext {
300
290
  }
301
291
 
302
292
  transaction
303
- .stage_write(StageWrite::AdoptedChanges {
293
+ .stage_write(TransactionWrite::AdoptedChanges {
304
294
  changes: adopted_changes,
305
295
  })
306
296
  .await?;
@@ -1,17 +1,18 @@
1
- //! Engine2 session boundary.
1
+ //! Engine session boundary.
2
2
  //!
3
- //! Transaction invariant:
4
- //! any engine2 operation that may write must enter through
5
- //! `SessionContext::with_write_transaction`. Reads that influence writes are
6
- //! only available from the transaction capability. Session APIs must not
7
- //! open `Transaction` directly or use session-level read helpers inside write
8
- //! flows.
3
+ //! Transaction invariant: a session has one execution lease. Parent-handle
4
+ //! calls use it for implicit single-statement execution; explicit transactions
5
+ //! hold it until commit or rollback. Session APIs must not open `Transaction`
6
+ //! directly or use session-level read helpers inside write flows.
9
7
 
10
8
  mod context;
11
9
  mod create_version;
12
10
  mod execute;
13
11
  mod merge;
12
+ #[cfg(feature = "storage-benches")]
13
+ pub mod optimization9_sql2_bench;
14
14
  mod switch_version;
15
+ mod transaction;
15
16
 
16
17
  pub use context::SessionContext;
17
18
  pub(crate) use context::{SessionMode, WORKSPACE_VERSION_KEY};
@@ -23,3 +24,4 @@ pub use merge::{
23
24
  MergeVersionReceipt,
24
25
  };
25
26
  pub use switch_version::{SwitchVersionOptions, SwitchVersionReceipt};
27
+ pub use transaction::SessionTransaction;
@@ -0,0 +1,100 @@
1
+ use crate::functions::FunctionContext;
2
+ use crate::session::context::{SessionContext, SessionSqlExecutionContext};
3
+ use crate::sql2::{self, SqlLogicalPlan};
4
+ use crate::storage::StorageReadScope;
5
+ use crate::transaction::open_transaction;
6
+ use crate::{LixError, SqlQueryResult, Value};
7
+
8
+ /// Opaque read plan used by the Optimization 9 SQL2 diagnostic benchmark.
9
+ ///
10
+ /// This module is gated behind `storage-benches` and exists only to split SQL2
11
+ /// planning cost from SQL2 execution cost without widening the normal session
12
+ /// API.
13
+ pub struct PreparedReadPlan {
14
+ plan: SqlLogicalPlan,
15
+ read_scope:
16
+ StorageReadScope<Box<dyn crate::storage::StorageReadTransaction + Send + Sync + 'static>>,
17
+ runtime_functions: FunctionContext,
18
+ }
19
+
20
+ pub async fn plan_read_only(session: &SessionContext, sql: &str) -> Result<(), LixError> {
21
+ let prepared = prepare_read_plan(session, sql).await?;
22
+ drop(prepared.plan);
23
+ drop(prepared.runtime_functions);
24
+ prepared.read_scope.rollback().await
25
+ }
26
+
27
+ pub async fn plan_write_only(session: &SessionContext, sql: &str) -> Result<(), LixError> {
28
+ session.ensure_open()?;
29
+ let opened = open_transaction(
30
+ &session.mode,
31
+ session.storage.clone(),
32
+ std::sync::Arc::clone(&session.live_state),
33
+ std::sync::Arc::clone(&session.tracked_state),
34
+ std::sync::Arc::clone(&session.binary_cas),
35
+ std::sync::Arc::clone(&session.commit_store),
36
+ std::sync::Arc::clone(&session.version_ctx),
37
+ std::sync::Arc::clone(&session.catalog_context),
38
+ )
39
+ .await?;
40
+ let mut transaction = opened.transaction;
41
+ let runtime_functions = opened.runtime_functions;
42
+ let plan = sql2::create_write_logical_plan(&mut transaction, sql).await?;
43
+ drop(plan);
44
+ drop(runtime_functions);
45
+ transaction.rollback().await
46
+ }
47
+
48
+ pub async fn prepare_read_plan(
49
+ session: &SessionContext,
50
+ sql: &str,
51
+ ) -> Result<PreparedReadPlan, LixError> {
52
+ session.ensure_open()?;
53
+ let read_scope = StorageReadScope::new(session.storage.begin_read_transaction().await?);
54
+ let mut read_store = read_scope.store();
55
+ let live_state: std::sync::Arc<dyn crate::live_state::LiveStateReader> =
56
+ std::sync::Arc::new(session.live_state.reader(read_store.clone()));
57
+ let runtime_functions = FunctionContext::prepare(live_state.as_ref()).await?;
58
+ let functions = runtime_functions.provider();
59
+ let active_version_id = session
60
+ .active_version_id_from_reader(&mut read_store)
61
+ .await?;
62
+ let visible_schemas = session
63
+ .catalog_context
64
+ .schema_jsons_for_sql_read_planning(live_state.as_ref(), &active_version_id)
65
+ .await?;
66
+ let ctx = SessionSqlExecutionContext {
67
+ active_version_id: &active_version_id,
68
+ read_store,
69
+ live_state: std::sync::Arc::clone(&session.live_state),
70
+ binary_cas: std::sync::Arc::clone(&session.binary_cas),
71
+ commit_store: std::sync::Arc::clone(&session.commit_store),
72
+ version_ctx: std::sync::Arc::clone(&session.version_ctx),
73
+ visible_schemas,
74
+ functions: functions.clone(),
75
+ };
76
+ let plan = sql2::create_logical_plan(&ctx, sql).await?;
77
+ drop(ctx);
78
+ drop(live_state);
79
+
80
+ Ok(PreparedReadPlan {
81
+ plan,
82
+ read_scope,
83
+ runtime_functions,
84
+ })
85
+ }
86
+
87
+ pub async fn execute_read_plan(
88
+ prepared: PreparedReadPlan,
89
+ params: &[Value],
90
+ ) -> Result<SqlQueryResult, LixError> {
91
+ let PreparedReadPlan {
92
+ plan,
93
+ read_scope,
94
+ runtime_functions,
95
+ } = prepared;
96
+ let result = sql2::execute_logical_plan(plan, params).await;
97
+ read_scope.rollback().await?;
98
+ drop(runtime_functions);
99
+ result
100
+ }
@@ -2,15 +2,14 @@ use std::sync::Arc;
2
2
 
3
3
  use serde_json::json;
4
4
 
5
- use crate::transaction::types::StageRow;
6
- use crate::version::VersionRefReader;
5
+ use crate::transaction::types::{TransactionJson, TransactionWriteRow};
6
+ use crate::version::{VersionLifecycle, VersionOperation, VersionReferenceRole};
7
7
  use crate::LixError;
8
8
  use crate::GLOBAL_VERSION_ID;
9
9
 
10
10
  use super::context::{SessionContext, SessionMode, WORKSPACE_VERSION_KEY};
11
11
 
12
12
  const KEY_VALUE_SCHEMA_KEY: &str = "lix_key_value";
13
- const KEY_VALUE_SCHEMA_VERSION: &str = "1";
14
13
 
15
14
  /// Options for switching a session to another version.
16
15
  #[derive(Debug, Clone, PartialEq, Eq)]
@@ -40,17 +39,16 @@ impl SessionContext {
40
39
  let next_mode = self
41
40
  .with_write_transaction(|transaction| {
42
41
  Box::pin(async move {
43
- let head = {
42
+ {
44
43
  let reader = transaction.version_ref_reader();
45
- reader.load_head_commit_id(&version_id).await?
44
+ VersionLifecycle::new(&reader)
45
+ .require_existing_commit_id(
46
+ &version_id,
47
+ VersionOperation::SwitchVersion,
48
+ VersionReferenceRole::Target,
49
+ )
50
+ .await?
46
51
  };
47
- if head.is_none() {
48
- return Err(LixError::version_not_found(
49
- version_id.clone(),
50
- "switch_version",
51
- "target",
52
- ));
53
- }
54
52
 
55
53
  match current_mode {
56
54
  SessionMode::Pinned { .. } => Ok(SessionMode::Pinned {
@@ -73,10 +71,11 @@ impl SessionContext {
73
71
  Arc::clone(&self.live_state),
74
72
  Arc::clone(&self.tracked_state),
75
73
  Arc::clone(&self.binary_cas),
76
- Arc::clone(&self.changelog),
74
+ Arc::clone(&self.commit_store),
77
75
  Arc::clone(&self.version_ctx),
78
- Arc::clone(&self.schema_registry),
76
+ Arc::clone(&self.catalog_context),
79
77
  self.closed_flag(),
78
+ self.active_transaction_flag(),
80
79
  );
81
80
  Ok((
82
81
  session,
@@ -87,20 +86,19 @@ impl SessionContext {
87
86
  }
88
87
  }
89
88
 
90
- fn workspace_version_stage_row(version_id: &str) -> Result<StageRow, LixError> {
91
- Ok(StageRow {
89
+ fn workspace_version_stage_row(version_id: &str) -> Result<TransactionWriteRow, LixError> {
90
+ Ok(TransactionWriteRow {
92
91
  entity_id: Some(crate::entity_identity::EntityIdentity::single(
93
92
  WORKSPACE_VERSION_KEY,
94
93
  )),
95
94
  schema_key: KEY_VALUE_SCHEMA_KEY.to_string(),
96
95
  file_id: None,
97
- snapshot_content: Some(encode_snapshot(json!({
96
+ snapshot: Some(TransactionJson::from_value_unchecked(json!({
98
97
  "key": WORKSPACE_VERSION_KEY,
99
98
  "value": version_id,
100
- }))?),
99
+ }))),
101
100
  metadata: None,
102
101
  origin: None,
103
- schema_version: KEY_VALUE_SCHEMA_VERSION.to_string(),
104
102
  created_at: None,
105
103
  updated_at: None,
106
104
  global: true,
@@ -110,12 +108,3 @@ fn workspace_version_stage_row(version_id: &str) -> Result<StageRow, LixError> {
110
108
  version_id: GLOBAL_VERSION_ID.to_string(),
111
109
  })
112
110
  }
113
-
114
- fn encode_snapshot(value: serde_json::Value) -> Result<String, LixError> {
115
- serde_json::to_string(&value).map_err(|error| {
116
- LixError::new(
117
- "LIX_ERROR_UNKNOWN",
118
- format!("engine2 switch_version snapshot serialization failed: {error}"),
119
- )
120
- })
121
- }
@@ -0,0 +1,76 @@
1
+ use std::sync::Arc;
2
+
3
+ use crate::functions::FunctionContext;
4
+ use crate::transaction::{open_transaction, Transaction};
5
+ use crate::LixError;
6
+
7
+ use super::context::SessionTransactionGuard;
8
+ use super::SessionContext;
9
+
10
+ pub struct SessionTransaction {
11
+ pub(super) transaction: Option<Transaction>,
12
+ pub(super) runtime_functions: FunctionContext,
13
+ _transaction_guard: SessionTransactionGuard,
14
+ }
15
+
16
+ impl SessionContext {
17
+ pub async fn begin_transaction(&self) -> Result<SessionTransaction, LixError> {
18
+ self.ensure_open()?;
19
+ let transaction_guard = self.reserve_session_transaction()?;
20
+ let opened = match open_transaction(
21
+ &self.mode,
22
+ self.storage.clone(),
23
+ Arc::clone(&self.live_state),
24
+ Arc::clone(&self.tracked_state),
25
+ Arc::clone(&self.binary_cas),
26
+ Arc::clone(&self.commit_store),
27
+ Arc::clone(&self.version_ctx),
28
+ Arc::clone(&self.catalog_context),
29
+ )
30
+ .await
31
+ {
32
+ Ok(opened) => opened,
33
+ Err(error) => {
34
+ return Err(error);
35
+ }
36
+ };
37
+ Ok(SessionTransaction {
38
+ transaction: Some(opened.transaction),
39
+ runtime_functions: opened.runtime_functions,
40
+ _transaction_guard: transaction_guard,
41
+ })
42
+ }
43
+ }
44
+
45
+ impl SessionTransaction {
46
+ pub(super) fn transaction_mut(&mut self) -> Result<&mut Transaction, LixError> {
47
+ self.transaction
48
+ .as_mut()
49
+ .ok_or_else(|| transaction_state_error("Lix transaction is closed"))
50
+ }
51
+
52
+ pub async fn commit(mut self) -> Result<(), LixError> {
53
+ let transaction = self
54
+ .transaction
55
+ .take()
56
+ .ok_or_else(|| transaction_state_error("Lix transaction is closed"))?;
57
+ let result = transaction
58
+ .commit(&self.runtime_functions)
59
+ .await
60
+ .map(|_| ());
61
+ result
62
+ }
63
+
64
+ pub async fn rollback(mut self) -> Result<(), LixError> {
65
+ let transaction = self
66
+ .transaction
67
+ .take()
68
+ .ok_or_else(|| transaction_state_error("Lix transaction is closed"))?;
69
+ let result = transaction.rollback().await;
70
+ result
71
+ }
72
+ }
73
+
74
+ pub(crate) fn transaction_state_error(message: impl Into<String>) -> LixError {
75
+ LixError::new("LIX_INVALID_TRANSACTION_STATE", message)
76
+ }
@@ -18,17 +18,18 @@ use datafusion::physical_plan::{
18
18
  };
19
19
  use futures_util::stream;
20
20
 
21
- use crate::changelog::{materialize_change, ChangelogScanRequest, MaterializedCanonicalChange};
21
+ use crate::commit_store::ChangeScanRequest;
22
22
  use crate::serialize_row_metadata;
23
23
  use crate::LixError;
24
24
 
25
25
  use super::record_batch::record_batch_with_row_count;
26
26
  use super::result_metadata::json_field;
27
- use super::SqlChangelogQuerySource;
27
+ use super::SqlCommitStoreQuerySource;
28
+ use crate::commit_store::{materialize_change, MaterializedChange};
28
29
 
29
30
  pub(crate) async fn register_lix_change_provider(
30
31
  session: &datafusion::prelude::SessionContext,
31
- query_source: SqlChangelogQuerySource,
32
+ query_source: SqlCommitStoreQuerySource,
32
33
  ) -> Result<(), LixError> {
33
34
  session
34
35
  .register_table("lix_change", Arc::new(LixChangeProvider::new(query_source)))
@@ -38,7 +39,7 @@ pub(crate) async fn register_lix_change_provider(
38
39
 
39
40
  struct LixChangeProvider {
40
41
  schema: SchemaRef,
41
- query_source: SqlChangelogQuerySource,
42
+ query_source: SqlCommitStoreQuerySource,
42
43
  }
43
44
 
44
45
  impl std::fmt::Debug for LixChangeProvider {
@@ -48,7 +49,7 @@ impl std::fmt::Debug for LixChangeProvider {
48
49
  }
49
50
 
50
51
  impl LixChangeProvider {
51
- fn new(query_source: SqlChangelogQuerySource) -> Self {
52
+ fn new(query_source: SqlCommitStoreQuerySource) -> Self {
52
53
  Self {
53
54
  schema: lix_change_schema(),
54
55
  query_source,
@@ -97,7 +98,7 @@ impl TableProvider for LixChangeProvider {
97
98
  }
98
99
 
99
100
  struct LixChangeScanExec {
100
- query_source: SqlChangelogQuerySource,
101
+ query_source: SqlCommitStoreQuerySource,
101
102
  schema: SchemaRef,
102
103
  projection: Option<Vec<usize>>,
103
104
  limit: Option<usize>,
@@ -112,7 +113,7 @@ impl std::fmt::Debug for LixChangeScanExec {
112
113
 
113
114
  impl LixChangeScanExec {
114
115
  fn new(
115
- query_source: SqlChangelogQuerySource,
116
+ query_source: SqlCommitStoreQuerySource,
116
117
  schema: SchemaRef,
117
118
  projection: Option<Vec<usize>>,
118
119
  limit: Option<usize>,
@@ -191,8 +192,8 @@ impl ExecutionPlan for LixChangeScanExec {
191
192
  let stream = stream::once(async move {
192
193
  let mut json_reader = query_source.json_reader;
193
194
  let canonical_changes = query_source
194
- .changelog_reader
195
- .scan_changes(&ChangelogScanRequest { limit })
195
+ .commit_store_reader
196
+ .scan_changes(&ChangeScanRequest { limit })
196
197
  .await
197
198
  .map_err(lix_error_to_datafusion_error)?;
198
199
  let mut changes = Vec::with_capacity(canonical_changes.len());
@@ -214,7 +215,6 @@ enum ChangeColumn {
214
215
  Id,
215
216
  EntityId,
216
217
  SchemaKey,
217
- SchemaVersion,
218
218
  FileId,
219
219
  Metadata,
220
220
  CreatedAt,
@@ -224,9 +224,8 @@ enum ChangeColumn {
224
224
  fn lix_change_schema() -> SchemaRef {
225
225
  Arc::new(Schema::new(vec![
226
226
  Field::new("id", DataType::Utf8, false),
227
- Field::new("entity_id", DataType::Utf8, false),
227
+ json_field("entity_id", false),
228
228
  Field::new("schema_key", DataType::Utf8, false),
229
- Field::new("schema_version", DataType::Utf8, false),
230
229
  Field::new("file_id", DataType::Utf8, true),
231
230
  json_field("metadata", true),
232
231
  Field::new("created_at", DataType::Utf8, false),
@@ -239,7 +238,6 @@ fn change_projection_for_scan(projection: Option<&Vec<usize>>) -> Vec<ChangeColu
239
238
  ChangeColumn::Id,
240
239
  ChangeColumn::EntityId,
241
240
  ChangeColumn::SchemaKey,
242
- ChangeColumn::SchemaVersion,
243
241
  ChangeColumn::FileId,
244
242
  ChangeColumn::Metadata,
245
243
  ChangeColumn::CreatedAt,
@@ -262,7 +260,7 @@ fn projected_schema(schema: &SchemaRef, projection: Option<&Vec<usize>>) -> Sche
262
260
 
263
261
  fn change_record_batch(
264
262
  projection: &[ChangeColumn],
265
- changes: &[MaterializedCanonicalChange],
263
+ changes: &[MaterializedChange],
266
264
  ) -> Result<RecordBatch> {
267
265
  let arrays = projection
268
266
  .iter()
@@ -274,7 +272,7 @@ fn change_record_batch(
274
272
  .map(|row| {
275
273
  Some(
276
274
  row.entity_id
277
- .as_string()
275
+ .as_json_array_text()
278
276
  .expect("canonical change entity identity should project"),
279
277
  )
280
278
  })
@@ -283,9 +281,6 @@ fn change_record_batch(
283
281
  ChangeColumn::SchemaKey => {
284
282
  string_array(changes.iter().map(|row| Some(row.schema_key.as_str())))
285
283
  }
286
- ChangeColumn::SchemaVersion => {
287
- string_array(changes.iter().map(|row| Some(row.schema_version.as_str())))
288
- }
289
284
  ChangeColumn::FileId => string_array(changes.iter().map(|row| row.file_id.as_deref())),
290
285
  ChangeColumn::Metadata => Arc::new(StringArray::from(
291
286
  changes
@@ -312,9 +307,8 @@ fn change_schema(projection: &[ChangeColumn]) -> SchemaRef {
312
307
  .iter()
313
308
  .map(|column| match column {
314
309
  ChangeColumn::Id => Field::new("id", DataType::Utf8, false),
315
- ChangeColumn::EntityId => Field::new("entity_id", DataType::Utf8, false),
310
+ ChangeColumn::EntityId => json_field("entity_id", false),
316
311
  ChangeColumn::SchemaKey => Field::new("schema_key", DataType::Utf8, false),
317
- ChangeColumn::SchemaVersion => Field::new("schema_version", DataType::Utf8, false),
318
312
  ChangeColumn::FileId => Field::new("file_id", DataType::Utf8, true),
319
313
  ChangeColumn::Metadata => json_field("metadata", true),
320
314
  ChangeColumn::CreatedAt => Field::new("created_at", DataType::Utf8, false),