@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.
- package/README.md +1 -1
- package/SKILL.md +105 -65
- package/dist/engine-wasm/index.js +4 -4
- package/dist/engine-wasm/wasm/lix_engine.d.ts +30 -6
- package/dist/engine-wasm/wasm/lix_engine.js +187 -117
- package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
- package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +14 -8
- package/dist/generated/builtin-schemas.d.ts +69 -69
- package/dist/generated/builtin-schemas.js +94 -94
- package/dist/open-lix.d.ts +42 -28
- package/dist/open-lix.js +49 -10
- package/dist/sqlite/index.js +86 -30
- package/dist-engine-src/README.md +3 -3
- package/dist-engine-src/src/backend/capabilities.rs +67 -0
- package/dist-engine-src/src/backend/conformance/baseline.rs +1127 -0
- package/dist-engine-src/src/backend/conformance/factory.rs +93 -0
- package/dist-engine-src/src/backend/conformance/failure_tests.rs +608 -0
- package/dist-engine-src/src/backend/conformance/fixtures.rs +26 -0
- package/dist-engine-src/src/backend/conformance/mod.rs +75 -0
- package/dist-engine-src/src/backend/conformance/model.rs +28 -0
- package/dist-engine-src/src/backend/conformance/model_based.rs +257 -0
- package/dist-engine-src/src/backend/conformance/persistence.rs +204 -0
- package/dist-engine-src/src/backend/conformance/projection.rs +21 -0
- package/dist-engine-src/src/backend/conformance/pushdown.rs +24 -0
- package/dist-engine-src/src/backend/conformance/runner.rs +90 -0
- package/dist-engine-src/src/backend/conformance/scan.rs +24 -0
- package/dist-engine-src/src/backend/conformance/write.rs +16 -0
- package/dist-engine-src/src/backend/error.rs +94 -0
- package/dist-engine-src/src/backend/in_memory.rs +670 -0
- package/dist-engine-src/src/backend/mod.rs +36 -9
- package/dist-engine-src/src/backend/predicate.rs +80 -0
- package/dist-engine-src/src/backend/traits.rs +260 -0
- package/dist-engine-src/src/backend/types.rs +224 -81
- package/dist-engine-src/src/binary_cas/context.rs +8 -8
- package/dist-engine-src/src/binary_cas/kv.rs +234 -259
- package/dist-engine-src/src/{version → branch}/context.rs +12 -12
- package/dist-engine-src/src/branch/lifecycle.rs +221 -0
- package/dist-engine-src/src/branch/mod.rs +13 -0
- package/dist-engine-src/src/branch/refs.rs +321 -0
- package/dist-engine-src/src/branch/stage_rows.rs +67 -0
- package/dist-engine-src/src/branch/types.rs +21 -0
- package/dist-engine-src/src/catalog/context.rs +18 -18
- package/dist-engine-src/src/catalog/snapshot.rs +8 -8
- package/dist-engine-src/src/changelog/bench_support.rs +785 -0
- package/dist-engine-src/src/changelog/change.rs +1 -0
- package/dist-engine-src/src/changelog/codec.rs +497 -0
- package/dist-engine-src/src/changelog/commit.rs +1 -0
- package/dist-engine-src/src/changelog/context.rs +1614 -0
- package/dist-engine-src/src/changelog/mod.rs +29 -0
- package/dist-engine-src/src/changelog/store.rs +163 -0
- package/dist-engine-src/src/changelog/test_support.rs +54 -0
- package/dist-engine-src/src/changelog/types.rs +213 -0
- package/dist-engine-src/src/commit_graph/context.rs +317 -274
- package/dist-engine-src/src/commit_graph/mod.rs +2 -4
- package/dist-engine-src/src/commit_graph/types.rs +22 -42
- package/dist-engine-src/src/commit_graph/walker.rs +133 -103
- package/dist-engine-src/src/common/error.rs +52 -18
- package/dist-engine-src/src/common/identity.rs +2 -2
- package/dist-engine-src/src/common/mod.rs +1 -1
- package/dist-engine-src/src/domain.rs +42 -46
- package/dist-engine-src/src/engine.rs +74 -96
- package/dist-engine-src/src/{entity_identity.rs → entity_pk.rs} +89 -92
- package/dist-engine-src/src/functions/context.rs +56 -52
- package/dist-engine-src/src/functions/state.rs +51 -52
- package/dist-engine-src/src/init.rs +288 -154
- package/dist-engine-src/src/json_store/context.rs +15 -266
- package/dist-engine-src/src/json_store/mod.rs +26 -0
- package/dist-engine-src/src/json_store/store.rs +103 -718
- package/dist-engine-src/src/json_store/types.rs +4 -9
- package/dist-engine-src/src/lib.rs +49 -19
- package/dist-engine-src/src/live_state/context.rs +654 -790
- package/dist-engine-src/src/live_state/mod.rs +9 -3
- package/dist-engine-src/src/live_state/overlay.rs +4 -4
- package/dist-engine-src/src/live_state/types.rs +30 -21
- package/dist-engine-src/src/live_state/visibility.rs +514 -71
- package/dist-engine-src/src/plugin/install.rs +48 -48
- package/dist-engine-src/src/plugin/manifest.rs +7 -7
- package/dist-engine-src/src/plugin/materializer.rs +0 -275
- package/dist-engine-src/src/plugin/plugin_manifest.json +4 -3
- package/dist-engine-src/src/schema/builtin/lix_binary_blob_ref.json +2 -2
- package/dist-engine-src/src/schema/builtin/lix_branch_descriptor.json +34 -0
- package/dist-engine-src/src/schema/builtin/lix_branch_ref.json +48 -0
- package/dist-engine-src/src/schema/builtin/lix_change.json +3 -3
- package/dist-engine-src/src/schema/builtin/lix_commit.json +1 -1
- package/dist-engine-src/src/schema/builtin/lix_label_assignment.json +6 -6
- package/dist-engine-src/src/schema/builtin/mod.rs +18 -20
- package/dist-engine-src/src/schema/compatibility.rs +11 -11
- package/dist-engine-src/src/schema/definition.json +2 -2
- package/dist-engine-src/src/schema/definition.rs +5 -5
- package/dist-engine-src/src/schema/key.rs +3 -3
- package/dist-engine-src/src/schema/mod.rs +1 -1
- package/dist-engine-src/src/schema/tests.rs +18 -18
- package/dist-engine-src/src/session/context.rs +819 -124
- package/dist-engine-src/src/session/create_branch.rs +94 -0
- package/dist-engine-src/src/session/execute.rs +260 -57
- package/dist-engine-src/src/session/merge/analysis.rs +9 -3
- package/dist-engine-src/src/session/merge/{version.rs → branch.rs} +119 -129
- package/dist-engine-src/src/session/merge/conflicts.rs +2 -2
- package/dist-engine-src/src/session/merge/mod.rs +5 -6
- package/dist-engine-src/src/session/merge/stats.rs +7 -11
- package/dist-engine-src/src/session/mod.rs +19 -16
- package/dist-engine-src/src/session/switch_branch.rs +113 -0
- package/dist-engine-src/src/session/transaction.rs +557 -0
- package/dist-engine-src/src/sql2/bind/classify.rs +102 -0
- package/dist-engine-src/src/sql2/bind/error.rs +5 -0
- package/dist-engine-src/src/sql2/bind/expr.rs +29 -0
- package/dist-engine-src/src/sql2/bind/mod.rs +12 -0
- package/dist-engine-src/src/sql2/{udfs/public_call.rs → bind/public_udf.rs} +98 -3
- package/dist-engine-src/src/sql2/bind/read.rs +65 -0
- package/dist-engine-src/src/sql2/bind/statement.rs +2236 -0
- package/dist-engine-src/src/sql2/bind/table.rs +273 -0
- package/dist-engine-src/src/sql2/bind/write.rs +86 -0
- package/dist-engine-src/src/sql2/branch_scope.rs +436 -0
- package/dist-engine-src/src/sql2/catalog/capability.rs +20 -0
- package/dist-engine-src/src/sql2/catalog/entity_surface.rs +296 -0
- package/dist-engine-src/src/sql2/catalog/mod.rs +15 -0
- package/dist-engine-src/src/sql2/catalog/registry.rs +556 -0
- package/dist-engine-src/src/sql2/catalog/schema.rs +88 -0
- package/dist-engine-src/src/sql2/catalog/surface.rs +41 -0
- package/dist-engine-src/src/sql2/change_materialization.rs +122 -0
- package/dist-engine-src/src/sql2/context.rs +36 -30
- package/dist-engine-src/src/sql2/error.rs +4 -5
- package/dist-engine-src/src/sql2/exec/bound_public_write.rs +1593 -0
- package/dist-engine-src/src/sql2/exec/datafusion.rs +5266 -0
- package/dist-engine-src/src/sql2/exec/fast_write.rs +82 -0
- package/dist-engine-src/src/sql2/exec/mod.rs +24 -0
- package/dist-engine-src/src/sql2/exec/write.rs +661 -0
- package/dist-engine-src/src/sql2/filesystem_planner.rs +72 -77
- package/dist-engine-src/src/sql2/filesystem_visibility.rs +21 -21
- package/dist-engine-src/src/sql2/history_projection.rs +8 -8
- package/dist-engine-src/src/sql2/history_route.rs +35 -31
- package/dist-engine-src/src/sql2/mod.rs +30 -24
- package/dist-engine-src/src/sql2/optimize/datafusion.rs +1 -0
- package/dist-engine-src/src/sql2/optimize/mod.rs +2 -0
- package/dist-engine-src/src/sql2/optimize/simple_write.rs +116 -0
- package/dist-engine-src/src/sql2/parse/mod.rs +69 -0
- package/dist-engine-src/src/sql2/parse/normalize.rs +1 -0
- package/dist-engine-src/src/sql2/plan/branch_scope.rs +24 -0
- package/dist-engine-src/src/sql2/plan/mod.rs +5 -0
- package/dist-engine-src/src/sql2/plan/predicate.rs +22 -0
- package/dist-engine-src/src/sql2/plan/write.rs +147 -0
- package/dist-engine-src/src/sql2/predicate_typecheck.rs +258 -0
- package/dist-engine-src/src/sql2/{version_provider.rs → providers/branch.rs} +218 -214
- package/dist-engine-src/src/sql2/{change_provider.rs → providers/change.rs} +156 -42
- package/dist-engine-src/src/sql2/{directory_provider.rs → providers/directory.rs} +291 -322
- package/dist-engine-src/src/sql2/{directory_history_provider.rs → providers/directory_history.rs} +56 -42
- package/dist-engine-src/src/sql2/providers/entity.rs +1484 -0
- package/dist-engine-src/src/sql2/{entity_history_provider.rs → providers/entity_history.rs} +43 -31
- package/dist-engine-src/src/sql2/{file_provider.rs → providers/file.rs} +323 -316
- package/dist-engine-src/src/sql2/{file_history_provider.rs → providers/file_history.rs} +60 -46
- package/dist-engine-src/src/sql2/{history_provider.rs → providers/history.rs} +46 -32
- package/dist-engine-src/src/sql2/{lix_state_provider.rs → providers/lix_state.rs} +359 -329
- package/dist-engine-src/src/sql2/providers/mod.rs +508 -0
- package/dist-engine-src/src/sql2/read_only.rs +2 -2
- package/dist-engine-src/src/sql2/session.rs +47 -96
- package/dist-engine-src/src/sql2/storage/constraints.rs +1 -0
- package/dist-engine-src/src/sql2/storage/mod.rs +1 -0
- package/dist-engine-src/src/sql2/test_support/differential.rs +712 -0
- package/dist-engine-src/src/sql2/test_support/generators.rs +354 -0
- package/dist-engine-src/src/sql2/test_support/mod.rs +2 -0
- package/dist-engine-src/src/sql2/udfs/{lix_active_version_commit_id.rs → lix_active_branch_commit_id.rs} +7 -7
- package/dist-engine-src/src/sql2/udfs/mod.rs +3 -6
- package/dist-engine-src/src/sql2/write_normalization.rs +45 -22
- package/dist-engine-src/src/storage/conformance.rs +399 -0
- package/dist-engine-src/src/storage/context.rs +552 -288
- package/dist-engine-src/src/storage/mod.rs +48 -10
- package/dist-engine-src/src/storage/point.rs +440 -0
- package/dist-engine-src/src/storage/read_scope.rs +43 -64
- package/dist-engine-src/src/storage/reader.rs +867 -0
- package/dist-engine-src/src/storage/scan.rs +784 -0
- package/dist-engine-src/src/storage/spaces.rs +236 -0
- package/dist-engine-src/src/storage/stats.rs +80 -0
- package/dist-engine-src/src/storage/write_set.rs +962 -0
- package/dist-engine-src/src/storage_bench.rs +136 -4828
- package/dist-engine-src/src/test_support.rs +360 -138
- package/dist-engine-src/src/tracked_state/bench_support.rs +394 -0
- package/dist-engine-src/src/tracked_state/codec.rs +155 -1057
- package/dist-engine-src/src/tracked_state/commit_root_rebuild.rs +358 -0
- package/dist-engine-src/src/tracked_state/context.rs +1927 -993
- package/dist-engine-src/src/tracked_state/diff.rs +1715 -261
- package/dist-engine-src/src/tracked_state/merge.rs +74 -88
- package/dist-engine-src/src/tracked_state/mod.rs +19 -16
- package/dist-engine-src/src/tracked_state/{materialization.rs → row_materialization.rs} +50 -178
- package/dist-engine-src/src/tracked_state/storage.rs +243 -191
- package/dist-engine-src/src/tracked_state/tree.rs +247 -371
- package/dist-engine-src/src/tracked_state/types.rs +49 -42
- package/dist-engine-src/src/transaction/bench_support.rs +407 -0
- package/dist-engine-src/src/transaction/commit.rs +821 -713
- package/dist-engine-src/src/transaction/context.rs +705 -600
- package/dist-engine-src/src/transaction/mod.rs +13 -2
- package/dist-engine-src/src/transaction/normalization.rs +63 -76
- package/dist-engine-src/src/transaction/prep.rs +13 -13
- package/dist-engine-src/src/transaction/schema_resolver.rs +19 -5
- package/dist-engine-src/src/transaction/staging.rs +228 -434
- package/dist-engine-src/src/transaction/types.rs +41 -98
- package/dist-engine-src/src/transaction/validation.rs +382 -446
- package/dist-engine-src/src/untracked_state/codec.rs +337 -29
- package/dist-engine-src/src/untracked_state/context.rs +7 -7
- package/dist-engine-src/src/untracked_state/materialization.rs +2 -2
- package/dist-engine-src/src/untracked_state/mod.rs +1 -1
- package/dist-engine-src/src/untracked_state/storage.rs +659 -157
- package/dist-engine-src/src/untracked_state/types.rs +21 -21
- package/package.json +71 -68
- package/dist-engine-src/src/backend/kv.rs +0 -358
- package/dist-engine-src/src/backend/testing.rs +0 -658
- package/dist-engine-src/src/commit_store/codec.rs +0 -887
- package/dist-engine-src/src/commit_store/context.rs +0 -944
- package/dist-engine-src/src/commit_store/materialization.rs +0 -84
- package/dist-engine-src/src/commit_store/mod.rs +0 -16
- package/dist-engine-src/src/commit_store/storage.rs +0 -600
- package/dist-engine-src/src/commit_store/types.rs +0 -215
- package/dist-engine-src/src/schema/builtin/lix_version_descriptor.json +0 -34
- package/dist-engine-src/src/schema/builtin/lix_version_ref.json +0 -48
- package/dist-engine-src/src/session/create_version.rs +0 -88
- package/dist-engine-src/src/session/merge/apply.rs +0 -23
- package/dist-engine-src/src/session/optimization9_sql2_bench.rs +0 -100
- package/dist-engine-src/src/session/switch_version.rs +0 -109
- package/dist-engine-src/src/sql2/classify.rs +0 -182
- package/dist-engine-src/src/sql2/entity_provider.rs +0 -3211
- package/dist-engine-src/src/sql2/execute.rs +0 -3440
- package/dist-engine-src/src/sql2/public_bind/assignment.rs +0 -46
- package/dist-engine-src/src/sql2/public_bind/capability.rs +0 -41
- package/dist-engine-src/src/sql2/public_bind/dml.rs +0 -166
- package/dist-engine-src/src/sql2/public_bind/mod.rs +0 -25
- package/dist-engine-src/src/sql2/public_bind/table.rs +0 -168
- package/dist-engine-src/src/sql2/version_scope.rs +0 -394
- package/dist-engine-src/src/storage/types.rs +0 -501
- package/dist-engine-src/src/tracked_state/by_file_index.rs +0 -98
- package/dist-engine-src/src/tracked_state/materializer.rs +0 -488
- package/dist-engine-src/src/transaction/live_state_overlay.rs +0 -35
- package/dist-engine-src/src/version/lifecycle.rs +0 -221
- package/dist-engine-src/src/version/mod.rs +0 -13
- package/dist-engine-src/src/version/refs.rs +0 -330
- package/dist-engine-src/src/version/stage_rows.rs +0 -67
- package/dist-engine-src/src/version/types.rs +0 -21
|
@@ -25,70 +25,88 @@ use datafusion::scalar::ScalarValue;
|
|
|
25
25
|
use futures_util::{stream, TryStreamExt};
|
|
26
26
|
use serde_json::Value as JsonValue;
|
|
27
27
|
|
|
28
|
-
use crate::
|
|
28
|
+
use crate::branch::BranchRefReader;
|
|
29
|
+
use crate::entity_pk::EntityPk;
|
|
29
30
|
use crate::live_state::MaterializedLiveStateRow;
|
|
30
31
|
use crate::live_state::{
|
|
31
|
-
LiveStateFilter, LiveStateProjection, LiveStateReader, LiveStateScanRequest,
|
|
32
|
+
LiveStateFilter, LiveStateProjection, LiveStateReader, LiveStateRowFilter, LiveStateScanRequest,
|
|
32
33
|
};
|
|
34
|
+
use crate::sql2::branch_scope::{resolve_provider_branch_ids, BranchBinding};
|
|
33
35
|
use crate::sql2::dml::{InsertExec, InsertSink};
|
|
34
36
|
use crate::sql2::read_only::reject_read_only_stage_rows;
|
|
35
|
-
use crate::sql2::version_scope::{resolve_provider_version_ids, VersionBinding};
|
|
36
37
|
use crate::sql2::write_normalization::{InsertCell, SqlCell, UpdateAssignmentValues};
|
|
37
38
|
use crate::transaction::types::{TransactionJson, TransactionWriteRow};
|
|
38
|
-
use crate::
|
|
39
|
-
use crate::GLOBAL_VERSION_ID;
|
|
39
|
+
use crate::GLOBAL_BRANCH_ID;
|
|
40
40
|
use crate::{parse_row_metadata_value, serialize_row_metadata, LixError, NullableKeyFilter};
|
|
41
41
|
|
|
42
42
|
use crate::sql2::{
|
|
43
|
-
SqlWriteContext, WriteAccess,
|
|
43
|
+
SqlWriteContext, WriteAccess, WriteContextBranchRefReader, WriteContextLiveStateReader,
|
|
44
44
|
};
|
|
45
45
|
use crate::transaction::types::{TransactionWrite, TransactionWriteMode};
|
|
46
46
|
|
|
47
|
-
use
|
|
48
|
-
|
|
47
|
+
use crate::sql2::predicate_typecheck::{
|
|
48
|
+
canonicalize_json_identity_text_filters, validate_json_predicate_filters,
|
|
49
|
+
};
|
|
50
|
+
use crate::sql2::result_metadata::json_field;
|
|
49
51
|
|
|
50
|
-
pub(
|
|
52
|
+
pub(super) async fn register_lix_state_active_provider(
|
|
51
53
|
session: &SessionContext,
|
|
52
|
-
|
|
54
|
+
surface_name: &str,
|
|
55
|
+
active_branch_id: &str,
|
|
53
56
|
live_state: Arc<dyn LiveStateReader>,
|
|
54
|
-
|
|
57
|
+
branch_ref: Arc<dyn BranchRefReader>,
|
|
55
58
|
) -> Result<(), LixError> {
|
|
56
59
|
session
|
|
57
60
|
.register_table(
|
|
58
|
-
|
|
59
|
-
Arc::new(LixStateProvider::
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
surface_name,
|
|
62
|
+
Arc::new(LixStateProvider::active_branch(
|
|
63
|
+
active_branch_id,
|
|
64
|
+
live_state,
|
|
65
|
+
branch_ref,
|
|
62
66
|
)),
|
|
63
67
|
)
|
|
64
68
|
.map_err(datafusion_error_to_lix_error)?;
|
|
69
|
+
Ok(())
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
pub(super) async fn register_lix_state_by_branch_provider(
|
|
73
|
+
session: &SessionContext,
|
|
74
|
+
surface_name: &str,
|
|
75
|
+
live_state: Arc<dyn LiveStateReader>,
|
|
76
|
+
branch_ref: Arc<dyn BranchRefReader>,
|
|
77
|
+
) -> Result<(), LixError> {
|
|
65
78
|
session
|
|
66
79
|
.register_table(
|
|
67
|
-
|
|
68
|
-
Arc::new(LixStateProvider::
|
|
69
|
-
active_version_id,
|
|
70
|
-
live_state,
|
|
71
|
-
version_ref,
|
|
72
|
-
)),
|
|
80
|
+
surface_name,
|
|
81
|
+
Arc::new(LixStateProvider::by_branch(live_state, branch_ref)),
|
|
73
82
|
)
|
|
74
83
|
.map_err(datafusion_error_to_lix_error)?;
|
|
75
84
|
Ok(())
|
|
76
85
|
}
|
|
77
86
|
|
|
78
|
-
pub(
|
|
87
|
+
pub(super) async fn register_lix_state_by_branch_write_provider(
|
|
79
88
|
session: &SessionContext,
|
|
89
|
+
surface_name: &str,
|
|
80
90
|
write_ctx: SqlWriteContext,
|
|
81
91
|
) -> Result<(), LixError> {
|
|
82
92
|
session
|
|
83
93
|
.register_table(
|
|
84
|
-
|
|
85
|
-
Arc::new(LixStateProvider::
|
|
94
|
+
surface_name,
|
|
95
|
+
Arc::new(LixStateProvider::by_branch_with_write(write_ctx)),
|
|
86
96
|
)
|
|
87
97
|
.map_err(datafusion_error_to_lix_error)?;
|
|
98
|
+
Ok(())
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
pub(super) async fn register_lix_state_active_write_provider(
|
|
102
|
+
session: &SessionContext,
|
|
103
|
+
surface_name: &str,
|
|
104
|
+
write_ctx: SqlWriteContext,
|
|
105
|
+
) -> Result<(), LixError> {
|
|
88
106
|
session
|
|
89
107
|
.register_table(
|
|
90
|
-
|
|
91
|
-
Arc::new(LixStateProvider::
|
|
108
|
+
surface_name,
|
|
109
|
+
Arc::new(LixStateProvider::active_branch_with_write(write_ctx)),
|
|
92
110
|
)
|
|
93
111
|
.map_err(datafusion_error_to_lix_error)?;
|
|
94
112
|
Ok(())
|
|
@@ -97,9 +115,9 @@ pub(crate) async fn register_lix_state_write_providers(
|
|
|
97
115
|
pub(crate) struct LixStateProvider {
|
|
98
116
|
schema: SchemaRef,
|
|
99
117
|
live_state: Arc<dyn LiveStateReader>,
|
|
100
|
-
|
|
118
|
+
branch_ref: Arc<dyn BranchRefReader>,
|
|
101
119
|
write_access: WriteAccess,
|
|
102
|
-
|
|
120
|
+
branch_binding: BranchBinding,
|
|
103
121
|
}
|
|
104
122
|
|
|
105
123
|
impl std::fmt::Debug for LixStateProvider {
|
|
@@ -111,55 +129,55 @@ impl std::fmt::Debug for LixStateProvider {
|
|
|
111
129
|
}
|
|
112
130
|
|
|
113
131
|
impl LixStateProvider {
|
|
114
|
-
pub(crate) fn
|
|
115
|
-
|
|
132
|
+
pub(crate) fn active_branch(
|
|
133
|
+
active_branch_id: impl Into<String>,
|
|
116
134
|
live_state: Arc<dyn LiveStateReader>,
|
|
117
|
-
|
|
135
|
+
branch_ref: Arc<dyn BranchRefReader>,
|
|
118
136
|
) -> Self {
|
|
119
137
|
Self {
|
|
120
138
|
schema: lix_state_schema(),
|
|
121
139
|
live_state,
|
|
122
|
-
|
|
140
|
+
branch_ref,
|
|
123
141
|
write_access: WriteAccess::read_only(),
|
|
124
|
-
|
|
142
|
+
branch_binding: BranchBinding::active(active_branch_id),
|
|
125
143
|
}
|
|
126
144
|
}
|
|
127
145
|
|
|
128
|
-
pub(crate) fn
|
|
129
|
-
let
|
|
146
|
+
pub(crate) fn active_branch_with_write(write_ctx: SqlWriteContext) -> Self {
|
|
147
|
+
let active_branch_id = write_ctx.active_branch_id();
|
|
130
148
|
let live_state = Arc::new(WriteContextLiveStateReader::new(write_ctx.clone()));
|
|
131
|
-
let
|
|
149
|
+
let branch_ref = Arc::new(WriteContextBranchRefReader::new(write_ctx.clone()));
|
|
132
150
|
Self {
|
|
133
151
|
schema: lix_state_schema(),
|
|
134
152
|
live_state,
|
|
135
|
-
|
|
153
|
+
branch_ref,
|
|
136
154
|
write_access: WriteAccess::write(write_ctx),
|
|
137
|
-
|
|
155
|
+
branch_binding: BranchBinding::active(active_branch_id),
|
|
138
156
|
}
|
|
139
157
|
}
|
|
140
158
|
|
|
141
|
-
pub(crate) fn
|
|
159
|
+
pub(crate) fn by_branch(
|
|
142
160
|
live_state: Arc<dyn LiveStateReader>,
|
|
143
|
-
|
|
161
|
+
branch_ref: Arc<dyn BranchRefReader>,
|
|
144
162
|
) -> Self {
|
|
145
163
|
Self {
|
|
146
|
-
schema:
|
|
164
|
+
schema: lix_state_by_branch_schema(),
|
|
147
165
|
live_state,
|
|
148
|
-
|
|
166
|
+
branch_ref,
|
|
149
167
|
write_access: WriteAccess::read_only(),
|
|
150
|
-
|
|
168
|
+
branch_binding: BranchBinding::explicit(),
|
|
151
169
|
}
|
|
152
170
|
}
|
|
153
171
|
|
|
154
|
-
pub(crate) fn
|
|
172
|
+
pub(crate) fn by_branch_with_write(write_ctx: SqlWriteContext) -> Self {
|
|
155
173
|
let live_state = Arc::new(WriteContextLiveStateReader::new(write_ctx.clone()));
|
|
156
|
-
let
|
|
174
|
+
let branch_ref = Arc::new(WriteContextBranchRefReader::new(write_ctx.clone()));
|
|
157
175
|
Self {
|
|
158
|
-
schema:
|
|
176
|
+
schema: lix_state_by_branch_schema(),
|
|
159
177
|
live_state,
|
|
160
|
-
|
|
178
|
+
branch_ref,
|
|
161
179
|
write_access: WriteAccess::write(write_ctx),
|
|
162
|
-
|
|
180
|
+
branch_binding: BranchBinding::explicit(),
|
|
163
181
|
}
|
|
164
182
|
}
|
|
165
183
|
}
|
|
@@ -201,24 +219,22 @@ impl TableProvider for LixStateProvider {
|
|
|
201
219
|
filters: &[Expr],
|
|
202
220
|
limit: Option<usize>,
|
|
203
221
|
) -> Result<Arc<dyn datafusion::physical_plan::ExecutionPlan>> {
|
|
204
|
-
let route =
|
|
222
|
+
let route = LixStateByBranchRoute::from_filters(filters);
|
|
205
223
|
let projected_schema = projected_schema(&self.schema, projection)?;
|
|
206
224
|
let mut request = lix_state_scan_request(
|
|
207
225
|
&self.schema,
|
|
208
|
-
self.
|
|
226
|
+
self.branch_binding.active_branch_id(),
|
|
209
227
|
projection,
|
|
210
228
|
&route,
|
|
211
229
|
limit,
|
|
212
230
|
);
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
.map_err(lix_error_to_datafusion_error)?;
|
|
221
|
-
}
|
|
231
|
+
request.filter.branch_ids = resolve_provider_branch_ids(
|
|
232
|
+
self.branch_ref.as_ref(),
|
|
233
|
+
&self.branch_binding,
|
|
234
|
+
request.filter.branch_ids,
|
|
235
|
+
)
|
|
236
|
+
.await
|
|
237
|
+
.map_err(lix_error_to_datafusion_error)?;
|
|
222
238
|
Ok(Arc::new(LixStateScanExec::new(
|
|
223
239
|
Arc::clone(&self.live_state),
|
|
224
240
|
projected_schema,
|
|
@@ -236,21 +252,13 @@ impl TableProvider for LixStateProvider {
|
|
|
236
252
|
return not_impl_err!("{insert_op} not implemented for lix_state yet");
|
|
237
253
|
}
|
|
238
254
|
|
|
239
|
-
let active_version_id = self
|
|
240
|
-
.version_binding
|
|
241
|
-
.require_active_version_id("INSERT")
|
|
242
|
-
.map_err(lix_error_to_datafusion_error)?;
|
|
243
|
-
|
|
244
255
|
let write_ctx = self.write_access.require_write("INSERT into lix_state")?;
|
|
256
|
+
let branch_binding = self.branch_binding.active_branch_id().map(str::to_owned);
|
|
245
257
|
|
|
246
258
|
self.schema
|
|
247
259
|
.logically_equivalent_names_and_types(&input.schema())?;
|
|
248
260
|
|
|
249
|
-
let sink = LixStateInsertSink::new(
|
|
250
|
-
Arc::clone(&self.schema),
|
|
251
|
-
write_ctx.clone(),
|
|
252
|
-
active_version_id,
|
|
253
|
-
);
|
|
261
|
+
let sink = LixStateInsertSink::new(write_ctx.clone(), branch_binding);
|
|
254
262
|
Ok(Arc::new(InsertExec::new(input, Arc::new(sink))))
|
|
255
263
|
}
|
|
256
264
|
|
|
@@ -259,28 +267,25 @@ impl TableProvider for LixStateProvider {
|
|
|
259
267
|
state: &dyn Session,
|
|
260
268
|
filters: Vec<Expr>,
|
|
261
269
|
) -> Result<Arc<dyn ExecutionPlan>> {
|
|
262
|
-
let active_version_id = self
|
|
263
|
-
.version_binding
|
|
264
|
-
.require_active_version_id("DELETE")
|
|
265
|
-
.map_err(lix_error_to_datafusion_error)?;
|
|
266
|
-
|
|
267
270
|
let write_ctx = self.write_access.require_write("DELETE FROM lix_state")?;
|
|
268
271
|
|
|
269
272
|
let df_schema = DFSchema::try_from(Arc::clone(&self.schema))?;
|
|
273
|
+
let filters = canonicalize_json_identity_text_filters(self.schema.as_ref(), &filters)?;
|
|
270
274
|
validate_json_predicate_filters(self.schema.as_ref(), &filters)?;
|
|
271
275
|
let physical_filters = filters
|
|
272
276
|
.iter()
|
|
273
277
|
.map(|expr| create_physical_expr(expr, &df_schema, state.execution_props()))
|
|
274
278
|
.collect::<Result<Vec<_>>>()?;
|
|
275
279
|
|
|
276
|
-
let route =
|
|
280
|
+
let route = LixStateByBranchRoute::from_filters(&filters);
|
|
281
|
+
let branch_binding = self.branch_binding.active_branch_id().map(str::to_owned);
|
|
277
282
|
let request =
|
|
278
|
-
lix_state_scan_request(&self.schema,
|
|
283
|
+
lix_state_scan_request(&self.schema, branch_binding.as_deref(), None, &route, None);
|
|
279
284
|
|
|
280
285
|
Ok(Arc::new(LixStateDeleteExec::new(
|
|
281
286
|
write_ctx.clone(),
|
|
282
287
|
Arc::clone(&self.schema),
|
|
283
|
-
|
|
288
|
+
branch_binding,
|
|
284
289
|
request,
|
|
285
290
|
physical_filters,
|
|
286
291
|
)))
|
|
@@ -292,16 +297,11 @@ impl TableProvider for LixStateProvider {
|
|
|
292
297
|
assignments: Vec<(String, Expr)>,
|
|
293
298
|
filters: Vec<Expr>,
|
|
294
299
|
) -> Result<Arc<dyn ExecutionPlan>> {
|
|
295
|
-
let active_version_id = self
|
|
296
|
-
.version_binding
|
|
297
|
-
.require_active_version_id("UPDATE")
|
|
298
|
-
.map_err(lix_error_to_datafusion_error)?;
|
|
299
|
-
|
|
300
300
|
let write_ctx = self.write_access.require_write("UPDATE lix_state")?;
|
|
301
|
-
|
|
302
301
|
validate_lix_state_update_assignments(&self.schema, &assignments)?;
|
|
303
302
|
|
|
304
303
|
let df_schema = DFSchema::try_from(Arc::clone(&self.schema))?;
|
|
304
|
+
let filters = canonicalize_json_identity_text_filters(self.schema.as_ref(), &filters)?;
|
|
305
305
|
validate_json_predicate_filters(self.schema.as_ref(), &filters)?;
|
|
306
306
|
let physical_assignments = assignments
|
|
307
307
|
.iter()
|
|
@@ -317,14 +317,15 @@ impl TableProvider for LixStateProvider {
|
|
|
317
317
|
.map(|expr| create_physical_expr(expr, &df_schema, state.execution_props()))
|
|
318
318
|
.collect::<Result<Vec<_>>>()?;
|
|
319
319
|
|
|
320
|
-
let route =
|
|
320
|
+
let route = LixStateByBranchRoute::from_filters(&filters);
|
|
321
|
+
let branch_binding = self.branch_binding.active_branch_id().map(str::to_owned);
|
|
321
322
|
let request =
|
|
322
|
-
lix_state_scan_request(&self.schema,
|
|
323
|
+
lix_state_scan_request(&self.schema, branch_binding.as_deref(), None, &route, None);
|
|
323
324
|
|
|
324
325
|
Ok(Arc::new(LixStateUpdateExec::new(
|
|
325
326
|
write_ctx.clone(),
|
|
326
327
|
Arc::clone(&self.schema),
|
|
327
|
-
|
|
328
|
+
branch_binding,
|
|
328
329
|
request,
|
|
329
330
|
physical_assignments,
|
|
330
331
|
physical_filters,
|
|
@@ -334,7 +335,7 @@ impl TableProvider for LixStateProvider {
|
|
|
334
335
|
|
|
335
336
|
struct LixStateInsertSink {
|
|
336
337
|
write_ctx: SqlWriteContext,
|
|
337
|
-
|
|
338
|
+
branch_binding: Option<String>,
|
|
338
339
|
}
|
|
339
340
|
|
|
340
341
|
impl std::fmt::Debug for LixStateInsertSink {
|
|
@@ -344,10 +345,10 @@ impl std::fmt::Debug for LixStateInsertSink {
|
|
|
344
345
|
}
|
|
345
346
|
|
|
346
347
|
impl LixStateInsertSink {
|
|
347
|
-
fn new(
|
|
348
|
+
fn new(write_ctx: SqlWriteContext, branch_binding: Option<String>) -> Self {
|
|
348
349
|
Self {
|
|
349
350
|
write_ctx,
|
|
350
|
-
|
|
351
|
+
branch_binding,
|
|
351
352
|
}
|
|
352
353
|
}
|
|
353
354
|
}
|
|
@@ -374,7 +375,8 @@ impl InsertSink for LixStateInsertSink {
|
|
|
374
375
|
for batch in batches {
|
|
375
376
|
rows.extend(lix_state_write_rows_from_batch(
|
|
376
377
|
&batch,
|
|
377
|
-
|
|
378
|
+
self.branch_binding.as_deref(),
|
|
379
|
+
"INSERT into lix_state",
|
|
378
380
|
)?);
|
|
379
381
|
}
|
|
380
382
|
reject_read_only_stage_rows(&rows, "INSERT into lix_state")?;
|
|
@@ -397,7 +399,7 @@ impl InsertSink for LixStateInsertSink {
|
|
|
397
399
|
struct LixStateDeleteExec {
|
|
398
400
|
write_ctx: SqlWriteContext,
|
|
399
401
|
table_schema: SchemaRef,
|
|
400
|
-
|
|
402
|
+
branch_binding: Option<String>,
|
|
401
403
|
request: LiveStateScanRequest,
|
|
402
404
|
filters: Vec<Arc<dyn PhysicalExpr>>,
|
|
403
405
|
result_schema: SchemaRef,
|
|
@@ -414,7 +416,7 @@ impl LixStateDeleteExec {
|
|
|
414
416
|
fn new(
|
|
415
417
|
write_ctx: SqlWriteContext,
|
|
416
418
|
table_schema: SchemaRef,
|
|
417
|
-
|
|
419
|
+
branch_binding: Option<String>,
|
|
418
420
|
request: LiveStateScanRequest,
|
|
419
421
|
filters: Vec<Arc<dyn PhysicalExpr>>,
|
|
420
422
|
) -> Self {
|
|
@@ -428,7 +430,7 @@ impl LixStateDeleteExec {
|
|
|
428
430
|
Self {
|
|
429
431
|
write_ctx,
|
|
430
432
|
table_schema,
|
|
431
|
-
|
|
433
|
+
branch_binding,
|
|
432
434
|
request,
|
|
433
435
|
filters,
|
|
434
436
|
result_schema,
|
|
@@ -489,26 +491,24 @@ impl ExecutionPlan for LixStateDeleteExec {
|
|
|
489
491
|
}
|
|
490
492
|
let write_ctx = self.write_ctx.clone();
|
|
491
493
|
let table_schema = Arc::clone(&self.table_schema);
|
|
492
|
-
let
|
|
494
|
+
let branch_binding = self.branch_binding.clone();
|
|
493
495
|
let request = self.request.clone();
|
|
494
496
|
let filters = self.filters.clone();
|
|
495
497
|
let result_schema = Arc::clone(&self.result_schema);
|
|
496
498
|
let stream_schema = Arc::clone(&result_schema);
|
|
497
499
|
|
|
498
500
|
let stream = stream::once(async move {
|
|
499
|
-
let rows =
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
.scan_live_state(&request)
|
|
504
|
-
.await
|
|
505
|
-
.map_err(lix_error_to_datafusion_error)?
|
|
506
|
-
};
|
|
501
|
+
let rows = write_ctx
|
|
502
|
+
.scan_live_state(&request)
|
|
503
|
+
.await
|
|
504
|
+
.map_err(lix_error_to_datafusion_error)?;
|
|
507
505
|
let source_batch = lix_state_record_batch(Arc::clone(&table_schema), &rows)
|
|
508
506
|
.map_err(lix_error_to_datafusion_error)?;
|
|
509
507
|
let matched_batch = filter_lix_state_batch(source_batch, &filters)?;
|
|
510
|
-
let write_rows =
|
|
511
|
-
|
|
508
|
+
let write_rows = lix_state_deletable_write_rows_from_batch(
|
|
509
|
+
&matched_batch,
|
|
510
|
+
branch_binding.as_deref(),
|
|
511
|
+
)?;
|
|
512
512
|
reject_read_only_stage_rows(&write_rows, "DELETE FROM lix_state")?;
|
|
513
513
|
let count = u64::try_from(write_rows.len())
|
|
514
514
|
.map_err(|_| DataFusionError::Execution("DELETE row count overflow".to_string()))?;
|
|
@@ -539,7 +539,7 @@ impl ExecutionPlan for LixStateDeleteExec {
|
|
|
539
539
|
struct LixStateUpdateExec {
|
|
540
540
|
write_ctx: SqlWriteContext,
|
|
541
541
|
table_schema: SchemaRef,
|
|
542
|
-
|
|
542
|
+
branch_binding: Option<String>,
|
|
543
543
|
request: LiveStateScanRequest,
|
|
544
544
|
assignments: Vec<(String, Arc<dyn PhysicalExpr>)>,
|
|
545
545
|
filters: Vec<Arc<dyn PhysicalExpr>>,
|
|
@@ -557,7 +557,7 @@ impl LixStateUpdateExec {
|
|
|
557
557
|
fn new(
|
|
558
558
|
write_ctx: SqlWriteContext,
|
|
559
559
|
table_schema: SchemaRef,
|
|
560
|
-
|
|
560
|
+
branch_binding: Option<String>,
|
|
561
561
|
request: LiveStateScanRequest,
|
|
562
562
|
assignments: Vec<(String, Arc<dyn PhysicalExpr>)>,
|
|
563
563
|
filters: Vec<Arc<dyn PhysicalExpr>>,
|
|
@@ -572,7 +572,7 @@ impl LixStateUpdateExec {
|
|
|
572
572
|
Self {
|
|
573
573
|
write_ctx,
|
|
574
574
|
table_schema,
|
|
575
|
-
|
|
575
|
+
branch_binding,
|
|
576
576
|
request,
|
|
577
577
|
assignments,
|
|
578
578
|
filters,
|
|
@@ -639,7 +639,7 @@ impl ExecutionPlan for LixStateUpdateExec {
|
|
|
639
639
|
}
|
|
640
640
|
let write_ctx = self.write_ctx.clone();
|
|
641
641
|
let table_schema = Arc::clone(&self.table_schema);
|
|
642
|
-
let
|
|
642
|
+
let branch_binding = self.branch_binding.clone();
|
|
643
643
|
let request = self.request.clone();
|
|
644
644
|
let assignments = self.assignments.clone();
|
|
645
645
|
let filters = self.filters.clone();
|
|
@@ -647,21 +647,17 @@ impl ExecutionPlan for LixStateUpdateExec {
|
|
|
647
647
|
let stream_schema = Arc::clone(&result_schema);
|
|
648
648
|
|
|
649
649
|
let stream = stream::once(async move {
|
|
650
|
-
let rows =
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
.scan_live_state(&request)
|
|
655
|
-
.await
|
|
656
|
-
.map_err(lix_error_to_datafusion_error)?
|
|
657
|
-
};
|
|
650
|
+
let rows = write_ctx
|
|
651
|
+
.scan_live_state(&request)
|
|
652
|
+
.await
|
|
653
|
+
.map_err(lix_error_to_datafusion_error)?;
|
|
658
654
|
let source_batch = lix_state_record_batch(Arc::clone(&table_schema), &rows)
|
|
659
655
|
.map_err(lix_error_to_datafusion_error)?;
|
|
660
656
|
let matched_batch = filter_lix_state_batch(source_batch, &filters)?;
|
|
661
657
|
let write_rows = lix_state_update_write_rows_from_batch(
|
|
662
658
|
&matched_batch,
|
|
663
659
|
&assignments,
|
|
664
|
-
|
|
660
|
+
branch_binding.as_deref(),
|
|
665
661
|
)?;
|
|
666
662
|
reject_read_only_stage_rows(&write_rows, "UPDATE lix_state")?;
|
|
667
663
|
let count = u64::try_from(write_rows.len())
|
|
@@ -689,25 +685,6 @@ impl ExecutionPlan for LixStateUpdateExec {
|
|
|
689
685
|
}
|
|
690
686
|
}
|
|
691
687
|
|
|
692
|
-
fn validate_lix_state_update_assignments(
|
|
693
|
-
schema: &SchemaRef,
|
|
694
|
-
assignments: &[(String, Expr)],
|
|
695
|
-
) -> Result<()> {
|
|
696
|
-
for (column_name, _) in assignments {
|
|
697
|
-
schema.field_with_name(column_name).map_err(|_| {
|
|
698
|
-
DataFusionError::Plan(format!(
|
|
699
|
-
"UPDATE lix_state failed: column '{column_name}' does not exist"
|
|
700
|
-
))
|
|
701
|
-
})?;
|
|
702
|
-
if !matches!(column_name.as_str(), "snapshot_content" | "metadata") {
|
|
703
|
-
return Err(DataFusionError::Execution(format!(
|
|
704
|
-
"UPDATE lix_state cannot stage read-only column '{column_name}'"
|
|
705
|
-
)));
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
Ok(())
|
|
709
|
-
}
|
|
710
|
-
|
|
711
688
|
fn filter_lix_state_batch(
|
|
712
689
|
batch: RecordBatch,
|
|
713
690
|
filters: &[Arc<dyn PhysicalExpr>],
|
|
@@ -750,9 +727,10 @@ fn evaluate_lix_state_filters(
|
|
|
750
727
|
|
|
751
728
|
fn lix_state_stageable_write_rows_from_batch(
|
|
752
729
|
batch: &RecordBatch,
|
|
753
|
-
|
|
730
|
+
branch_binding: Option<&str>,
|
|
731
|
+
action: &str,
|
|
754
732
|
) -> Result<Vec<TransactionWriteRow>> {
|
|
755
|
-
let mut rows = lix_state_write_rows_from_batch(batch,
|
|
733
|
+
let mut rows = lix_state_write_rows_from_batch(batch, branch_binding, action)?;
|
|
756
734
|
for row in &mut rows {
|
|
757
735
|
row.created_at = None;
|
|
758
736
|
row.updated_at = None;
|
|
@@ -765,31 +743,36 @@ fn lix_state_stageable_write_rows_from_batch(
|
|
|
765
743
|
fn lix_state_update_write_rows_from_batch(
|
|
766
744
|
batch: &RecordBatch,
|
|
767
745
|
assignments: &[(String, Arc<dyn PhysicalExpr>)],
|
|
768
|
-
|
|
746
|
+
branch_binding: Option<&str>,
|
|
769
747
|
) -> Result<Vec<TransactionWriteRow>> {
|
|
770
748
|
let assignment_values = UpdateAssignmentValues::evaluate(batch, assignments)?;
|
|
771
749
|
(0..batch.num_rows())
|
|
772
750
|
.map(|row_index| {
|
|
773
751
|
let global = optional_bool_value(batch, row_index, "global")?.unwrap_or(false);
|
|
774
|
-
let
|
|
775
|
-
optional_string_value(batch, row_index, "
|
|
752
|
+
let branch_id =
|
|
753
|
+
optional_string_value(batch, row_index, "branch_id")?.unwrap_or_else(|| {
|
|
776
754
|
if global {
|
|
777
|
-
|
|
755
|
+
GLOBAL_BRANCH_ID.to_string()
|
|
778
756
|
} else {
|
|
779
|
-
|
|
757
|
+
branch_binding.unwrap_or_default().to_string()
|
|
780
758
|
}
|
|
781
759
|
});
|
|
760
|
+
if !global && branch_id.is_empty() {
|
|
761
|
+
return Err(DataFusionError::Execution(
|
|
762
|
+
"UPDATE lix_state_by_branch requires branch_id".to_string(),
|
|
763
|
+
));
|
|
764
|
+
}
|
|
782
765
|
|
|
783
766
|
Ok(TransactionWriteRow {
|
|
784
|
-
|
|
785
|
-
|
|
767
|
+
entity_pk: Some(
|
|
768
|
+
EntityPk::from_json_array_text(&required_string_value(
|
|
786
769
|
batch,
|
|
787
770
|
row_index,
|
|
788
|
-
"
|
|
771
|
+
"entity_pk",
|
|
789
772
|
)?)
|
|
790
773
|
.map_err(|error| {
|
|
791
774
|
DataFusionError::Execution(format!(
|
|
792
|
-
"lix_state UPDATE has invalid
|
|
775
|
+
"lix_state UPDATE has invalid entity_pk: {error}"
|
|
793
776
|
))
|
|
794
777
|
})?,
|
|
795
778
|
),
|
|
@@ -815,7 +798,7 @@ fn lix_state_update_write_rows_from_batch(
|
|
|
815
798
|
change_id: None,
|
|
816
799
|
commit_id: None,
|
|
817
800
|
untracked: optional_bool_value(batch, row_index, "untracked")?.unwrap_or(false),
|
|
818
|
-
|
|
801
|
+
branch_id,
|
|
819
802
|
})
|
|
820
803
|
})
|
|
821
804
|
.collect()
|
|
@@ -823,9 +806,10 @@ fn lix_state_update_write_rows_from_batch(
|
|
|
823
806
|
|
|
824
807
|
fn lix_state_deletable_write_rows_from_batch(
|
|
825
808
|
batch: &RecordBatch,
|
|
826
|
-
|
|
809
|
+
branch_binding: Option<&str>,
|
|
827
810
|
) -> Result<Vec<TransactionWriteRow>> {
|
|
828
|
-
let mut rows =
|
|
811
|
+
let mut rows =
|
|
812
|
+
lix_state_stageable_write_rows_from_batch(batch, branch_binding, "DELETE FROM lix_state")?;
|
|
829
813
|
for row in &mut rows {
|
|
830
814
|
row.snapshot = None;
|
|
831
815
|
}
|
|
@@ -861,9 +845,9 @@ fn update_optional_metadata_value(
|
|
|
861
845
|
update_optional_string_value(batch, assignment_values, row_index, column_name)?
|
|
862
846
|
.map(|value| {
|
|
863
847
|
let metadata = parse_row_metadata_value(&value, context)
|
|
864
|
-
.map_err(
|
|
848
|
+
.map_err(crate::sql2::error::lix_error_to_datafusion_error)?;
|
|
865
849
|
TransactionJson::from_value(metadata, &format!("{context} metadata"))
|
|
866
|
-
.map_err(
|
|
850
|
+
.map_err(crate::sql2::error::lix_error_to_datafusion_error)
|
|
867
851
|
})
|
|
868
852
|
.transpose()
|
|
869
853
|
}
|
|
@@ -897,30 +881,36 @@ fn dml_count_batch(schema: SchemaRef, count: u64) -> Result<RecordBatch> {
|
|
|
897
881
|
|
|
898
882
|
fn lix_state_write_rows_from_batch(
|
|
899
883
|
batch: &RecordBatch,
|
|
900
|
-
|
|
884
|
+
branch_binding: Option<&str>,
|
|
885
|
+
action: &str,
|
|
901
886
|
) -> Result<Vec<TransactionWriteRow>> {
|
|
902
887
|
(0..batch.num_rows())
|
|
903
888
|
.map(|row_index| {
|
|
904
889
|
let global = optional_bool_value(batch, row_index, "global")?.unwrap_or(false);
|
|
905
|
-
let
|
|
906
|
-
optional_string_value(batch, row_index, "
|
|
890
|
+
let branch_id =
|
|
891
|
+
optional_string_value(batch, row_index, "branch_id")?.unwrap_or_else(|| {
|
|
907
892
|
if global {
|
|
908
|
-
|
|
893
|
+
GLOBAL_BRANCH_ID.to_string()
|
|
909
894
|
} else {
|
|
910
|
-
|
|
895
|
+
branch_binding.unwrap_or_default().to_string()
|
|
911
896
|
}
|
|
912
897
|
});
|
|
898
|
+
if !global && branch_id.is_empty() {
|
|
899
|
+
return Err(DataFusionError::Execution(format!(
|
|
900
|
+
"{action} requires branch_id"
|
|
901
|
+
)));
|
|
902
|
+
}
|
|
913
903
|
|
|
914
904
|
Ok(TransactionWriteRow {
|
|
915
|
-
|
|
916
|
-
|
|
905
|
+
entity_pk: Some(
|
|
906
|
+
EntityPk::from_json_array_text(&required_string_value(
|
|
917
907
|
batch,
|
|
918
908
|
row_index,
|
|
919
|
-
"
|
|
909
|
+
"entity_pk",
|
|
920
910
|
)?)
|
|
921
911
|
.map_err(|error| {
|
|
922
912
|
DataFusionError::Execution(format!(
|
|
923
|
-
"lix_state INSERT has invalid
|
|
913
|
+
"lix_state INSERT has invalid entity_pk: {error}"
|
|
924
914
|
))
|
|
925
915
|
})?,
|
|
926
916
|
),
|
|
@@ -935,12 +925,34 @@ fn lix_state_write_rows_from_batch(
|
|
|
935
925
|
change_id: optional_string_value(batch, row_index, "change_id")?,
|
|
936
926
|
commit_id: optional_string_value(batch, row_index, "commit_id")?,
|
|
937
927
|
untracked: optional_bool_value(batch, row_index, "untracked")?.unwrap_or(false),
|
|
938
|
-
|
|
928
|
+
branch_id,
|
|
939
929
|
})
|
|
940
930
|
})
|
|
941
931
|
.collect()
|
|
942
932
|
}
|
|
943
933
|
|
|
934
|
+
fn validate_lix_state_update_assignments(
|
|
935
|
+
schema: &SchemaRef,
|
|
936
|
+
assignments: &[(String, Expr)],
|
|
937
|
+
) -> Result<()> {
|
|
938
|
+
for (column_name, _) in assignments {
|
|
939
|
+
schema.field_with_name(column_name).map_err(|_| {
|
|
940
|
+
DataFusionError::Plan(format!(
|
|
941
|
+
"UPDATE lix_state failed: column '{column_name}' does not exist"
|
|
942
|
+
))
|
|
943
|
+
})?;
|
|
944
|
+
if !matches!(
|
|
945
|
+
column_name.as_str(),
|
|
946
|
+
"snapshot_content" | "metadata" | "global" | "untracked"
|
|
947
|
+
) {
|
|
948
|
+
return Err(DataFusionError::Execution(format!(
|
|
949
|
+
"UPDATE lix_state cannot stage read-only column '{column_name}'"
|
|
950
|
+
)));
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
Ok(())
|
|
954
|
+
}
|
|
955
|
+
|
|
944
956
|
fn required_string_value(
|
|
945
957
|
batch: &RecordBatch,
|
|
946
958
|
row_index: usize,
|
|
@@ -982,9 +994,9 @@ fn optional_metadata_value(
|
|
|
982
994
|
optional_string_value(batch, row_index, column_name)?
|
|
983
995
|
.map(|value| {
|
|
984
996
|
let metadata = parse_row_metadata_value(&value, context)
|
|
985
|
-
.map_err(
|
|
997
|
+
.map_err(crate::sql2::error::lix_error_to_datafusion_error)?;
|
|
986
998
|
TransactionJson::from_value(metadata, &format!("{context} metadata"))
|
|
987
|
-
.map_err(
|
|
999
|
+
.map_err(crate::sql2::error::lix_error_to_datafusion_error)
|
|
988
1000
|
})
|
|
989
1001
|
.transpose()
|
|
990
1002
|
}
|
|
@@ -1006,7 +1018,7 @@ fn parse_snapshot_json(value: &str, column_name: &str) -> Result<TransactionJson
|
|
|
1006
1018
|
))
|
|
1007
1019
|
})?;
|
|
1008
1020
|
TransactionJson::from_value(parsed, &format!("lix_state {column_name}"))
|
|
1009
|
-
.map_err(
|
|
1021
|
+
.map_err(crate::sql2::error::lix_error_to_datafusion_error)
|
|
1010
1022
|
}
|
|
1011
1023
|
|
|
1012
1024
|
fn optional_bool_value(
|
|
@@ -1140,14 +1152,10 @@ impl ExecutionPlan for LixStateScanExec {
|
|
|
1140
1152
|
let request = self.request.clone();
|
|
1141
1153
|
let stream_schema = Arc::clone(&schema);
|
|
1142
1154
|
let stream = stream::once(async move {
|
|
1143
|
-
let rows =
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
.scan_rows(&request)
|
|
1148
|
-
.await
|
|
1149
|
-
.map_err(lix_error_to_datafusion_error)?
|
|
1150
|
-
};
|
|
1155
|
+
let rows = live_state
|
|
1156
|
+
.scan_rows(&request)
|
|
1157
|
+
.await
|
|
1158
|
+
.map_err(lix_error_to_datafusion_error)?;
|
|
1151
1159
|
let batch = lix_state_record_batch(Arc::clone(&stream_schema), &rows)
|
|
1152
1160
|
.map_err(lix_error_to_datafusion_error)?;
|
|
1153
1161
|
Ok::<_, DataFusionError>(stream::iter(vec![Ok::<RecordBatch, DataFusionError>(
|
|
@@ -1159,9 +1167,9 @@ impl ExecutionPlan for LixStateScanExec {
|
|
|
1159
1167
|
}
|
|
1160
1168
|
}
|
|
1161
1169
|
|
|
1162
|
-
fn lix_state_schema() -> SchemaRef {
|
|
1170
|
+
pub(super) fn lix_state_schema() -> SchemaRef {
|
|
1163
1171
|
Arc::new(Schema::new(vec![
|
|
1164
|
-
json_field("
|
|
1172
|
+
json_field("entity_pk", false),
|
|
1165
1173
|
Field::new("schema_key", DataType::Utf8, false),
|
|
1166
1174
|
Field::new("file_id", DataType::Utf8, true),
|
|
1167
1175
|
json_field("snapshot_content", true),
|
|
@@ -1175,9 +1183,9 @@ fn lix_state_schema() -> SchemaRef {
|
|
|
1175
1183
|
]))
|
|
1176
1184
|
}
|
|
1177
1185
|
|
|
1178
|
-
fn
|
|
1186
|
+
pub(super) fn lix_state_by_branch_schema() -> SchemaRef {
|
|
1179
1187
|
Arc::new(Schema::new(vec![
|
|
1180
|
-
json_field("
|
|
1188
|
+
json_field("entity_pk", false),
|
|
1181
1189
|
Field::new("schema_key", DataType::Utf8, false),
|
|
1182
1190
|
Field::new("file_id", DataType::Utf8, true),
|
|
1183
1191
|
json_field("snapshot_content", true),
|
|
@@ -1188,20 +1196,20 @@ fn lix_state_by_version_schema() -> SchemaRef {
|
|
|
1188
1196
|
Field::new("change_id", DataType::Utf8, true),
|
|
1189
1197
|
Field::new("commit_id", DataType::Utf8, true),
|
|
1190
1198
|
Field::new("untracked", DataType::Boolean, true),
|
|
1191
|
-
Field::new("
|
|
1199
|
+
Field::new("branch_id", DataType::Utf8, false),
|
|
1192
1200
|
]))
|
|
1193
1201
|
}
|
|
1194
1202
|
|
|
1195
1203
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
|
1196
|
-
struct
|
|
1204
|
+
struct LixStateByBranchRoute {
|
|
1197
1205
|
schema_keys: Option<BTreeSet<String>>,
|
|
1198
|
-
|
|
1199
|
-
|
|
1206
|
+
branch_ids: Option<BTreeSet<String>>,
|
|
1207
|
+
entity_pks: Option<BTreeSet<String>>,
|
|
1200
1208
|
file_id: Option<NullableKeyFilter<String>>,
|
|
1201
1209
|
contradictory: bool,
|
|
1202
1210
|
}
|
|
1203
1211
|
|
|
1204
|
-
impl
|
|
1212
|
+
impl LixStateByBranchRoute {
|
|
1205
1213
|
fn from_filters(filters: &[Expr]) -> Self {
|
|
1206
1214
|
let mut route = Self::default();
|
|
1207
1215
|
for filter in filters {
|
|
@@ -1217,16 +1225,16 @@ impl LixStateByVersionRoute {
|
|
|
1217
1225
|
&mut route.contradictory,
|
|
1218
1226
|
);
|
|
1219
1227
|
}
|
|
1220
|
-
LixStateFilterPredicate::
|
|
1228
|
+
LixStateFilterPredicate::BranchIds(values) => {
|
|
1221
1229
|
merge_string_route_slot(
|
|
1222
|
-
&mut route.
|
|
1230
|
+
&mut route.branch_ids,
|
|
1223
1231
|
values,
|
|
1224
1232
|
&mut route.contradictory,
|
|
1225
1233
|
);
|
|
1226
1234
|
}
|
|
1227
|
-
LixStateFilterPredicate::
|
|
1235
|
+
LixStateFilterPredicate::EntityPks(values) => {
|
|
1228
1236
|
merge_string_route_slot(
|
|
1229
|
-
&mut route.
|
|
1237
|
+
&mut route.entity_pks,
|
|
1230
1238
|
values,
|
|
1231
1239
|
&mut route.contradictory,
|
|
1232
1240
|
);
|
|
@@ -1248,16 +1256,16 @@ impl LixStateByVersionRoute {
|
|
|
1248
1256
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
1249
1257
|
enum LixStateFilterPredicate {
|
|
1250
1258
|
SchemaKeys(BTreeSet<String>),
|
|
1251
|
-
|
|
1252
|
-
|
|
1259
|
+
BranchIds(BTreeSet<String>),
|
|
1260
|
+
EntityPks(BTreeSet<String>),
|
|
1253
1261
|
FileId(NullableKeyFilter<String>),
|
|
1254
1262
|
}
|
|
1255
1263
|
|
|
1256
1264
|
fn lix_state_scan_request(
|
|
1257
1265
|
schema: &SchemaRef,
|
|
1258
|
-
|
|
1266
|
+
branch_binding: Option<&str>,
|
|
1259
1267
|
projection: Option<&Vec<usize>>,
|
|
1260
|
-
route: &
|
|
1268
|
+
route: &LixStateByBranchRoute,
|
|
1261
1269
|
limit: Option<usize>,
|
|
1262
1270
|
) -> LiveStateScanRequest {
|
|
1263
1271
|
let projection = LiveStateProjection {
|
|
@@ -1269,21 +1277,21 @@ fn lix_state_scan_request(
|
|
|
1269
1277
|
.as_ref()
|
|
1270
1278
|
.map(|values| values.iter().cloned().collect())
|
|
1271
1279
|
.unwrap_or_default(),
|
|
1272
|
-
|
|
1273
|
-
.
|
|
1280
|
+
entity_pks: route
|
|
1281
|
+
.entity_pks
|
|
1274
1282
|
.as_ref()
|
|
1275
1283
|
.map(|values| {
|
|
1276
1284
|
values
|
|
1277
1285
|
.iter()
|
|
1278
|
-
.filter_map(|value|
|
|
1286
|
+
.filter_map(|value| EntityPk::from_json_array_text(value).ok())
|
|
1279
1287
|
.collect()
|
|
1280
1288
|
})
|
|
1281
1289
|
.unwrap_or_default(),
|
|
1282
|
-
|
|
1290
|
+
branch_ids: branch_binding
|
|
1283
1291
|
.map(|value| vec![value.to_string()])
|
|
1284
1292
|
.or_else(|| {
|
|
1285
1293
|
route
|
|
1286
|
-
.
|
|
1294
|
+
.branch_ids
|
|
1287
1295
|
.as_ref()
|
|
1288
1296
|
.map(|values| values.iter().cloned().collect())
|
|
1289
1297
|
})
|
|
@@ -1294,10 +1302,14 @@ fn lix_state_scan_request(
|
|
|
1294
1302
|
filter.file_ids.push(file_id);
|
|
1295
1303
|
}
|
|
1296
1304
|
|
|
1305
|
+
if route.contradictory {
|
|
1306
|
+
filter.rows = LiveStateRowFilter::None;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1297
1309
|
LiveStateScanRequest {
|
|
1298
1310
|
filter,
|
|
1299
1311
|
projection,
|
|
1300
|
-
limit
|
|
1312
|
+
limit,
|
|
1301
1313
|
}
|
|
1302
1314
|
}
|
|
1303
1315
|
|
|
@@ -1396,8 +1408,8 @@ fn parse_lix_state_in_list_filter(in_list: &InList) -> Option<LixStateFilterPred
|
|
|
1396
1408
|
let values = values.into_iter().collect::<BTreeSet<_>>();
|
|
1397
1409
|
match column.name.as_str() {
|
|
1398
1410
|
"schema_key" => Some(LixStateFilterPredicate::SchemaKeys(values)),
|
|
1399
|
-
"
|
|
1400
|
-
"
|
|
1411
|
+
"branch_id" => Some(LixStateFilterPredicate::BranchIds(values)),
|
|
1412
|
+
"entity_pk" => canonical_entity_pk_values(values).map(LixStateFilterPredicate::EntityPks),
|
|
1401
1413
|
_ => None,
|
|
1402
1414
|
}
|
|
1403
1415
|
}
|
|
@@ -1424,25 +1436,25 @@ fn parse_lix_state_column_literal_filter(
|
|
|
1424
1436
|
match column.name.as_str() {
|
|
1425
1437
|
"schema_key" => string_expr_literal(literal_expr)
|
|
1426
1438
|
.map(|value| LixStateFilterPredicate::SchemaKeys(BTreeSet::from([value]))),
|
|
1427
|
-
"
|
|
1428
|
-
.map(|value| LixStateFilterPredicate::
|
|
1429
|
-
"
|
|
1430
|
-
.and_then(|value|
|
|
1431
|
-
.map(|value| LixStateFilterPredicate::
|
|
1439
|
+
"branch_id" => string_expr_literal(literal_expr)
|
|
1440
|
+
.map(|value| LixStateFilterPredicate::BranchIds(BTreeSet::from([value]))),
|
|
1441
|
+
"entity_pk" => string_expr_literal(literal_expr)
|
|
1442
|
+
.and_then(|value| canonical_entity_pk_value(&value))
|
|
1443
|
+
.map(|value| LixStateFilterPredicate::EntityPks(BTreeSet::from([value]))),
|
|
1432
1444
|
"file_id" => nullable_key_literal(literal_expr).map(LixStateFilterPredicate::FileId),
|
|
1433
1445
|
_ => None,
|
|
1434
1446
|
}
|
|
1435
1447
|
}
|
|
1436
1448
|
|
|
1437
|
-
fn
|
|
1449
|
+
fn canonical_entity_pk_values(values: BTreeSet<String>) -> Option<BTreeSet<String>> {
|
|
1438
1450
|
values
|
|
1439
1451
|
.into_iter()
|
|
1440
|
-
.map(|value|
|
|
1452
|
+
.map(|value| canonical_entity_pk_value(&value))
|
|
1441
1453
|
.collect()
|
|
1442
1454
|
}
|
|
1443
1455
|
|
|
1444
|
-
fn
|
|
1445
|
-
|
|
1456
|
+
fn canonical_entity_pk_value(value: &str) -> Option<String> {
|
|
1457
|
+
EntityPk::from_json_array_text(value)
|
|
1446
1458
|
.ok()?
|
|
1447
1459
|
.as_json_array_text()
|
|
1448
1460
|
.ok()
|
|
@@ -1490,9 +1502,9 @@ fn lix_state_record_batch(
|
|
|
1490
1502
|
.iter()
|
|
1491
1503
|
.map(|field| {
|
|
1492
1504
|
Ok(match field.name().as_str() {
|
|
1493
|
-
"
|
|
1505
|
+
"entity_pk" => Arc::new(StringArray::from(
|
|
1494
1506
|
rows.iter()
|
|
1495
|
-
.map(|row| row.
|
|
1507
|
+
.map(|row| row.entity_pk.as_json_array_text().map(Some))
|
|
1496
1508
|
.collect::<std::result::Result<Vec<_>, LixError>>()?,
|
|
1497
1509
|
)) as ArrayRef,
|
|
1498
1510
|
"schema_key" => string_array(rows.iter().map(|row| Some(row.schema_key.as_str()))),
|
|
@@ -1515,7 +1527,7 @@ fn lix_state_record_batch(
|
|
|
1515
1527
|
"untracked" => Arc::new(BooleanArray::from(
|
|
1516
1528
|
rows.iter().map(|row| row.untracked).collect::<Vec<_>>(),
|
|
1517
1529
|
)) as ArrayRef,
|
|
1518
|
-
"
|
|
1530
|
+
"branch_id" => string_array(rows.iter().map(|row| Some(row.branch_id.as_str()))),
|
|
1519
1531
|
other => {
|
|
1520
1532
|
return Err(LixError::new(
|
|
1521
1533
|
"LIX_ERROR_UNKNOWN",
|
|
@@ -1529,7 +1541,7 @@ fn lix_state_record_batch(
|
|
|
1529
1541
|
RecordBatch::try_new(schema, columns).map_err(|error| {
|
|
1530
1542
|
LixError::new(
|
|
1531
1543
|
"LIX_ERROR_UNKNOWN",
|
|
1532
|
-
format!("sql2 failed to build
|
|
1544
|
+
format!("sql2 failed to build lix_state_by_branch batch: {error}"),
|
|
1533
1545
|
)
|
|
1534
1546
|
})
|
|
1535
1547
|
}
|
|
@@ -1553,22 +1565,23 @@ fn projected_schema(schema: &SchemaRef, projection: Option<&Vec<usize>>) -> Resu
|
|
|
1553
1565
|
}
|
|
1554
1566
|
|
|
1555
1567
|
fn datafusion_error_to_lix_error(error: DataFusionError) -> LixError {
|
|
1556
|
-
|
|
1568
|
+
crate::sql2::error::datafusion_error_to_lix_error(error)
|
|
1557
1569
|
}
|
|
1558
1570
|
|
|
1559
1571
|
fn lix_error_to_datafusion_error(error: LixError) -> DataFusionError {
|
|
1560
|
-
|
|
1572
|
+
crate::sql2::error::lix_error_to_datafusion_error(error)
|
|
1561
1573
|
}
|
|
1562
1574
|
|
|
1563
1575
|
#[cfg(test)]
|
|
1564
1576
|
mod tests {
|
|
1565
1577
|
use super::{
|
|
1566
1578
|
lix_state_scan_request, lix_state_schema, lix_state_write_rows_from_batch,
|
|
1567
|
-
parse_lix_state_filter,
|
|
1568
|
-
|
|
1569
|
-
LixStateUpdateExec,
|
|
1579
|
+
parse_lix_state_filter, register_lix_state_active_write_provider,
|
|
1580
|
+
register_lix_state_by_branch_write_provider, LixStateByBranchRoute, LixStateDeleteExec,
|
|
1581
|
+
LixStateFilterPredicate, LixStateInsertSink, LixStateProvider, LixStateUpdateExec,
|
|
1570
1582
|
};
|
|
1571
1583
|
use crate::binary_cas::BlobDataReader;
|
|
1584
|
+
use crate::branch::{BranchHead, BranchRefReader};
|
|
1572
1585
|
use crate::functions::{
|
|
1573
1586
|
FunctionProvider, FunctionProviderHandle, SharedFunctionProvider, SystemFunctionProvider,
|
|
1574
1587
|
};
|
|
@@ -1578,9 +1591,8 @@ mod tests {
|
|
|
1578
1591
|
TransactionJson, TransactionWrite, TransactionWriteMode, TransactionWriteOutcome,
|
|
1579
1592
|
TransactionWriteRow,
|
|
1580
1593
|
};
|
|
1581
|
-
use crate::version::{VersionHead, VersionRefReader};
|
|
1582
1594
|
use crate::{
|
|
1583
|
-
|
|
1595
|
+
entity_pk::EntityPk,
|
|
1584
1596
|
live_state::{
|
|
1585
1597
|
LiveStateReader, LiveStateRowRequest, LiveStateScanRequest, MaterializedLiveStateRow,
|
|
1586
1598
|
},
|
|
@@ -1611,11 +1623,7 @@ mod tests {
|
|
|
1611
1623
|
use std::sync::Arc;
|
|
1612
1624
|
|
|
1613
1625
|
struct EmptyLiveStateReader;
|
|
1614
|
-
struct
|
|
1615
|
-
#[allow(dead_code)]
|
|
1616
|
-
struct RowsLiveStateReader {
|
|
1617
|
-
rows: Vec<MaterializedLiveStateRow>,
|
|
1618
|
-
}
|
|
1626
|
+
struct EmptyBranchRefReader;
|
|
1619
1627
|
struct DummyBlobReader;
|
|
1620
1628
|
|
|
1621
1629
|
#[derive(Default)]
|
|
@@ -1730,35 +1738,18 @@ mod tests {
|
|
|
1730
1738
|
}
|
|
1731
1739
|
|
|
1732
1740
|
#[async_trait]
|
|
1733
|
-
impl
|
|
1734
|
-
async fn load_head(&self,
|
|
1741
|
+
impl BranchRefReader for EmptyBranchRefReader {
|
|
1742
|
+
async fn load_head(&self, _branch_id: &str) -> Result<Option<BranchHead>, LixError> {
|
|
1735
1743
|
Ok(None)
|
|
1736
1744
|
}
|
|
1737
1745
|
|
|
1738
|
-
async fn scan_heads(&self) -> Result<Vec<
|
|
1746
|
+
async fn scan_heads(&self) -> Result<Vec<BranchHead>, LixError> {
|
|
1739
1747
|
Ok(Vec::new())
|
|
1740
1748
|
}
|
|
1741
1749
|
}
|
|
1742
1750
|
|
|
1743
|
-
fn
|
|
1744
|
-
Arc::new(
|
|
1745
|
-
}
|
|
1746
|
-
|
|
1747
|
-
#[async_trait]
|
|
1748
|
-
impl LiveStateReader for RowsLiveStateReader {
|
|
1749
|
-
async fn scan_rows(
|
|
1750
|
-
&self,
|
|
1751
|
-
_request: &LiveStateScanRequest,
|
|
1752
|
-
) -> Result<Vec<MaterializedLiveStateRow>, LixError> {
|
|
1753
|
-
Ok(self.rows.clone())
|
|
1754
|
-
}
|
|
1755
|
-
|
|
1756
|
-
async fn load_row(
|
|
1757
|
-
&self,
|
|
1758
|
-
_request: &LiveStateRowRequest,
|
|
1759
|
-
) -> Result<Option<MaterializedLiveStateRow>, LixError> {
|
|
1760
|
-
Ok(None)
|
|
1761
|
-
}
|
|
1751
|
+
fn empty_branch_ref() -> Arc<dyn BranchRefReader> {
|
|
1752
|
+
Arc::new(EmptyBranchRefReader)
|
|
1762
1753
|
}
|
|
1763
1754
|
|
|
1764
1755
|
fn test_functions() -> FunctionProviderHandle {
|
|
@@ -1782,8 +1773,8 @@ mod tests {
|
|
|
1782
1773
|
|
|
1783
1774
|
#[async_trait]
|
|
1784
1775
|
impl SqlWriteExecutionContext for DummyWriteContext {
|
|
1785
|
-
fn
|
|
1786
|
-
"
|
|
1776
|
+
fn active_branch_id(&self) -> &str {
|
|
1777
|
+
"branch-a"
|
|
1787
1778
|
}
|
|
1788
1779
|
|
|
1789
1780
|
fn functions(&self) -> FunctionProviderHandle {
|
|
@@ -1808,14 +1799,11 @@ mod tests {
|
|
|
1808
1799
|
Ok(self.rows.clone())
|
|
1809
1800
|
}
|
|
1810
1801
|
|
|
1811
|
-
async fn
|
|
1812
|
-
|
|
1813
|
-
version_id: &str,
|
|
1814
|
-
) -> Result<Option<String>, LixError> {
|
|
1815
|
-
if version_id == "ghost-version" {
|
|
1802
|
+
async fn load_branch_head(&mut self, branch_id: &str) -> Result<Option<String>, LixError> {
|
|
1803
|
+
if branch_id == "ghost-branch" {
|
|
1816
1804
|
return Ok(None);
|
|
1817
1805
|
}
|
|
1818
|
-
Ok(Some(format!("commit-{
|
|
1806
|
+
Ok(Some(format!("commit-{branch_id}")))
|
|
1819
1807
|
}
|
|
1820
1808
|
|
|
1821
1809
|
async fn stage_write(
|
|
@@ -1828,8 +1816,8 @@ mod tests {
|
|
|
1828
1816
|
|
|
1829
1817
|
#[async_trait]
|
|
1830
1818
|
impl SqlWriteExecutionContext for CapturingWriteContext {
|
|
1831
|
-
fn
|
|
1832
|
-
"
|
|
1819
|
+
fn active_branch_id(&self) -> &str {
|
|
1820
|
+
"branch-a"
|
|
1833
1821
|
}
|
|
1834
1822
|
|
|
1835
1823
|
fn functions(&self) -> FunctionProviderHandle {
|
|
@@ -1854,14 +1842,11 @@ mod tests {
|
|
|
1854
1842
|
Ok(self.rows.clone())
|
|
1855
1843
|
}
|
|
1856
1844
|
|
|
1857
|
-
async fn
|
|
1858
|
-
|
|
1859
|
-
version_id: &str,
|
|
1860
|
-
) -> Result<Option<String>, LixError> {
|
|
1861
|
-
if version_id == "ghost-version" {
|
|
1845
|
+
async fn load_branch_head(&mut self, branch_id: &str) -> Result<Option<String>, LixError> {
|
|
1846
|
+
if branch_id == "ghost-branch" {
|
|
1862
1847
|
return Ok(None);
|
|
1863
1848
|
}
|
|
1864
|
-
Ok(Some(format!("commit-{
|
|
1849
|
+
Ok(Some(format!("commit-{branch_id}")))
|
|
1865
1850
|
}
|
|
1866
1851
|
|
|
1867
1852
|
async fn stage_write(
|
|
@@ -1937,17 +1922,17 @@ mod tests {
|
|
|
1937
1922
|
.expect("valid stageable lix_state batch")
|
|
1938
1923
|
}
|
|
1939
1924
|
|
|
1940
|
-
fn live_row(
|
|
1925
|
+
fn live_row(entity_pk: &str, metadata: Option<&str>) -> MaterializedLiveStateRow {
|
|
1941
1926
|
MaterializedLiveStateRow {
|
|
1942
|
-
|
|
1927
|
+
entity_pk: EntityPk::single(entity_pk),
|
|
1943
1928
|
schema_key: "lix_key_value".to_string(),
|
|
1944
1929
|
file_id: None,
|
|
1945
1930
|
snapshot_content: Some("{\"key\":\"hello\",\"value\":\"world\"}".to_string()),
|
|
1946
1931
|
metadata: metadata.map(str::to_string),
|
|
1947
1932
|
deleted: false,
|
|
1948
|
-
|
|
1949
|
-
change_id: Some(format!("change-{
|
|
1950
|
-
commit_id: Some(format!("commit-{
|
|
1933
|
+
branch_id: "branch-a".to_string(),
|
|
1934
|
+
change_id: Some(format!("change-{entity_pk}")),
|
|
1935
|
+
commit_id: Some(format!("commit-{entity_pk}")),
|
|
1951
1936
|
global: false,
|
|
1952
1937
|
untracked: false,
|
|
1953
1938
|
created_at: "2026-04-23T00:00:00Z".to_string(),
|
|
@@ -1972,16 +1957,16 @@ mod tests {
|
|
|
1972
1957
|
}
|
|
1973
1958
|
|
|
1974
1959
|
#[test]
|
|
1975
|
-
fn
|
|
1960
|
+
fn parses_in_list_filter_for_branch_id() {
|
|
1976
1961
|
let expr = Expr::InList(InList::new(
|
|
1977
|
-
Box::new(col("
|
|
1962
|
+
Box::new(col("branch_id")),
|
|
1978
1963
|
vec![str_lit("a"), str_lit("b")],
|
|
1979
1964
|
false,
|
|
1980
1965
|
));
|
|
1981
1966
|
|
|
1982
1967
|
assert_eq!(
|
|
1983
1968
|
parse_lix_state_filter(&expr),
|
|
1984
|
-
Some(LixStateFilterPredicate::
|
|
1969
|
+
Some(LixStateFilterPredicate::BranchIds(BTreeSet::from([
|
|
1985
1970
|
"a".to_string(),
|
|
1986
1971
|
"b".to_string(),
|
|
1987
1972
|
])))
|
|
@@ -1990,15 +1975,15 @@ mod tests {
|
|
|
1990
1975
|
|
|
1991
1976
|
#[test]
|
|
1992
1977
|
fn builds_scan_request_from_route_and_projection() {
|
|
1993
|
-
let schema = super::
|
|
1994
|
-
let route =
|
|
1978
|
+
let schema = super::lix_state_by_branch_schema();
|
|
1979
|
+
let route = LixStateByBranchRoute::from_filters(&[
|
|
1995
1980
|
Expr::BinaryExpr(BinaryExpr::new(
|
|
1996
1981
|
Box::new(col("schema_key")),
|
|
1997
1982
|
Operator::Eq,
|
|
1998
1983
|
Box::new(str_lit("profile")),
|
|
1999
1984
|
)),
|
|
2000
1985
|
Expr::BinaryExpr(BinaryExpr::new(
|
|
2001
|
-
Box::new(col("
|
|
1986
|
+
Box::new(col("branch_id")),
|
|
2002
1987
|
Operator::Eq,
|
|
2003
1988
|
Box::new(str_lit("v1")),
|
|
2004
1989
|
)),
|
|
@@ -2009,14 +1994,14 @@ mod tests {
|
|
|
2009
1994
|
lix_state_scan_request(&schema, None, Some(&vec![0, 1, 11]), &route, Some(10));
|
|
2010
1995
|
|
|
2011
1996
|
assert_eq!(request.filter.schema_keys, vec!["profile".to_string()]);
|
|
2012
|
-
assert_eq!(request.filter.
|
|
1997
|
+
assert_eq!(request.filter.branch_ids, vec!["v1".to_string()]);
|
|
2013
1998
|
assert_eq!(request.filter.file_ids, vec![NullableKeyFilter::Null]);
|
|
2014
1999
|
assert_eq!(
|
|
2015
2000
|
request.projection.columns,
|
|
2016
2001
|
vec![
|
|
2017
|
-
"
|
|
2002
|
+
"entity_pk".to_string(),
|
|
2018
2003
|
"schema_key".to_string(),
|
|
2019
|
-
"
|
|
2004
|
+
"branch_id".to_string()
|
|
2020
2005
|
]
|
|
2021
2006
|
);
|
|
2022
2007
|
assert_eq!(request.limit, Some(10));
|
|
@@ -2024,37 +2009,37 @@ mod tests {
|
|
|
2024
2009
|
|
|
2025
2010
|
#[test]
|
|
2026
2011
|
fn builds_route_from_and_filter_tree() {
|
|
2027
|
-
let route =
|
|
2012
|
+
let route = LixStateByBranchRoute::from_filters(&[Expr::BinaryExpr(BinaryExpr::new(
|
|
2028
2013
|
Box::new(Expr::BinaryExpr(BinaryExpr::new(
|
|
2029
|
-
Box::new(col("
|
|
2014
|
+
Box::new(col("entity_pk")),
|
|
2030
2015
|
Operator::Eq,
|
|
2031
2016
|
Box::new(str_lit("[\"entity-a\"]")),
|
|
2032
2017
|
))),
|
|
2033
2018
|
Operator::And,
|
|
2034
2019
|
Box::new(Expr::InList(InList::new(
|
|
2035
|
-
Box::new(col("
|
|
2036
|
-
vec![str_lit("
|
|
2020
|
+
Box::new(col("branch_id")),
|
|
2021
|
+
vec![str_lit("branch-a"), str_lit("global")],
|
|
2037
2022
|
false,
|
|
2038
2023
|
))),
|
|
2039
2024
|
))]);
|
|
2040
2025
|
|
|
2041
2026
|
assert_eq!(
|
|
2042
|
-
route.
|
|
2027
|
+
route.entity_pks,
|
|
2043
2028
|
Some(BTreeSet::from(["[\"entity-a\"]".to_string()]))
|
|
2044
2029
|
);
|
|
2045
2030
|
assert_eq!(
|
|
2046
|
-
route.
|
|
2031
|
+
route.branch_ids,
|
|
2047
2032
|
Some(BTreeSet::from([
|
|
2048
2033
|
"global".to_string(),
|
|
2049
|
-
"
|
|
2034
|
+
"branch-a".to_string()
|
|
2050
2035
|
]))
|
|
2051
2036
|
);
|
|
2052
2037
|
}
|
|
2053
2038
|
|
|
2054
2039
|
#[test]
|
|
2055
2040
|
fn contradictory_filters_turn_into_zero_limit_request() {
|
|
2056
|
-
let schema = super::
|
|
2057
|
-
let route =
|
|
2041
|
+
let schema = super::lix_state_by_branch_schema();
|
|
2042
|
+
let route = LixStateByBranchRoute::from_filters(&[
|
|
2058
2043
|
Expr::BinaryExpr(BinaryExpr::new(
|
|
2059
2044
|
Box::new(col("schema_key")),
|
|
2060
2045
|
Operator::Eq,
|
|
@@ -2069,23 +2054,60 @@ mod tests {
|
|
|
2069
2054
|
|
|
2070
2055
|
let request = lix_state_scan_request(&schema, None, None, &route, None);
|
|
2071
2056
|
|
|
2072
|
-
assert_eq!(
|
|
2057
|
+
assert_eq!(
|
|
2058
|
+
request.filter.rows,
|
|
2059
|
+
crate::live_state::LiveStateRowFilter::None
|
|
2060
|
+
);
|
|
2061
|
+
assert_eq!(request.limit, None);
|
|
2073
2062
|
assert!(request.filter.schema_keys.is_empty());
|
|
2074
2063
|
}
|
|
2075
2064
|
|
|
2065
|
+
#[tokio::test]
|
|
2066
|
+
async fn active_provider_contradictory_filters_still_validate_active_head() {
|
|
2067
|
+
let provider = LixStateProvider::active_branch(
|
|
2068
|
+
"missing-branch",
|
|
2069
|
+
Arc::new(EmptyLiveStateReader),
|
|
2070
|
+
empty_branch_ref(),
|
|
2071
|
+
);
|
|
2072
|
+
let session = SessionContext::new();
|
|
2073
|
+
let filters = vec![
|
|
2074
|
+
Expr::BinaryExpr(BinaryExpr::new(
|
|
2075
|
+
Box::new(col("schema_key")),
|
|
2076
|
+
Operator::Eq,
|
|
2077
|
+
Box::new(str_lit("a")),
|
|
2078
|
+
)),
|
|
2079
|
+
Expr::BinaryExpr(BinaryExpr::new(
|
|
2080
|
+
Box::new(col("schema_key")),
|
|
2081
|
+
Operator::Eq,
|
|
2082
|
+
Box::new(str_lit("b")),
|
|
2083
|
+
)),
|
|
2084
|
+
];
|
|
2085
|
+
|
|
2086
|
+
let error = provider
|
|
2087
|
+
.scan(&session.state(), None, &filters, None)
|
|
2088
|
+
.await
|
|
2089
|
+
.expect_err("missing active branch should be checked before zero-row scan");
|
|
2090
|
+
let error = super::datafusion_error_to_lix_error(error);
|
|
2091
|
+
|
|
2092
|
+
assert_eq!(error.code, LixError::CODE_BRANCH_NOT_FOUND);
|
|
2093
|
+
assert!(error
|
|
2094
|
+
.message
|
|
2095
|
+
.contains("branch 'missing-branch' was not found"));
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2076
2098
|
#[test]
|
|
2077
|
-
fn
|
|
2099
|
+
fn active_branch_view_pins_branch_filter() {
|
|
2078
2100
|
let schema = super::lix_state_schema();
|
|
2079
|
-
let route =
|
|
2101
|
+
let route = LixStateByBranchRoute::from_filters(&[Expr::BinaryExpr(BinaryExpr::new(
|
|
2080
2102
|
Box::new(col("schema_key")),
|
|
2081
2103
|
Operator::Eq,
|
|
2082
2104
|
Box::new(str_lit("profile")),
|
|
2083
2105
|
))]);
|
|
2084
2106
|
|
|
2085
|
-
let request = lix_state_scan_request(&schema, Some("
|
|
2107
|
+
let request = lix_state_scan_request(&schema, Some("branch-a"), None, &route, None);
|
|
2086
2108
|
|
|
2087
2109
|
assert_eq!(request.filter.schema_keys, vec!["profile".to_string()]);
|
|
2088
|
-
assert_eq!(request.filter.
|
|
2110
|
+
assert_eq!(request.filter.branch_ids, vec!["branch-a".to_string()]);
|
|
2089
2111
|
}
|
|
2090
2112
|
|
|
2091
2113
|
#[tokio::test]
|
|
@@ -2094,9 +2116,12 @@ mod tests {
|
|
|
2094
2116
|
let mut write_context = DummyWriteContext::default();
|
|
2095
2117
|
let write_ctx = SqlWriteContext::new(&mut write_context);
|
|
2096
2118
|
|
|
2097
|
-
|
|
2119
|
+
register_lix_state_active_write_provider(&session, "lix_state", write_ctx.clone())
|
|
2120
|
+
.await
|
|
2121
|
+
.expect("lix_state provider should register");
|
|
2122
|
+
register_lix_state_by_branch_write_provider(&session, "lix_state_by_branch", write_ctx)
|
|
2098
2123
|
.await
|
|
2099
|
-
.expect("
|
|
2124
|
+
.expect("lix_state_by_branch provider should register");
|
|
2100
2125
|
|
|
2101
2126
|
let lix_state = session
|
|
2102
2127
|
.table_provider("lix_state")
|
|
@@ -2108,23 +2133,22 @@ mod tests {
|
|
|
2108
2133
|
.expect("lix_state should be a LixStateProvider");
|
|
2109
2134
|
assert!(lix_state.write_access.is_write());
|
|
2110
2135
|
|
|
2111
|
-
let
|
|
2112
|
-
.table_provider("
|
|
2136
|
+
let by_branch = session
|
|
2137
|
+
.table_provider("lix_state_by_branch")
|
|
2113
2138
|
.await
|
|
2114
|
-
.expect("
|
|
2115
|
-
let
|
|
2139
|
+
.expect("lix_state_by_branch provider should exist");
|
|
2140
|
+
let by_branch = by_branch
|
|
2116
2141
|
.as_any()
|
|
2117
2142
|
.downcast_ref::<LixStateProvider>()
|
|
2118
|
-
.expect("
|
|
2119
|
-
assert!(
|
|
2143
|
+
.expect("lix_state_by_branch should be a LixStateProvider");
|
|
2144
|
+
assert!(by_branch.write_access.is_write());
|
|
2120
2145
|
}
|
|
2121
2146
|
|
|
2122
2147
|
#[tokio::test]
|
|
2123
2148
|
async fn insert_into_requires_write_transaction() {
|
|
2124
2149
|
let session = SessionContext::new();
|
|
2125
2150
|
let live_state = Arc::new(EmptyLiveStateReader) as Arc<dyn LiveStateReader>;
|
|
2126
|
-
let provider =
|
|
2127
|
-
LixStateProvider::active_version("version-a", live_state, empty_version_ref());
|
|
2151
|
+
let provider = LixStateProvider::active_branch("branch-a", live_state, empty_branch_ref());
|
|
2128
2152
|
let input = Arc::new(EmptyExec::new(provider.schema())) as Arc<dyn ExecutionPlan>;
|
|
2129
2153
|
|
|
2130
2154
|
let error = provider
|
|
@@ -2142,8 +2166,7 @@ mod tests {
|
|
|
2142
2166
|
async fn update_requires_write_transaction() {
|
|
2143
2167
|
let session = SessionContext::new();
|
|
2144
2168
|
let live_state = Arc::new(EmptyLiveStateReader) as Arc<dyn LiveStateReader>;
|
|
2145
|
-
let provider =
|
|
2146
|
-
LixStateProvider::active_version("version-a", live_state, empty_version_ref());
|
|
2169
|
+
let provider = LixStateProvider::active_branch("branch-a", live_state, empty_branch_ref());
|
|
2147
2170
|
|
|
2148
2171
|
let error = provider
|
|
2149
2172
|
.update(
|
|
@@ -2164,8 +2187,7 @@ mod tests {
|
|
|
2164
2187
|
async fn delete_requires_write_transaction() {
|
|
2165
2188
|
let session = SessionContext::new();
|
|
2166
2189
|
let live_state = Arc::new(EmptyLiveStateReader) as Arc<dyn LiveStateReader>;
|
|
2167
|
-
let provider =
|
|
2168
|
-
LixStateProvider::active_version("version-a", live_state, empty_version_ref());
|
|
2190
|
+
let provider = LixStateProvider::active_branch("branch-a", live_state, empty_branch_ref());
|
|
2169
2191
|
|
|
2170
2192
|
let error = provider
|
|
2171
2193
|
.delete_from(&session.state(), vec![])
|
|
@@ -2183,7 +2205,7 @@ mod tests {
|
|
|
2183
2205
|
let session = SessionContext::new();
|
|
2184
2206
|
let mut write_context = DummyWriteContext::default();
|
|
2185
2207
|
let write_ctx = SqlWriteContext::new(&mut write_context);
|
|
2186
|
-
let provider = LixStateProvider::
|
|
2208
|
+
let provider = LixStateProvider::active_branch_with_write(write_ctx);
|
|
2187
2209
|
|
|
2188
2210
|
let plan = provider
|
|
2189
2211
|
.delete_from(&session.state(), vec![])
|
|
@@ -2198,19 +2220,19 @@ mod tests {
|
|
|
2198
2220
|
let session = SessionContext::new();
|
|
2199
2221
|
let mut write_context = DummyWriteContext::default();
|
|
2200
2222
|
let write_ctx = SqlWriteContext::new(&mut write_context);
|
|
2201
|
-
let provider = LixStateProvider::
|
|
2223
|
+
let provider = LixStateProvider::active_branch_with_write(write_ctx);
|
|
2202
2224
|
|
|
2203
2225
|
let error = provider
|
|
2204
2226
|
.update(
|
|
2205
2227
|
&session.state(),
|
|
2206
|
-
vec![("
|
|
2228
|
+
vec![("entity_pk".to_string(), str_lit("entity-2"))],
|
|
2207
2229
|
vec![],
|
|
2208
2230
|
)
|
|
2209
2231
|
.await
|
|
2210
2232
|
.expect_err("updating a read-only field should fail");
|
|
2211
2233
|
|
|
2212
2234
|
assert!(
|
|
2213
|
-
error.to_string().contains("read-only column '
|
|
2235
|
+
error.to_string().contains("read-only column 'entity_pk'"),
|
|
2214
2236
|
"unexpected error: {error}"
|
|
2215
2237
|
);
|
|
2216
2238
|
}
|
|
@@ -2220,7 +2242,7 @@ mod tests {
|
|
|
2220
2242
|
let session = SessionContext::new();
|
|
2221
2243
|
let mut write_context = DummyWriteContext::default();
|
|
2222
2244
|
let write_ctx = SqlWriteContext::new(&mut write_context);
|
|
2223
|
-
let provider = LixStateProvider::
|
|
2245
|
+
let provider = LixStateProvider::active_branch_with_write(write_ctx);
|
|
2224
2246
|
|
|
2225
2247
|
let plan = provider
|
|
2226
2248
|
.update(
|
|
@@ -2239,7 +2261,7 @@ mod tests {
|
|
|
2239
2261
|
let session = SessionContext::new();
|
|
2240
2262
|
let mut write_context = DummyWriteContext::default();
|
|
2241
2263
|
let write_ctx = SqlWriteContext::new(&mut write_context);
|
|
2242
|
-
let provider = LixStateProvider::
|
|
2264
|
+
let provider = LixStateProvider::active_branch_with_write(write_ctx);
|
|
2243
2265
|
let input = Arc::new(EmptyExec::new(provider.schema())) as Arc<dyn ExecutionPlan>;
|
|
2244
2266
|
|
|
2245
2267
|
let plan = provider
|
|
@@ -2252,13 +2274,17 @@ mod tests {
|
|
|
2252
2274
|
|
|
2253
2275
|
#[test]
|
|
2254
2276
|
fn decodes_lix_state_batch_into_write_rows() {
|
|
2255
|
-
let rows = lix_state_write_rows_from_batch(
|
|
2256
|
-
|
|
2277
|
+
let rows = lix_state_write_rows_from_batch(
|
|
2278
|
+
&one_row_lix_state_batch(false),
|
|
2279
|
+
Some("branch-a"),
|
|
2280
|
+
"INSERT into lix_state",
|
|
2281
|
+
)
|
|
2282
|
+
.expect("batch should decode");
|
|
2257
2283
|
|
|
2258
2284
|
assert_eq!(
|
|
2259
2285
|
rows,
|
|
2260
2286
|
vec![TransactionWriteRow {
|
|
2261
|
-
|
|
2287
|
+
entity_pk: Some(crate::entity_pk::EntityPk::single("entity-1")),
|
|
2262
2288
|
schema_key: "lix_key_value".to_string(),
|
|
2263
2289
|
file_id: None,
|
|
2264
2290
|
snapshot: Some(TransactionJson::from_value_for_test(
|
|
@@ -2274,17 +2300,21 @@ mod tests {
|
|
|
2274
2300
|
change_id: Some("change-a".to_string()),
|
|
2275
2301
|
commit_id: None,
|
|
2276
2302
|
untracked: false,
|
|
2277
|
-
|
|
2303
|
+
branch_id: "branch-a".to_string(),
|
|
2278
2304
|
}]
|
|
2279
2305
|
);
|
|
2280
2306
|
}
|
|
2281
2307
|
|
|
2282
2308
|
#[test]
|
|
2283
|
-
fn
|
|
2284
|
-
let rows = lix_state_write_rows_from_batch(
|
|
2285
|
-
|
|
2309
|
+
fn decodes_global_lix_state_batch_into_global_branch() {
|
|
2310
|
+
let rows = lix_state_write_rows_from_batch(
|
|
2311
|
+
&one_row_lix_state_batch(true),
|
|
2312
|
+
Some("branch-a"),
|
|
2313
|
+
"INSERT into lix_state",
|
|
2314
|
+
)
|
|
2315
|
+
.expect("batch should decode");
|
|
2286
2316
|
|
|
2287
|
-
assert_eq!(rows[0].
|
|
2317
|
+
assert_eq!(rows[0].branch_id, "global");
|
|
2288
2318
|
assert!(rows[0].global);
|
|
2289
2319
|
}
|
|
2290
2320
|
|
|
@@ -2292,7 +2322,7 @@ mod tests {
|
|
|
2292
2322
|
async fn insert_sink_stages_decoded_lix_state_rows() {
|
|
2293
2323
|
let mut write_context = CapturingWriteContext::default();
|
|
2294
2324
|
let write_ctx = SqlWriteContext::new(&mut write_context);
|
|
2295
|
-
let sink = LixStateInsertSink::new(
|
|
2325
|
+
let sink = LixStateInsertSink::new(write_ctx, Some("branch-a".to_string()));
|
|
2296
2326
|
let batch = one_row_lix_state_batch(false);
|
|
2297
2327
|
let count = sink
|
|
2298
2328
|
.write_batches(vec![batch], &Arc::new(TaskContext::default()))
|
|
@@ -2305,7 +2335,7 @@ mod tests {
|
|
|
2305
2335
|
&[TransactionWrite::Rows {
|
|
2306
2336
|
mode: TransactionWriteMode::Insert,
|
|
2307
2337
|
rows: vec![TransactionWriteRow {
|
|
2308
|
-
|
|
2338
|
+
entity_pk: Some(crate::entity_pk::EntityPk::single("entity-1")),
|
|
2309
2339
|
schema_key: "lix_key_value".to_string(),
|
|
2310
2340
|
file_id: None,
|
|
2311
2341
|
snapshot: Some(TransactionJson::from_value_for_test(
|
|
@@ -2321,7 +2351,7 @@ mod tests {
|
|
|
2321
2351
|
change_id: Some("change-a".to_string()),
|
|
2322
2352
|
commit_id: None,
|
|
2323
2353
|
untracked: false,
|
|
2324
|
-
|
|
2354
|
+
branch_id: "branch-a".to_string(),
|
|
2325
2355
|
}]
|
|
2326
2356
|
}]
|
|
2327
2357
|
);
|
|
@@ -2332,7 +2362,7 @@ mod tests {
|
|
|
2332
2362
|
let session = SessionContext::new();
|
|
2333
2363
|
let mut write_context = CapturingWriteContext::default();
|
|
2334
2364
|
let write_ctx = SqlWriteContext::new(&mut write_context);
|
|
2335
|
-
let provider = LixStateProvider::
|
|
2365
|
+
let provider = LixStateProvider::active_branch_with_write(write_ctx);
|
|
2336
2366
|
let input = Arc::new(SingleBatchExec::new(one_row_stageable_lix_state_batch()))
|
|
2337
2367
|
as Arc<dyn ExecutionPlan>;
|
|
2338
2368
|
|
|
@@ -2371,7 +2401,7 @@ mod tests {
|
|
|
2371
2401
|
writes: Vec::new(),
|
|
2372
2402
|
};
|
|
2373
2403
|
let write_ctx = SqlWriteContext::new(&mut write_context);
|
|
2374
|
-
let provider = LixStateProvider::
|
|
2404
|
+
let provider = LixStateProvider::active_branch_with_write(write_ctx);
|
|
2375
2405
|
|
|
2376
2406
|
let plan = provider
|
|
2377
2407
|
.update(
|
|
@@ -2413,7 +2443,7 @@ mod tests {
|
|
|
2413
2443
|
&[TransactionWrite::Rows {
|
|
2414
2444
|
mode: TransactionWriteMode::Replace,
|
|
2415
2445
|
rows: vec![TransactionWriteRow {
|
|
2416
|
-
|
|
2446
|
+
entity_pk: Some(crate::entity_pk::EntityPk::single("entity-1")),
|
|
2417
2447
|
schema_key: "lix_key_value".to_string(),
|
|
2418
2448
|
file_id: None,
|
|
2419
2449
|
snapshot: Some(TransactionJson::from_value_for_test(
|
|
@@ -2429,7 +2459,7 @@ mod tests {
|
|
|
2429
2459
|
change_id: None,
|
|
2430
2460
|
commit_id: None,
|
|
2431
2461
|
untracked: false,
|
|
2432
|
-
|
|
2462
|
+
branch_id: "branch-a".to_string(),
|
|
2433
2463
|
}]
|
|
2434
2464
|
}]
|
|
2435
2465
|
);
|
|
@@ -2446,7 +2476,7 @@ mod tests {
|
|
|
2446
2476
|
writes: Vec::new(),
|
|
2447
2477
|
};
|
|
2448
2478
|
let write_ctx = SqlWriteContext::new(&mut write_context);
|
|
2449
|
-
let provider = LixStateProvider::
|
|
2479
|
+
let provider = LixStateProvider::active_branch_with_write(write_ctx);
|
|
2450
2480
|
|
|
2451
2481
|
let plan = provider
|
|
2452
2482
|
.delete_from(&session.state(), vec![])
|
|
@@ -2472,7 +2502,7 @@ mod tests {
|
|
|
2472
2502
|
mode: TransactionWriteMode::Replace,
|
|
2473
2503
|
rows: vec![
|
|
2474
2504
|
TransactionWriteRow {
|
|
2475
|
-
|
|
2505
|
+
entity_pk: Some(crate::entity_pk::EntityPk::single("entity-1")),
|
|
2476
2506
|
schema_key: "lix_key_value".to_string(),
|
|
2477
2507
|
file_id: None,
|
|
2478
2508
|
snapshot: None,
|
|
@@ -2486,10 +2516,10 @@ mod tests {
|
|
|
2486
2516
|
change_id: None,
|
|
2487
2517
|
commit_id: None,
|
|
2488
2518
|
untracked: false,
|
|
2489
|
-
|
|
2519
|
+
branch_id: "branch-a".to_string(),
|
|
2490
2520
|
},
|
|
2491
2521
|
TransactionWriteRow {
|
|
2492
|
-
|
|
2522
|
+
entity_pk: Some(crate::entity_pk::EntityPk::single("entity-2")),
|
|
2493
2523
|
schema_key: "lix_key_value".to_string(),
|
|
2494
2524
|
file_id: None,
|
|
2495
2525
|
snapshot: None,
|
|
@@ -2503,7 +2533,7 @@ mod tests {
|
|
|
2503
2533
|
change_id: None,
|
|
2504
2534
|
commit_id: None,
|
|
2505
2535
|
untracked: false,
|
|
2506
|
-
|
|
2536
|
+
branch_id: "branch-a".to_string(),
|
|
2507
2537
|
},
|
|
2508
2538
|
]
|
|
2509
2539
|
}]
|