@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
|
@@ -3,28 +3,27 @@ use serde_json::Value as JsonValue;
|
|
|
3
3
|
use crate::common::json_pointer_get;
|
|
4
4
|
use crate::LixError;
|
|
5
5
|
|
|
6
|
-
/// Logical entity
|
|
6
|
+
/// Logical entity primary key derived from a schema primary key.
|
|
7
7
|
///
|
|
8
|
-
/// Keep this as typed tuple data inside engine. SQL `
|
|
8
|
+
/// Keep this as typed tuple data inside engine. SQL `entity_pk` surfaces
|
|
9
9
|
/// should use the JSON-array projection.
|
|
10
10
|
#[derive(
|
|
11
11
|
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
|
|
12
12
|
)]
|
|
13
|
-
pub(crate) struct
|
|
13
|
+
pub(crate) struct EntityPk {
|
|
14
14
|
pub(crate) parts: Vec<String>,
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
18
|
-
pub(crate) enum
|
|
18
|
+
pub(crate) enum EntityPkError {
|
|
19
19
|
EmptyPrimaryKey,
|
|
20
20
|
EmptyPrimaryKeyPath { index: usize },
|
|
21
|
-
EmptyPrimaryKeyValue { index: usize },
|
|
22
21
|
MissingPrimaryKeyValue { index: usize },
|
|
23
22
|
UnsupportedPrimaryKeyValue { index: usize },
|
|
24
|
-
|
|
23
|
+
InvalidEncodedEntityPk,
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
impl std::fmt::Display for
|
|
26
|
+
impl std::fmt::Display for EntityPkError {
|
|
28
27
|
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
29
28
|
match self {
|
|
30
29
|
Self::EmptyPrimaryKey => {
|
|
@@ -36,12 +35,6 @@ impl std::fmt::Display for EntityIdentityError {
|
|
|
36
35
|
"primary-key path at index {index} must not be empty"
|
|
37
36
|
)
|
|
38
37
|
}
|
|
39
|
-
Self::EmptyPrimaryKeyValue { index } => {
|
|
40
|
-
write!(
|
|
41
|
-
formatter,
|
|
42
|
-
"primary-key value at index {index} must not be empty"
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
38
|
Self::MissingPrimaryKeyValue { index } => {
|
|
46
39
|
write!(formatter, "primary-key value at index {index} is missing")
|
|
47
40
|
}
|
|
@@ -49,49 +42,48 @@ impl std::fmt::Display for EntityIdentityError {
|
|
|
49
42
|
formatter,
|
|
50
43
|
"primary-key value at index {index} must be a JSON string"
|
|
51
44
|
),
|
|
52
|
-
Self::
|
|
45
|
+
Self::InvalidEncodedEntityPk => {
|
|
53
46
|
write!(
|
|
54
47
|
formatter,
|
|
55
|
-
"encoded entity
|
|
48
|
+
"encoded entity primary key must be a non-empty JSON array of strings"
|
|
56
49
|
)
|
|
57
50
|
}
|
|
58
51
|
}
|
|
59
52
|
}
|
|
60
53
|
}
|
|
61
54
|
|
|
62
|
-
impl
|
|
55
|
+
impl EntityPk {
|
|
63
56
|
pub(crate) fn single(value: impl Into<String>) -> Self {
|
|
64
57
|
Self {
|
|
65
58
|
parts: vec![value.into()],
|
|
66
59
|
}
|
|
67
60
|
}
|
|
68
61
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if parts.is_empty() {
|
|
72
|
-
return Err(EntityIdentityError::EmptyPrimaryKey);
|
|
73
|
-
}
|
|
74
|
-
if let Some((index, _)) = parts.iter().enumerate().find(|(_, part)| part.is_empty()) {
|
|
75
|
-
return Err(EntityIdentityError::EmptyPrimaryKeyValue { index });
|
|
76
|
-
}
|
|
62
|
+
pub(crate) fn from_parts(parts: Vec<String>) -> Result<Self, EntityPkError> {
|
|
63
|
+
validate_parts(&parts)?;
|
|
77
64
|
Ok(Self { parts })
|
|
78
65
|
}
|
|
79
66
|
|
|
67
|
+
#[cfg(test)]
|
|
68
|
+
pub(crate) fn tuple(parts: Vec<String>) -> Result<Self, EntityPkError> {
|
|
69
|
+
Self::from_parts(parts)
|
|
70
|
+
}
|
|
71
|
+
|
|
80
72
|
pub(crate) fn from_primary_key_paths(
|
|
81
73
|
snapshot: &JsonValue,
|
|
82
74
|
primary_key_paths: &[Vec<String>],
|
|
83
|
-
) -> Result<Self,
|
|
75
|
+
) -> Result<Self, EntityPkError> {
|
|
84
76
|
if primary_key_paths.is_empty() {
|
|
85
|
-
return Err(
|
|
77
|
+
return Err(EntityPkError::EmptyPrimaryKey);
|
|
86
78
|
}
|
|
87
79
|
|
|
88
80
|
let mut parts = Vec::with_capacity(primary_key_paths.len());
|
|
89
81
|
for (index, path) in primary_key_paths.iter().enumerate() {
|
|
90
82
|
if path.is_empty() {
|
|
91
|
-
return Err(
|
|
83
|
+
return Err(EntityPkError::EmptyPrimaryKeyPath { index });
|
|
92
84
|
}
|
|
93
85
|
let Some(value) = json_pointer_get(snapshot, path) else {
|
|
94
|
-
return Err(
|
|
86
|
+
return Err(EntityPkError::MissingPrimaryKeyValue { index });
|
|
95
87
|
};
|
|
96
88
|
parts.push(string_part_from_json_value(value, index)?);
|
|
97
89
|
}
|
|
@@ -102,7 +94,7 @@ impl EntityIdentity {
|
|
|
102
94
|
pub(crate) fn as_json_array_value(&self) -> Result<JsonValue, LixError> {
|
|
103
95
|
if self.parts.is_empty() {
|
|
104
96
|
return Err(LixError::unknown(
|
|
105
|
-
"entity
|
|
97
|
+
"entity primary key must contain at least one primary-key part",
|
|
106
98
|
));
|
|
107
99
|
}
|
|
108
100
|
|
|
@@ -116,14 +108,14 @@ impl EntityIdentity {
|
|
|
116
108
|
|
|
117
109
|
pub(crate) fn as_json_array_text(&self) -> Result<String, LixError> {
|
|
118
110
|
serde_json::to_string(&self.as_json_array_value()?).map_err(|error| {
|
|
119
|
-
LixError::unknown(format!("failed to encode entity
|
|
111
|
+
LixError::unknown(format!("failed to encode entity pk as JSON: {error}"))
|
|
120
112
|
})
|
|
121
113
|
}
|
|
122
114
|
|
|
123
115
|
pub(crate) fn as_single_string(&self) -> Result<&str, LixError> {
|
|
124
116
|
if self.parts.is_empty() {
|
|
125
117
|
return Err(LixError::unknown(
|
|
126
|
-
"entity
|
|
118
|
+
"entity primary key must contain at least one primary-key part",
|
|
127
119
|
));
|
|
128
120
|
}
|
|
129
121
|
|
|
@@ -132,7 +124,7 @@ impl EntityIdentity {
|
|
|
132
124
|
}
|
|
133
125
|
|
|
134
126
|
Err(LixError::unknown(
|
|
135
|
-
"entity
|
|
127
|
+
"entity primary key is not a single string primary-key tuple",
|
|
136
128
|
))
|
|
137
129
|
}
|
|
138
130
|
|
|
@@ -140,20 +132,18 @@ impl EntityIdentity {
|
|
|
140
132
|
Ok(self.as_single_string()?.to_owned())
|
|
141
133
|
}
|
|
142
134
|
|
|
143
|
-
pub(crate) fn from_json_array_text(
|
|
144
|
-
let value = serde_json::from_str::<JsonValue>(
|
|
145
|
-
.map_err(|_|
|
|
135
|
+
pub(crate) fn from_json_array_text(entity_pk: &str) -> Result<Self, EntityPkError> {
|
|
136
|
+
let value = serde_json::from_str::<JsonValue>(entity_pk)
|
|
137
|
+
.map_err(|_| EntityPkError::InvalidEncodedEntityPk)?;
|
|
146
138
|
Self::from_json_array_value(&value)
|
|
147
139
|
}
|
|
148
140
|
|
|
149
|
-
pub(crate) fn from_json_array_value(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
let JsonValue::Array(values) = entity_id else {
|
|
153
|
-
return Err(EntityIdentityError::InvalidEncodedEntityIdentity);
|
|
141
|
+
pub(crate) fn from_json_array_value(entity_pk: &JsonValue) -> Result<Self, EntityPkError> {
|
|
142
|
+
let JsonValue::Array(values) = entity_pk else {
|
|
143
|
+
return Err(EntityPkError::InvalidEncodedEntityPk);
|
|
154
144
|
};
|
|
155
145
|
if values.is_empty() {
|
|
156
|
-
return Err(
|
|
146
|
+
return Err(EntityPkError::EmptyPrimaryKey);
|
|
157
147
|
}
|
|
158
148
|
|
|
159
149
|
let mut parts = Vec::with_capacity(values.len());
|
|
@@ -164,16 +154,17 @@ impl EntityIdentity {
|
|
|
164
154
|
}
|
|
165
155
|
}
|
|
166
156
|
|
|
167
|
-
fn
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
157
|
+
fn validate_parts(parts: &[String]) -> Result<(), EntityPkError> {
|
|
158
|
+
if parts.is_empty() {
|
|
159
|
+
return Err(EntityPkError::EmptyPrimaryKey);
|
|
160
|
+
}
|
|
161
|
+
Ok(())
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
fn string_part_from_json_value(value: &JsonValue, index: usize) -> Result<String, EntityPkError> {
|
|
171
165
|
match value {
|
|
172
|
-
JsonValue::String(value) if value.is_empty() => {
|
|
173
|
-
Err(EntityIdentityError::EmptyPrimaryKeyValue { index })
|
|
174
|
-
}
|
|
175
166
|
JsonValue::String(value) => Ok(value.clone()),
|
|
176
|
-
_ => Err(
|
|
167
|
+
_ => Err(EntityPkError::UnsupportedPrimaryKeyValue { index }),
|
|
177
168
|
}
|
|
178
169
|
}
|
|
179
170
|
|
|
@@ -208,7 +199,7 @@ mod tests {
|
|
|
208
199
|
|
|
209
200
|
#[test]
|
|
210
201
|
fn single_string_identity_projects_to_single_string() {
|
|
211
|
-
let identity =
|
|
202
|
+
let identity = EntityPk::single("plain-id");
|
|
212
203
|
|
|
213
204
|
assert_eq!(
|
|
214
205
|
identity.as_single_string().expect("projection should work"),
|
|
@@ -217,8 +208,8 @@ mod tests {
|
|
|
217
208
|
}
|
|
218
209
|
|
|
219
210
|
#[test]
|
|
220
|
-
fn
|
|
221
|
-
let identity =
|
|
211
|
+
fn single_identity_projects_to_json_array_entity_pk() {
|
|
212
|
+
let identity = EntityPk::single("plain-id");
|
|
222
213
|
|
|
223
214
|
assert_eq!(
|
|
224
215
|
identity
|
|
@@ -229,8 +220,8 @@ mod tests {
|
|
|
229
220
|
}
|
|
230
221
|
|
|
231
222
|
#[test]
|
|
232
|
-
fn
|
|
233
|
-
let identity =
|
|
223
|
+
fn composite_identity_projects_to_json_array_entity_pk() {
|
|
224
|
+
let identity = EntityPk::tuple(vec!["namespace".to_string(), "42".to_string()])
|
|
234
225
|
.expect("tuple identity");
|
|
235
226
|
|
|
236
227
|
assert_eq!(
|
|
@@ -242,40 +233,43 @@ mod tests {
|
|
|
242
233
|
}
|
|
243
234
|
|
|
244
235
|
#[test]
|
|
245
|
-
fn
|
|
246
|
-
let identity =
|
|
236
|
+
fn entity_pk_json_array_roundtrips() {
|
|
237
|
+
let identity = EntityPk::tuple(vec!["namespace".to_string(), "42".to_string()])
|
|
247
238
|
.expect("tuple identity");
|
|
248
239
|
let encoded = identity
|
|
249
240
|
.as_json_array_text()
|
|
250
241
|
.expect("projection should work");
|
|
251
242
|
|
|
252
243
|
assert_eq!(
|
|
253
|
-
|
|
244
|
+
EntityPk::from_json_array_text(&encoded).expect("decode should work"),
|
|
254
245
|
identity
|
|
255
246
|
);
|
|
256
247
|
}
|
|
257
248
|
|
|
258
249
|
#[test]
|
|
259
|
-
fn
|
|
250
|
+
fn entity_pk_json_array_allows_empty_string_part() {
|
|
260
251
|
assert_eq!(
|
|
261
|
-
|
|
262
|
-
|
|
252
|
+
EntityPk::from_json_array_text("[\"\"]").expect("empty string is a valid part"),
|
|
253
|
+
EntityPk::single("")
|
|
263
254
|
);
|
|
264
255
|
}
|
|
265
256
|
|
|
266
257
|
#[test]
|
|
267
|
-
fn
|
|
258
|
+
fn tuple_allows_empty_string_part() {
|
|
268
259
|
assert_eq!(
|
|
269
|
-
|
|
270
|
-
|
|
260
|
+
EntityPk::tuple(vec!["namespace".to_string(), "".to_string()])
|
|
261
|
+
.expect("empty string is a valid part"),
|
|
262
|
+
EntityPk {
|
|
263
|
+
parts: vec!["namespace".to_string(), "".to_string()],
|
|
264
|
+
}
|
|
271
265
|
);
|
|
272
266
|
}
|
|
273
267
|
|
|
274
268
|
#[test]
|
|
275
|
-
fn
|
|
276
|
-
let left =
|
|
277
|
-
.expect("left tuple identity");
|
|
278
|
-
let right =
|
|
269
|
+
fn entity_pk_json_array_does_not_collide_on_delimiter_like_values() {
|
|
270
|
+
let left =
|
|
271
|
+
EntityPk::tuple(vec!["a~b".to_string(), "c".to_string()]).expect("left tuple identity");
|
|
272
|
+
let right = EntityPk::tuple(vec!["a".to_string(), "b~c".to_string()])
|
|
279
273
|
.expect("right tuple identity");
|
|
280
274
|
|
|
281
275
|
assert_ne!(
|
|
@@ -286,7 +280,7 @@ mod tests {
|
|
|
286
280
|
|
|
287
281
|
#[test]
|
|
288
282
|
fn composite_identity_rejects_single_string_projection() {
|
|
289
|
-
let identity =
|
|
283
|
+
let identity = EntityPk::tuple(vec!["namespace".to_string(), "42".to_string()])
|
|
290
284
|
.expect("tuple identity");
|
|
291
285
|
|
|
292
286
|
assert!(identity.as_single_string().is_err());
|
|
@@ -294,9 +288,9 @@ mod tests {
|
|
|
294
288
|
|
|
295
289
|
#[test]
|
|
296
290
|
fn composite_identity_does_not_collide_on_delimiter_like_values() {
|
|
297
|
-
let left =
|
|
298
|
-
.expect("left tuple identity");
|
|
299
|
-
let right =
|
|
291
|
+
let left =
|
|
292
|
+
EntityPk::tuple(vec!["a~b".to_string(), "1".to_string()]).expect("left tuple identity");
|
|
293
|
+
let right = EntityPk::tuple(vec!["a".to_string(), "b~1".to_string()])
|
|
300
294
|
.expect("right tuple identity");
|
|
301
295
|
|
|
302
296
|
assert_ne!(
|
|
@@ -312,7 +306,7 @@ mod tests {
|
|
|
312
306
|
"locale": "en"
|
|
313
307
|
});
|
|
314
308
|
|
|
315
|
-
let identity =
|
|
309
|
+
let identity = EntityPk::from_primary_key_paths(
|
|
316
310
|
&snapshot,
|
|
317
311
|
&[vec!["namespace".to_string()], vec!["locale".to_string()]],
|
|
318
312
|
)
|
|
@@ -320,25 +314,25 @@ mod tests {
|
|
|
320
314
|
|
|
321
315
|
assert_eq!(
|
|
322
316
|
identity,
|
|
323
|
-
|
|
317
|
+
EntityPk {
|
|
324
318
|
parts: vec!["messages".to_string(), "en".to_string()],
|
|
325
319
|
}
|
|
326
320
|
);
|
|
327
321
|
}
|
|
328
322
|
|
|
329
323
|
#[test]
|
|
330
|
-
fn
|
|
324
|
+
fn entity_pk_json_array_rejects_non_string_parts() {
|
|
331
325
|
assert_eq!(
|
|
332
|
-
|
|
333
|
-
Err(
|
|
326
|
+
EntityPk::from_json_array_text("[\"namespace\",42]"),
|
|
327
|
+
Err(EntityPkError::UnsupportedPrimaryKeyValue { index: 1 })
|
|
334
328
|
);
|
|
335
329
|
assert_eq!(
|
|
336
|
-
|
|
337
|
-
Err(
|
|
330
|
+
EntityPk::from_json_array_text("[\"namespace\",null]"),
|
|
331
|
+
Err(EntityPkError::UnsupportedPrimaryKeyValue { index: 1 })
|
|
338
332
|
);
|
|
339
333
|
assert_eq!(
|
|
340
|
-
|
|
341
|
-
Err(
|
|
334
|
+
EntityPk::from_json_array_text("[[\"nested\"]]"),
|
|
335
|
+
Err(EntityPkError::UnsupportedPrimaryKeyValue { index: 0 })
|
|
342
336
|
);
|
|
343
337
|
}
|
|
344
338
|
|
|
@@ -350,46 +344,49 @@ mod tests {
|
|
|
350
344
|
});
|
|
351
345
|
|
|
352
346
|
assert_eq!(
|
|
353
|
-
|
|
347
|
+
EntityPk::from_primary_key_paths(
|
|
354
348
|
&snapshot,
|
|
355
349
|
&[vec!["namespace".to_string()], vec!["index".to_string()],],
|
|
356
350
|
),
|
|
357
|
-
Err(
|
|
351
|
+
Err(EntityPkError::UnsupportedPrimaryKeyValue { index: 1 })
|
|
358
352
|
);
|
|
359
353
|
}
|
|
360
354
|
|
|
361
355
|
#[test]
|
|
362
|
-
fn
|
|
356
|
+
fn from_primary_key_paths_allows_empty_string_parts() {
|
|
363
357
|
let snapshot = json!({
|
|
364
358
|
"namespace": "messages",
|
|
365
359
|
"id": ""
|
|
366
360
|
});
|
|
367
361
|
|
|
368
362
|
assert_eq!(
|
|
369
|
-
|
|
363
|
+
EntityPk::from_primary_key_paths(
|
|
370
364
|
&snapshot,
|
|
371
365
|
&[vec!["namespace".to_string()], vec!["id".to_string()],],
|
|
372
|
-
)
|
|
373
|
-
|
|
366
|
+
)
|
|
367
|
+
.expect("empty string is a valid primary-key value"),
|
|
368
|
+
EntityPk {
|
|
369
|
+
parts: vec!["messages".to_string(), "".to_string()],
|
|
370
|
+
}
|
|
374
371
|
);
|
|
375
372
|
}
|
|
376
373
|
|
|
377
374
|
#[test]
|
|
378
375
|
fn from_primary_key_paths_rejects_nested_json_parts() {
|
|
379
376
|
let snapshot = json!({
|
|
380
|
-
"
|
|
377
|
+
"entity_pk": ["welcome.title", "en"],
|
|
381
378
|
"schema_key": "message"
|
|
382
379
|
});
|
|
383
380
|
|
|
384
381
|
assert_eq!(
|
|
385
|
-
|
|
382
|
+
EntityPk::from_primary_key_paths(
|
|
386
383
|
&snapshot,
|
|
387
384
|
&[
|
|
388
|
-
vec!["
|
|
385
|
+
vec!["entity_pk".to_string()],
|
|
389
386
|
vec!["schema_key".to_string()],
|
|
390
387
|
],
|
|
391
388
|
),
|
|
392
|
-
Err(
|
|
389
|
+
Err(EntityPkError::UnsupportedPrimaryKeyValue { index: 0 })
|
|
393
390
|
);
|
|
394
391
|
}
|
|
395
392
|
|
|
@@ -398,8 +395,8 @@ mod tests {
|
|
|
398
395
|
let snapshot = json!({ "id": "a" });
|
|
399
396
|
|
|
400
397
|
assert_eq!(
|
|
401
|
-
|
|
402
|
-
Err(
|
|
398
|
+
EntityPk::from_primary_key_paths(&snapshot, &[vec!["missing".to_string()]]),
|
|
399
|
+
Err(EntityPkError::MissingPrimaryKeyValue { index: 0 })
|
|
403
400
|
);
|
|
404
401
|
}
|
|
405
402
|
}
|
|
@@ -74,14 +74,12 @@ impl FunctionContext {
|
|
|
74
74
|
|
|
75
75
|
#[cfg(test)]
|
|
76
76
|
mod tests {
|
|
77
|
-
use std::sync::Arc;
|
|
78
|
-
|
|
79
|
-
use crate::backend::testing::UnitTestBackend;
|
|
80
77
|
use crate::functions::state::{DETERMINISTIC_MODE_KEY, DETERMINISTIC_SEQUENCE_KEY};
|
|
81
78
|
use crate::functions::{state::load_sequence, DeterministicSequence};
|
|
82
79
|
use crate::live_state::LiveStateContext;
|
|
83
80
|
use crate::storage::StorageContext;
|
|
84
|
-
use crate::
|
|
81
|
+
use crate::storage::{InMemoryStorageBackend, StorageReadOptions, StorageWriteOptions};
|
|
82
|
+
use crate::GLOBAL_BRANCH_ID;
|
|
85
83
|
|
|
86
84
|
use super::*;
|
|
87
85
|
|
|
@@ -95,10 +93,13 @@ mod tests {
|
|
|
95
93
|
|
|
96
94
|
#[tokio::test]
|
|
97
95
|
async fn prepare_uses_system_functions_when_mode_missing() {
|
|
98
|
-
let
|
|
99
|
-
let storage = StorageContext::new(backend.clone());
|
|
96
|
+
let storage = StorageContext::new(InMemoryStorageBackend::new());
|
|
100
97
|
let live_state = live_state_context();
|
|
101
|
-
let reader = live_state.reader(
|
|
98
|
+
let reader = live_state.reader(
|
|
99
|
+
storage
|
|
100
|
+
.begin_read(StorageReadOptions::default())
|
|
101
|
+
.expect("read should open"),
|
|
102
|
+
);
|
|
102
103
|
|
|
103
104
|
let context = FunctionContext::prepare(&reader)
|
|
104
105
|
.await
|
|
@@ -114,10 +115,9 @@ mod tests {
|
|
|
114
115
|
|
|
115
116
|
#[tokio::test]
|
|
116
117
|
async fn prepare_starts_deterministic_functions_at_sequence_zero() {
|
|
117
|
-
let
|
|
118
|
-
let storage = StorageContext::new(backend.clone());
|
|
118
|
+
let storage = StorageContext::new(InMemoryStorageBackend::new());
|
|
119
119
|
let live_state = live_state_context();
|
|
120
|
-
crate::test_support::
|
|
120
|
+
crate::test_support::seed_global_branch_head(storage.clone()).await;
|
|
121
121
|
write_key_value(
|
|
122
122
|
storage.clone(),
|
|
123
123
|
DETERMINISTIC_MODE_KEY,
|
|
@@ -127,7 +127,11 @@ mod tests {
|
|
|
127
127
|
)
|
|
128
128
|
.await;
|
|
129
129
|
|
|
130
|
-
let reader = live_state.reader(
|
|
130
|
+
let reader = live_state.reader(
|
|
131
|
+
storage
|
|
132
|
+
.begin_read(StorageReadOptions::default())
|
|
133
|
+
.expect("read should open"),
|
|
134
|
+
);
|
|
131
135
|
let context = FunctionContext::prepare(&reader)
|
|
132
136
|
.await
|
|
133
137
|
.expect("runtime context should prepare");
|
|
@@ -148,10 +152,9 @@ mod tests {
|
|
|
148
152
|
|
|
149
153
|
#[tokio::test]
|
|
150
154
|
async fn prepare_continues_from_persisted_sequence() {
|
|
151
|
-
let
|
|
152
|
-
let storage = StorageContext::new(backend.clone());
|
|
155
|
+
let storage = StorageContext::new(InMemoryStorageBackend::new());
|
|
153
156
|
let live_state = live_state_context();
|
|
154
|
-
crate::test_support::
|
|
157
|
+
crate::test_support::seed_global_branch_head(storage.clone()).await;
|
|
155
158
|
write_key_value(
|
|
156
159
|
storage.clone(),
|
|
157
160
|
DETERMINISTIC_MODE_KEY,
|
|
@@ -167,7 +170,11 @@ mod tests {
|
|
|
167
170
|
)
|
|
168
171
|
.await;
|
|
169
172
|
|
|
170
|
-
let reader = live_state.reader(
|
|
173
|
+
let reader = live_state.reader(
|
|
174
|
+
storage
|
|
175
|
+
.begin_read(StorageReadOptions::default())
|
|
176
|
+
.expect("read should open"),
|
|
177
|
+
);
|
|
171
178
|
let context = FunctionContext::prepare(&reader)
|
|
172
179
|
.await
|
|
173
180
|
.expect("runtime context should prepare");
|
|
@@ -187,10 +194,9 @@ mod tests {
|
|
|
187
194
|
|
|
188
195
|
#[tokio::test]
|
|
189
196
|
async fn persist_if_needed_writes_sequence_when_deterministic_functions_advanced() {
|
|
190
|
-
let
|
|
191
|
-
let storage = StorageContext::new(backend.clone());
|
|
197
|
+
let storage = StorageContext::new(InMemoryStorageBackend::new());
|
|
192
198
|
let live_state = live_state_context();
|
|
193
|
-
crate::test_support::
|
|
199
|
+
crate::test_support::seed_global_branch_head(storage.clone()).await;
|
|
194
200
|
write_key_value(
|
|
195
201
|
storage.clone(),
|
|
196
202
|
DETERMINISTIC_MODE_KEY,
|
|
@@ -201,56 +207,60 @@ mod tests {
|
|
|
201
207
|
.await;
|
|
202
208
|
|
|
203
209
|
let context = {
|
|
204
|
-
let reader = live_state.reader(
|
|
210
|
+
let reader = live_state.reader(
|
|
211
|
+
storage
|
|
212
|
+
.begin_read(StorageReadOptions::default())
|
|
213
|
+
.expect("read should open"),
|
|
214
|
+
);
|
|
205
215
|
FunctionContext::prepare(&reader)
|
|
206
216
|
.await
|
|
207
217
|
.expect("runtime context should prepare")
|
|
208
218
|
};
|
|
209
219
|
context.provider().call_uuid_v7();
|
|
210
220
|
|
|
211
|
-
let mut
|
|
212
|
-
.begin_write_transaction()
|
|
213
|
-
.await
|
|
214
|
-
.expect("transaction should open");
|
|
215
|
-
let mut writes = StorageWriteSet::new();
|
|
221
|
+
let mut writes = storage.new_write_set();
|
|
216
222
|
context
|
|
217
223
|
.stage_persist_if_needed(&mut writes)
|
|
218
224
|
.await
|
|
219
225
|
.expect("sequence should stage");
|
|
220
|
-
|
|
221
|
-
.
|
|
222
|
-
.
|
|
223
|
-
.expect("sequence should apply");
|
|
224
|
-
tx.commit().await.expect("transaction should commit");
|
|
226
|
+
storage
|
|
227
|
+
.commit_write_set(writes, StorageWriteOptions::default())
|
|
228
|
+
.expect("sequence should commit");
|
|
225
229
|
|
|
226
|
-
let reader = live_state.reader(
|
|
230
|
+
let reader = live_state.reader(
|
|
231
|
+
storage
|
|
232
|
+
.begin_read(StorageReadOptions::default())
|
|
233
|
+
.expect("read should open"),
|
|
234
|
+
);
|
|
227
235
|
let sequence = load_sequence(&reader).await.expect("sequence should load");
|
|
228
236
|
assert_eq!(sequence, DeterministicSequence { highest_seen: 0 });
|
|
229
237
|
}
|
|
230
238
|
|
|
231
239
|
#[tokio::test]
|
|
232
240
|
async fn persist_if_needed_is_noop_for_system_functions() {
|
|
233
|
-
let
|
|
234
|
-
let storage = StorageContext::new(backend.clone());
|
|
241
|
+
let storage = StorageContext::new(InMemoryStorageBackend::new());
|
|
235
242
|
let live_state = live_state_context();
|
|
236
|
-
let reader = live_state.reader(
|
|
243
|
+
let reader = live_state.reader(
|
|
244
|
+
storage
|
|
245
|
+
.begin_read(StorageReadOptions::default())
|
|
246
|
+
.expect("read should open"),
|
|
247
|
+
);
|
|
237
248
|
let context = FunctionContext::prepare(&reader)
|
|
238
249
|
.await
|
|
239
250
|
.expect("runtime context should prepare");
|
|
240
251
|
|
|
241
|
-
let
|
|
242
|
-
.begin_write_transaction()
|
|
243
|
-
.await
|
|
244
|
-
.expect("transaction should open");
|
|
245
|
-
let mut writes = StorageWriteSet::new();
|
|
252
|
+
let mut writes = storage.new_write_set();
|
|
246
253
|
context
|
|
247
254
|
.stage_persist_if_needed(&mut writes)
|
|
248
255
|
.await
|
|
249
256
|
.expect("persist should no-op");
|
|
250
257
|
assert!(writes.is_empty());
|
|
251
|
-
tx.commit().await.expect("transaction should commit");
|
|
252
258
|
|
|
253
|
-
let reader = live_state.reader(
|
|
259
|
+
let reader = live_state.reader(
|
|
260
|
+
storage
|
|
261
|
+
.begin_read(StorageReadOptions::default())
|
|
262
|
+
.expect("read should open"),
|
|
263
|
+
);
|
|
254
264
|
let sequence = load_sequence(&reader)
|
|
255
265
|
.await
|
|
256
266
|
.expect("missing sequence should load");
|
|
@@ -258,18 +268,14 @@ mod tests {
|
|
|
258
268
|
}
|
|
259
269
|
|
|
260
270
|
async fn write_key_value(storage: StorageContext, key: &str, value: serde_json::Value) {
|
|
261
|
-
let mut tx = storage
|
|
262
|
-
.begin_write_transaction()
|
|
263
|
-
.await
|
|
264
|
-
.expect("transaction should open");
|
|
265
271
|
let snapshot_content = serde_json::to_string(&serde_json::json!({
|
|
266
272
|
"key": key,
|
|
267
273
|
"value": value,
|
|
268
274
|
}))
|
|
269
275
|
.expect("snapshot should serialize");
|
|
270
|
-
let mut writes =
|
|
276
|
+
let mut writes = storage.new_write_set();
|
|
271
277
|
let row = crate::untracked_state::UntrackedStateRow {
|
|
272
|
-
|
|
278
|
+
entity_pk: crate::entity_pk::EntityPk::single(key),
|
|
273
279
|
schema_key: "lix_key_value".to_string(),
|
|
274
280
|
file_id: None,
|
|
275
281
|
snapshot_content: Some(snapshot_content),
|
|
@@ -277,16 +283,14 @@ mod tests {
|
|
|
277
283
|
created_at: "1970-01-01T00:00:00.000Z".to_string(),
|
|
278
284
|
updated_at: "1970-01-01T00:00:00.000Z".to_string(),
|
|
279
285
|
global: true,
|
|
280
|
-
|
|
286
|
+
branch_id: GLOBAL_BRANCH_ID.to_string(),
|
|
281
287
|
};
|
|
282
288
|
crate::untracked_state::UntrackedStateContext::new()
|
|
283
289
|
.writer(&mut writes)
|
|
284
290
|
.stage_rows(std::iter::once(row.as_ref()))
|
|
285
291
|
.expect("test key-value should stage");
|
|
286
|
-
|
|
287
|
-
.
|
|
288
|
-
.
|
|
289
|
-
.expect("test key-value should apply");
|
|
290
|
-
tx.commit().await.expect("transaction should commit");
|
|
292
|
+
storage
|
|
293
|
+
.commit_write_set(writes, StorageWriteOptions::default())
|
|
294
|
+
.expect("test key-value should commit");
|
|
291
295
|
}
|
|
292
296
|
}
|