@lix-js/sdk 0.6.0-preview.4 → 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 +65 -64
- package/dist/engine-wasm/index.js +4 -4
- package/dist/engine-wasm/wasm/lix_engine.d.ts +5 -5
- package/dist/engine-wasm/wasm/lix_engine.js +130 -118
- package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
- package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +9 -8
- package/dist/generated/builtin-schemas.d.ts +69 -69
- package/dist/generated/builtin-schemas.js +94 -94
- package/dist/open-lix.d.ts +33 -26
- package/dist/open-lix.js +10 -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 +803 -148
- package/dist-engine-src/src/session/create_branch.rs +94 -0
- package/dist-engine-src/src/session/execute.rs +223 -83
- 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 +15 -12
- package/dist-engine-src/src/session/switch_branch.rs +113 -0
- package/dist-engine-src/src/session/transaction.rs +495 -14
- package/dist-engine-src/src/sql2/{classify.rs → bind/classify.rs} +3 -75
- 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} +71 -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 +1 -1
- 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 +28 -23
- 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 -110
- package/dist-engine-src/src/sql2/entity_provider.rs +0 -3211
- package/dist-engine-src/src/sql2/execute.rs +0 -3533
- 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 -172
- package/dist-engine-src/src/sql2/public_bind/mod.rs +0 -26
- 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
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
#[cfg(feature = "storage-benches")]
|
|
2
|
+
mod bench_support;
|
|
1
3
|
mod commit;
|
|
2
4
|
mod context;
|
|
3
|
-
mod live_state_overlay;
|
|
4
5
|
mod normalization;
|
|
5
6
|
mod prep;
|
|
6
7
|
mod schema_resolver;
|
|
@@ -8,6 +9,16 @@ mod staging;
|
|
|
8
9
|
pub(crate) mod types;
|
|
9
10
|
mod validation;
|
|
10
11
|
|
|
12
|
+
#[cfg(feature = "storage-benches")]
|
|
13
|
+
pub mod bench {
|
|
14
|
+
pub use super::bench_support::*;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
pub(crate) use context::begin_commit_boundary;
|
|
18
|
+
pub(crate) use context::commit_at_boundary;
|
|
11
19
|
pub(crate) use context::open_transaction;
|
|
20
|
+
pub(crate) use context::CommitBoundaryGuard;
|
|
21
|
+
pub(crate) use context::CommitBoundaryState;
|
|
12
22
|
pub(crate) use context::Transaction;
|
|
13
|
-
pub(crate) use
|
|
23
|
+
pub(crate) use context::TransactionCommitBoundary;
|
|
24
|
+
pub(crate) use prep::prepare_branch_ref_row;
|
|
@@ -6,7 +6,7 @@ use crate::catalog::{CatalogSnapshot, SchemaPlan, SchemaPlanId};
|
|
|
6
6
|
use crate::common::format_json_pointer;
|
|
7
7
|
use crate::common::normalize_path_segment;
|
|
8
8
|
use crate::domain::Domain;
|
|
9
|
-
use crate::
|
|
9
|
+
use crate::entity_pk::{EntityPk, EntityPkError};
|
|
10
10
|
use crate::functions::FunctionProviderHandle;
|
|
11
11
|
use crate::schema::{
|
|
12
12
|
is_seed_schema_key, schema_from_registered_snapshot, validate_lix_schema,
|
|
@@ -27,7 +27,7 @@ pub(crate) struct NormalizedTransactionWriteRow {
|
|
|
27
27
|
pub(crate) facts: PreparedRowFacts,
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
/// Normalizes one incoming row into a row with final snapshot/entity
|
|
30
|
+
/// Normalizes one incoming row into a row with final snapshot/entity primary key.
|
|
31
31
|
///
|
|
32
32
|
/// This is the canonical schema-semantics boundary for transaction writes. It owns
|
|
33
33
|
/// schema default application, primary-key identity derivation, and explicit
|
|
@@ -60,7 +60,7 @@ pub(crate) fn normalize_transaction_write_row(
|
|
|
60
60
|
let defaults_changed = apply_defaults(&mut snapshot, schema_plan, &row, functions)?;
|
|
61
61
|
let descriptor_changed = normalize_filesystem_descriptor_snapshot(&row, &mut snapshot)?;
|
|
62
62
|
let snapshot = JsonValue::Object(snapshot);
|
|
63
|
-
row.
|
|
63
|
+
row.entity_pk = Some(resolve_entity_pk(&row, schema_plan, &snapshot)?);
|
|
64
64
|
if defaults_changed || descriptor_changed {
|
|
65
65
|
Some(TransactionJson::from_value(
|
|
66
66
|
snapshot,
|
|
@@ -69,11 +69,11 @@ pub(crate) fn normalize_transaction_write_row(
|
|
|
69
69
|
} else {
|
|
70
70
|
Some(TransactionJson::from_parts(Arc::new(snapshot), normalized))
|
|
71
71
|
}
|
|
72
|
-
} else if row.
|
|
72
|
+
} else if row.entity_pk.is_none() {
|
|
73
73
|
return Err(LixError::new(
|
|
74
74
|
LixError::CODE_SCHEMA_VALIDATION,
|
|
75
75
|
format!(
|
|
76
|
-
"tombstone for schema '{}' requires
|
|
76
|
+
"tombstone for schema '{}' requires entity_pk",
|
|
77
77
|
row.schema_key
|
|
78
78
|
),
|
|
79
79
|
));
|
|
@@ -87,10 +87,10 @@ pub(crate) fn normalize_transaction_write_row(
|
|
|
87
87
|
LixError::CODE_SCHEMA_DEFINITION,
|
|
88
88
|
"lix_registered_schema rows must not be scoped to a file",
|
|
89
89
|
)
|
|
90
|
-
.with_hint("Schema definitions are scoped by
|
|
90
|
+
.with_hint("Schema definitions are scoped by branch and durability only; write them with null file_id."));
|
|
91
91
|
}
|
|
92
92
|
let schema_domain =
|
|
93
|
-
Domain::schema_catalog(row.
|
|
93
|
+
Domain::schema_catalog(row.schema_scope_branch_id().to_string(), row.untracked);
|
|
94
94
|
remember_pending_registered_schema(
|
|
95
95
|
normalized_snapshot.as_ref().map(TransactionJson::value),
|
|
96
96
|
schema_domain,
|
|
@@ -210,31 +210,31 @@ fn optional_string_field<'a>(
|
|
|
210
210
|
})
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
fn
|
|
213
|
+
fn resolve_entity_pk(
|
|
214
214
|
row: &TransactionWriteRow,
|
|
215
215
|
schema_plan: &SchemaPlan,
|
|
216
216
|
snapshot: &JsonValue,
|
|
217
|
-
) -> Result<
|
|
217
|
+
) -> Result<EntityPk, LixError> {
|
|
218
218
|
let Some(primary_key_paths) = schema_plan.primary_key.as_ref() else {
|
|
219
|
-
return row.
|
|
219
|
+
return row.entity_pk.clone().ok_or_else(|| {
|
|
220
220
|
LixError::new(
|
|
221
221
|
LixError::CODE_SCHEMA_VALIDATION,
|
|
222
222
|
format!(
|
|
223
|
-
"write for schema '{}' requires
|
|
223
|
+
"write for schema '{}' requires entity_pk because the schema has no x-lix-primary-key",
|
|
224
224
|
row.schema_key
|
|
225
225
|
),
|
|
226
226
|
)
|
|
227
227
|
});
|
|
228
228
|
};
|
|
229
|
-
let derived =
|
|
230
|
-
.map_err(|error|
|
|
231
|
-
if let Some(
|
|
232
|
-
if
|
|
229
|
+
let derived = EntityPk::from_primary_key_paths(snapshot, primary_key_paths)
|
|
230
|
+
.map_err(|error| entity_pk_derivation_error(row, primary_key_paths, error))?;
|
|
231
|
+
if let Some(entity_pk) = row.entity_pk.as_ref() {
|
|
232
|
+
if entity_pk != &derived {
|
|
233
233
|
return Err(LixError::new(
|
|
234
234
|
LixError::CODE_SCHEMA_VALIDATION,
|
|
235
235
|
format!(
|
|
236
|
-
"
|
|
237
|
-
|
|
236
|
+
"entity_pk '{}' does not match x-lix-primary-key derived entity_pk '{}' for schema '{}'",
|
|
237
|
+
entity_pk.as_json_array_text()?, derived.as_json_array_text()?, row.schema_key
|
|
238
238
|
),
|
|
239
239
|
));
|
|
240
240
|
}
|
|
@@ -242,39 +242,30 @@ fn resolve_entity_id(
|
|
|
242
242
|
Ok(derived)
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
fn
|
|
245
|
+
fn entity_pk_derivation_error(
|
|
246
246
|
row: &TransactionWriteRow,
|
|
247
247
|
primary_key_paths: &[Vec<String>],
|
|
248
|
-
error:
|
|
248
|
+
error: EntityPkError,
|
|
249
249
|
) -> LixError {
|
|
250
250
|
let detail = match error {
|
|
251
|
-
|
|
252
|
-
|
|
251
|
+
EntityPkError::EmptyPrimaryKey => "empty x-lix-primary-key".to_string(),
|
|
252
|
+
EntityPkError::EmptyPrimaryKeyPath { index } => {
|
|
253
253
|
format!("empty x-lix-primary-key pointer at index {index}")
|
|
254
254
|
}
|
|
255
|
-
|
|
256
|
-
let pointer = primary_key_paths
|
|
257
|
-
.get(index)
|
|
258
|
-
.map(|path| format_json_pointer(path))
|
|
259
|
-
.unwrap_or_else(|| format!("index {index}"));
|
|
260
|
-
format!("empty value at primary-key pointer '{pointer}'")
|
|
261
|
-
}
|
|
262
|
-
EntityIdentityError::MissingPrimaryKeyValue { index } => {
|
|
255
|
+
EntityPkError::MissingPrimaryKeyValue { index } => {
|
|
263
256
|
let pointer = format_json_pointer(&primary_key_paths[index]);
|
|
264
257
|
format!("missing value at primary-key pointer '{pointer}'")
|
|
265
258
|
}
|
|
266
|
-
|
|
259
|
+
EntityPkError::UnsupportedPrimaryKeyValue { index } => {
|
|
267
260
|
let pointer = format_json_pointer(&primary_key_paths[index]);
|
|
268
261
|
format!("non-string value at primary-key pointer '{pointer}'")
|
|
269
262
|
}
|
|
270
|
-
|
|
271
|
-
"invalid encoded entity identity".to_string()
|
|
272
|
-
}
|
|
263
|
+
EntityPkError::InvalidEncodedEntityPk => "invalid encoded entity primary key".to_string(),
|
|
273
264
|
};
|
|
274
265
|
LixError::new(
|
|
275
266
|
LixError::CODE_SCHEMA_VALIDATION,
|
|
276
267
|
format!(
|
|
277
|
-
"failed to derive
|
|
268
|
+
"failed to derive entity_pk for schema '{}': {detail}",
|
|
278
269
|
row.schema_key
|
|
279
270
|
),
|
|
280
271
|
)
|
|
@@ -329,10 +320,10 @@ mod tests {
|
|
|
329
320
|
use crate::schema::seed_schema_definition;
|
|
330
321
|
|
|
331
322
|
#[test]
|
|
332
|
-
fn
|
|
323
|
+
fn normalization_derives_entity_pk_from_primary_key() {
|
|
333
324
|
let mut catalog = catalog_with(vec![schema_with_default_id()]);
|
|
334
325
|
let row = TransactionWriteRow {
|
|
335
|
-
|
|
326
|
+
entity_pk: None,
|
|
336
327
|
schema_key: "normalization_schema".to_string(),
|
|
337
328
|
snapshot: Some(snapshot_json(
|
|
338
329
|
r#"{"id":"entity-from-snapshot","value":"hello"}"#,
|
|
@@ -344,10 +335,8 @@ mod tests {
|
|
|
344
335
|
normalize_transaction_write_row(row, &mut catalog, functions()).expect("normalize row");
|
|
345
336
|
|
|
346
337
|
assert_eq!(
|
|
347
|
-
row.row.
|
|
348
|
-
Some(&crate::
|
|
349
|
-
"entity-from-snapshot"
|
|
350
|
-
))
|
|
338
|
+
row.row.entity_pk.as_ref(),
|
|
339
|
+
Some(&crate::entity_pk::EntityPk::single("entity-from-snapshot"))
|
|
351
340
|
);
|
|
352
341
|
}
|
|
353
342
|
|
|
@@ -355,7 +344,7 @@ mod tests {
|
|
|
355
344
|
fn normalization_applies_json_and_cel_defaults_before_identity_derivation() {
|
|
356
345
|
let mut catalog = catalog_with(vec![schema_with_default_id()]);
|
|
357
346
|
let row = TransactionWriteRow {
|
|
358
|
-
|
|
347
|
+
entity_pk: None,
|
|
359
348
|
schema_key: "normalization_schema".to_string(),
|
|
360
349
|
snapshot: Some(snapshot_json(r#"{}"#)),
|
|
361
350
|
..base_stage_row()
|
|
@@ -366,10 +355,8 @@ mod tests {
|
|
|
366
355
|
let snapshot = normalized_snapshot(&row);
|
|
367
356
|
|
|
368
357
|
assert_eq!(
|
|
369
|
-
row.row.
|
|
370
|
-
Some(&crate::
|
|
371
|
-
"uuid-default"
|
|
372
|
-
))
|
|
358
|
+
row.row.entity_pk.as_ref(),
|
|
359
|
+
Some(&crate::entity_pk::EntityPk::single("uuid-default"))
|
|
373
360
|
);
|
|
374
361
|
assert_eq!(snapshot["id"], "uuid-default");
|
|
375
362
|
assert_eq!(snapshot["value"], "literal-default");
|
|
@@ -379,7 +366,7 @@ mod tests {
|
|
|
379
366
|
fn normalization_applies_cel_defaults_from_snapshot_context() {
|
|
380
367
|
let mut catalog = catalog_with(vec![schema_with_cel_field_default()]);
|
|
381
368
|
let row = TransactionWriteRow {
|
|
382
|
-
|
|
369
|
+
entity_pk: None,
|
|
383
370
|
schema_key: "cel_field_default_schema".to_string(),
|
|
384
371
|
snapshot: Some(snapshot_json(r#"{"id":"entity-1","name":"Sample"}"#)),
|
|
385
372
|
..base_stage_row()
|
|
@@ -396,7 +383,7 @@ mod tests {
|
|
|
396
383
|
fn normalization_x_lix_default_overrides_json_default() {
|
|
397
384
|
let mut catalog = catalog_with(vec![schema_with_overridden_default()]);
|
|
398
385
|
let row = TransactionWriteRow {
|
|
399
|
-
|
|
386
|
+
entity_pk: None,
|
|
400
387
|
schema_key: "overridden_default_schema".to_string(),
|
|
401
388
|
snapshot: Some(snapshot_json(r#"{"id":"entity-1"}"#)),
|
|
402
389
|
..base_stage_row()
|
|
@@ -413,7 +400,7 @@ mod tests {
|
|
|
413
400
|
fn normalization_does_not_overwrite_explicit_null_with_default() {
|
|
414
401
|
let mut catalog = catalog_with(vec![schema_with_nullable_default()]);
|
|
415
402
|
let row = TransactionWriteRow {
|
|
416
|
-
|
|
403
|
+
entity_pk: None,
|
|
417
404
|
schema_key: "nullable_default_schema".to_string(),
|
|
418
405
|
snapshot: Some(snapshot_json(r#"{"id":"entity-1","status":null}"#)),
|
|
419
406
|
..base_stage_row()
|
|
@@ -430,7 +417,7 @@ mod tests {
|
|
|
430
417
|
fn normalization_applies_timestamp_function_default() {
|
|
431
418
|
let mut catalog = catalog_with(vec![schema_with_timestamp_default()]);
|
|
432
419
|
let row = TransactionWriteRow {
|
|
433
|
-
|
|
420
|
+
entity_pk: None,
|
|
434
421
|
schema_key: "timestamp_default_schema".to_string(),
|
|
435
422
|
snapshot: Some(snapshot_json(r#"{"id":"entity-1"}"#)),
|
|
436
423
|
..base_stage_row()
|
|
@@ -447,7 +434,7 @@ mod tests {
|
|
|
447
434
|
fn normalization_surfaces_cel_default_errors() {
|
|
448
435
|
let mut catalog = catalog_with(vec![schema_with_unknown_cel_default()]);
|
|
449
436
|
let row = TransactionWriteRow {
|
|
450
|
-
|
|
437
|
+
entity_pk: None,
|
|
451
438
|
schema_key: "unknown_cel_default_schema".to_string(),
|
|
452
439
|
snapshot: Some(snapshot_json(r#"{"id":"entity-1"}"#)),
|
|
453
440
|
..base_stage_row()
|
|
@@ -461,10 +448,10 @@ mod tests {
|
|
|
461
448
|
}
|
|
462
449
|
|
|
463
450
|
#[test]
|
|
464
|
-
fn
|
|
451
|
+
fn normalization_rejects_entity_pk_that_disagrees_with_primary_key() {
|
|
465
452
|
let mut catalog = catalog_with(vec![schema_with_default_id()]);
|
|
466
453
|
let row = TransactionWriteRow {
|
|
467
|
-
|
|
454
|
+
entity_pk: Some(crate::entity_pk::EntityPk::single("wrong-id")),
|
|
468
455
|
schema_key: "normalization_schema".to_string(),
|
|
469
456
|
snapshot: Some(snapshot_json(r#"{"id":"right-id","value":"hello"}"#)),
|
|
470
457
|
..base_stage_row()
|
|
@@ -475,14 +462,14 @@ mod tests {
|
|
|
475
462
|
|
|
476
463
|
assert!(error
|
|
477
464
|
.message
|
|
478
|
-
.contains("does not match x-lix-primary-key derived
|
|
465
|
+
.contains("does not match x-lix-primary-key derived entity_pk"));
|
|
479
466
|
}
|
|
480
467
|
|
|
481
468
|
#[test]
|
|
482
|
-
fn
|
|
469
|
+
fn normalization_derives_json_array_entity_pk_for_composite_primary_key() {
|
|
483
470
|
let mut catalog = catalog_with(vec![composite_key_schema()]);
|
|
484
471
|
let row = TransactionWriteRow {
|
|
485
|
-
|
|
472
|
+
entity_pk: None,
|
|
486
473
|
schema_key: "composite_key_schema".to_string(),
|
|
487
474
|
snapshot: Some(snapshot_json(r#"{"namespace":"a~b","key":"1"}"#)),
|
|
488
475
|
..base_stage_row()
|
|
@@ -490,19 +477,19 @@ mod tests {
|
|
|
490
477
|
|
|
491
478
|
let row =
|
|
492
479
|
normalize_transaction_write_row(row, &mut catalog, functions()).expect("normalize row");
|
|
493
|
-
let
|
|
494
|
-
let
|
|
480
|
+
let entity_pk = row.row.entity_pk.expect("composite entity pk");
|
|
481
|
+
let projected_entity_pk = entity_pk
|
|
495
482
|
.as_json_array_text()
|
|
496
|
-
.expect("entity
|
|
483
|
+
.expect("entity pk should project");
|
|
497
484
|
|
|
498
|
-
assert_eq!(
|
|
485
|
+
assert_eq!(projected_entity_pk, "[\"a~b\",\"1\"]");
|
|
499
486
|
}
|
|
500
487
|
|
|
501
488
|
#[test]
|
|
502
489
|
fn normalization_rejects_non_string_primary_key_values() {
|
|
503
490
|
let mut catalog = catalog_with(vec![composite_key_schema()]);
|
|
504
491
|
let row = TransactionWriteRow {
|
|
505
|
-
|
|
492
|
+
entity_pk: None,
|
|
506
493
|
schema_key: "composite_key_schema".to_string(),
|
|
507
494
|
snapshot: Some(snapshot_json(r#"{"namespace":"a~b","key":1}"#)),
|
|
508
495
|
..base_stage_row()
|
|
@@ -518,19 +505,19 @@ mod tests {
|
|
|
518
505
|
}
|
|
519
506
|
|
|
520
507
|
#[test]
|
|
521
|
-
fn
|
|
508
|
+
fn normalization_validates_explicit_composite_entity_pk_against_projection() {
|
|
522
509
|
let mut catalog = catalog_with(vec![composite_key_schema()]);
|
|
523
510
|
let snapshot = json!({
|
|
524
511
|
"namespace": "a~b",
|
|
525
512
|
"key": "1",
|
|
526
513
|
});
|
|
527
|
-
let derived =
|
|
514
|
+
let derived = EntityPk::from_primary_key_paths(
|
|
528
515
|
&snapshot,
|
|
529
516
|
&[vec!["namespace".to_string()], vec!["key".to_string()]],
|
|
530
517
|
)
|
|
531
518
|
.expect("identity should derive");
|
|
532
519
|
let row = TransactionWriteRow {
|
|
533
|
-
|
|
520
|
+
entity_pk: Some(derived.clone()),
|
|
534
521
|
schema_key: "composite_key_schema".to_string(),
|
|
535
522
|
snapshot: Some(transaction_json(snapshot.clone())),
|
|
536
523
|
..base_stage_row()
|
|
@@ -539,7 +526,7 @@ mod tests {
|
|
|
539
526
|
let row =
|
|
540
527
|
normalize_transaction_write_row(row, &mut catalog, functions()).expect("normalize row");
|
|
541
528
|
|
|
542
|
-
assert_eq!(row.row.
|
|
529
|
+
assert_eq!(row.row.entity_pk.as_ref(), Some(&derived));
|
|
543
530
|
}
|
|
544
531
|
|
|
545
532
|
#[test]
|
|
@@ -548,7 +535,7 @@ mod tests {
|
|
|
548
535
|
.expect("registered schema builtin")
|
|
549
536
|
.clone()]);
|
|
550
537
|
let registered = TransactionWriteRow {
|
|
551
|
-
|
|
538
|
+
entity_pk: None,
|
|
552
539
|
schema_key: REGISTERED_SCHEMA_KEY.to_string(),
|
|
553
540
|
snapshot: Some(transaction_json(json!({
|
|
554
541
|
"value": dynamic_schema_definition(),
|
|
@@ -560,7 +547,7 @@ mod tests {
|
|
|
560
547
|
.expect("register schema");
|
|
561
548
|
|
|
562
549
|
let dynamic = TransactionWriteRow {
|
|
563
|
-
|
|
550
|
+
entity_pk: None,
|
|
564
551
|
schema_key: "dynamic_schema".to_string(),
|
|
565
552
|
snapshot: Some(snapshot_json(r#"{"id":"dynamic-1"}"#)),
|
|
566
553
|
..base_stage_row()
|
|
@@ -569,8 +556,8 @@ mod tests {
|
|
|
569
556
|
.expect("dynamic row");
|
|
570
557
|
|
|
571
558
|
assert_eq!(
|
|
572
|
-
dynamic.row.
|
|
573
|
-
Some(&crate::
|
|
559
|
+
dynamic.row.entity_pk.as_ref(),
|
|
560
|
+
Some(&crate::entity_pk::EntityPk::single("dynamic-1"))
|
|
574
561
|
);
|
|
575
562
|
}
|
|
576
563
|
|
|
@@ -582,7 +569,7 @@ mod tests {
|
|
|
582
569
|
]);
|
|
583
570
|
|
|
584
571
|
let file = TransactionWriteRow {
|
|
585
|
-
|
|
572
|
+
entity_pk: None,
|
|
586
573
|
schema_key: FILE_DESCRIPTOR_SCHEMA_KEY.to_string(),
|
|
587
574
|
snapshot: Some(transaction_json(json!({
|
|
588
575
|
"id": "file-cafe",
|
|
@@ -598,7 +585,7 @@ mod tests {
|
|
|
598
585
|
assert_eq!(file_snapshot["name"], "Café.txt");
|
|
599
586
|
|
|
600
587
|
let directory = TransactionWriteRow {
|
|
601
|
-
|
|
588
|
+
entity_pk: None,
|
|
602
589
|
schema_key: DIRECTORY_DESCRIPTOR_SCHEMA_KEY.to_string(),
|
|
603
590
|
snapshot: Some(transaction_json(json!({
|
|
604
591
|
"id": "dir-cafe",
|
|
@@ -623,7 +610,7 @@ mod tests {
|
|
|
623
610
|
|
|
624
611
|
let dot_segment = normalize_transaction_write_row(
|
|
625
612
|
TransactionWriteRow {
|
|
626
|
-
|
|
613
|
+
entity_pk: None,
|
|
627
614
|
schema_key: FILE_DESCRIPTOR_SCHEMA_KEY.to_string(),
|
|
628
615
|
snapshot: Some(transaction_json(json!({
|
|
629
616
|
"id": "file-dotdot",
|
|
@@ -641,7 +628,7 @@ mod tests {
|
|
|
641
628
|
|
|
642
629
|
let bidi = normalize_transaction_write_row(
|
|
643
630
|
TransactionWriteRow {
|
|
644
|
-
|
|
631
|
+
entity_pk: None,
|
|
645
632
|
schema_key: FILE_DESCRIPTOR_SCHEMA_KEY.to_string(),
|
|
646
633
|
snapshot: Some(transaction_json(json!({
|
|
647
634
|
"id": "file-bidi",
|
|
@@ -659,7 +646,7 @@ mod tests {
|
|
|
659
646
|
|
|
660
647
|
let zero_width = normalize_transaction_write_row(
|
|
661
648
|
TransactionWriteRow {
|
|
662
|
-
|
|
649
|
+
entity_pk: None,
|
|
663
650
|
schema_key: DIRECTORY_DESCRIPTOR_SCHEMA_KEY.to_string(),
|
|
664
651
|
snapshot: Some(transaction_json(json!({
|
|
665
652
|
"id": "dir-zero-width",
|
|
@@ -682,7 +669,7 @@ mod tests {
|
|
|
682
669
|
|
|
683
670
|
let row = normalize_transaction_write_row(
|
|
684
671
|
TransactionWriteRow {
|
|
685
|
-
|
|
672
|
+
entity_pk: None,
|
|
686
673
|
schema_key: FILE_DESCRIPTOR_SCHEMA_KEY.to_string(),
|
|
687
674
|
snapshot: Some(transaction_json(json!({
|
|
688
675
|
"id": "file-opaque-name",
|
|
@@ -737,7 +724,7 @@ mod tests {
|
|
|
737
724
|
|
|
738
725
|
fn base_stage_row() -> TransactionWriteRow {
|
|
739
726
|
TransactionWriteRow {
|
|
740
|
-
|
|
727
|
+
entity_pk: Some(crate::entity_pk::EntityPk::single("entity-1")),
|
|
741
728
|
schema_key: "normalization_schema".to_string(),
|
|
742
729
|
file_id: None,
|
|
743
730
|
snapshot: Some(snapshot_json(r#"{"id":"entity-1","value":"hello"}"#)),
|
|
@@ -749,7 +736,7 @@ mod tests {
|
|
|
749
736
|
change_id: None,
|
|
750
737
|
commit_id: None,
|
|
751
738
|
untracked: false,
|
|
752
|
-
|
|
739
|
+
branch_id: crate::GLOBAL_BRANCH_ID.to_string(),
|
|
753
740
|
}
|
|
754
741
|
}
|
|
755
742
|
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
use crate::
|
|
1
|
+
use crate::branch::BRANCH_REF_SCHEMA_KEY;
|
|
2
|
+
use crate::entity_pk::EntityPk;
|
|
2
3
|
use crate::untracked_state::UntrackedStateRow;
|
|
3
|
-
use crate::
|
|
4
|
-
use crate::{LixError, GLOBAL_VERSION_ID};
|
|
4
|
+
use crate::{LixError, GLOBAL_BRANCH_ID};
|
|
5
5
|
|
|
6
|
-
pub(crate) struct
|
|
6
|
+
pub(crate) struct PreparedBranchRefRow {
|
|
7
7
|
pub(crate) row: UntrackedStateRow,
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
pub(crate) fn
|
|
11
|
-
|
|
10
|
+
pub(crate) fn prepare_branch_ref_row(
|
|
11
|
+
branch_id: &str,
|
|
12
12
|
commit_id: &str,
|
|
13
13
|
timestamp: &str,
|
|
14
|
-
) -> Result<
|
|
14
|
+
) -> Result<PreparedBranchRefRow, LixError> {
|
|
15
15
|
let snapshot = serde_json::json!({
|
|
16
|
-
"id":
|
|
16
|
+
"id": branch_id,
|
|
17
17
|
"commit_id": commit_id,
|
|
18
18
|
});
|
|
19
19
|
let snapshot = crate::json_store::NormalizedJson::from_value(
|
|
20
20
|
&snapshot,
|
|
21
|
-
"engine
|
|
21
|
+
"engine branch-ref snapshot_content",
|
|
22
22
|
)?;
|
|
23
23
|
|
|
24
|
-
Ok(
|
|
24
|
+
Ok(PreparedBranchRefRow {
|
|
25
25
|
row: UntrackedStateRow {
|
|
26
|
-
|
|
27
|
-
schema_key:
|
|
26
|
+
entity_pk: EntityPk::single(branch_id),
|
|
27
|
+
schema_key: BRANCH_REF_SCHEMA_KEY.to_string(),
|
|
28
28
|
file_id: None,
|
|
29
29
|
snapshot_content: Some(snapshot.as_str().to_string()),
|
|
30
30
|
metadata: None,
|
|
31
31
|
created_at: timestamp.to_string(),
|
|
32
32
|
updated_at: timestamp.to_string(),
|
|
33
33
|
global: true,
|
|
34
|
-
|
|
34
|
+
branch_id: GLOBAL_BRANCH_ID.to_string(),
|
|
35
35
|
},
|
|
36
36
|
})
|
|
37
37
|
}
|
|
@@ -6,9 +6,9 @@ use async_trait::async_trait;
|
|
|
6
6
|
use crate::catalog::{CatalogContext, CatalogSnapshot, SchemaCatalogFact};
|
|
7
7
|
use crate::domain::Domain;
|
|
8
8
|
use crate::live_state::{
|
|
9
|
-
LiveStateReader, LiveStateRowRequest, LiveStateScanRequest,
|
|
9
|
+
overlay_scan_rows, LiveStateReader, LiveStateRowRequest, LiveStateScanRequest,
|
|
10
|
+
MaterializedLiveStateRow,
|
|
10
11
|
};
|
|
11
|
-
use crate::transaction::live_state_overlay::overlay_scan_rows;
|
|
12
12
|
use crate::transaction::staging::PreparedStateRowOverlay;
|
|
13
13
|
use crate::LixError;
|
|
14
14
|
|
|
@@ -89,7 +89,7 @@ impl TransactionSchemaResolver {
|
|
|
89
89
|
match self
|
|
90
90
|
.catalogs_by_domain
|
|
91
91
|
.get_mut(&domain)
|
|
92
|
-
.expect("catalog cache should contain requested
|
|
92
|
+
.expect("catalog cache should contain requested branch")
|
|
93
93
|
{
|
|
94
94
|
CatalogEntry::Catalog(catalog) => Ok(catalog),
|
|
95
95
|
CatalogEntry::SchemaFacts(_) => {
|
|
@@ -109,7 +109,7 @@ impl TransactionSchemaResolver {
|
|
|
109
109
|
match self
|
|
110
110
|
.catalogs_by_domain
|
|
111
111
|
.get(&domain)
|
|
112
|
-
.expect("catalog cache should contain requested
|
|
112
|
+
.expect("catalog cache should contain requested branch")
|
|
113
113
|
{
|
|
114
114
|
CatalogEntry::Catalog(catalog) => Ok(catalog),
|
|
115
115
|
CatalogEntry::SchemaFacts(_) => {
|
|
@@ -144,6 +144,20 @@ impl LiveStateReader for TransactionSchemaLiveStateReader<'_> {
|
|
|
144
144
|
&self,
|
|
145
145
|
request: &LiveStateRowRequest,
|
|
146
146
|
) -> Result<Option<MaterializedLiveStateRow>, LixError> {
|
|
147
|
-
self
|
|
147
|
+
Ok(self
|
|
148
|
+
.scan_rows(&LiveStateScanRequest {
|
|
149
|
+
filter: crate::live_state::LiveStateFilter {
|
|
150
|
+
schema_keys: vec![request.schema_key.clone()],
|
|
151
|
+
entity_pks: vec![request.entity_pk.clone()],
|
|
152
|
+
branch_ids: vec![request.branch_id.clone()],
|
|
153
|
+
file_ids: vec![request.file_id.clone()],
|
|
154
|
+
..Default::default()
|
|
155
|
+
},
|
|
156
|
+
limit: Some(1),
|
|
157
|
+
..Default::default()
|
|
158
|
+
})
|
|
159
|
+
.await?
|
|
160
|
+
.into_iter()
|
|
161
|
+
.next())
|
|
148
162
|
}
|
|
149
163
|
}
|