@lix-js/sdk 0.6.0-preview.4 → 0.6.0
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 +76 -4
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +19 -0
- package/dist/index.d.ts +4 -5
- package/dist/index.js +3 -3
- package/dist/native.d.ts +1 -0
- package/dist/native.js +47 -0
- package/dist/open-lix.d.ts +39 -201
- package/dist/open-lix.js +59 -284
- package/dist/result.d.ts +18 -0
- package/dist/result.js +48 -0
- package/dist/types.d.ts +114 -1
- package/dist/value.d.ts +28 -0
- package/dist/value.js +245 -0
- package/package.json +20 -50
- package/SKILL.md +0 -506
- package/dist/builtin-schemas.d.ts +0 -1
- package/dist/builtin-schemas.js +0 -1
- package/dist/engine-wasm/index.d.ts +0 -87
- package/dist/engine-wasm/index.js +0 -339
- package/dist/engine-wasm/wasm/lix_engine.d.ts +0 -79
- package/dist/engine-wasm/wasm/lix_engine.js +0 -821
- package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
- package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +0 -26
- package/dist/generated/builtin-schemas.d.ts +0 -427
- package/dist/generated/builtin-schemas.js +0 -643
- package/dist/sqlite/index.d.ts +0 -12
- package/dist/sqlite/index.js +0 -303
- package/dist-engine-src/README.md +0 -18
- package/dist-engine-src/src/backend/kv.rs +0 -358
- package/dist-engine-src/src/backend/mod.rs +0 -12
- package/dist-engine-src/src/backend/testing.rs +0 -658
- package/dist-engine-src/src/backend/types.rs +0 -96
- package/dist-engine-src/src/binary_cas/chunking.rs +0 -31
- package/dist-engine-src/src/binary_cas/codec.rs +0 -346
- package/dist-engine-src/src/binary_cas/context.rs +0 -139
- package/dist-engine-src/src/binary_cas/kv.rs +0 -1063
- package/dist-engine-src/src/binary_cas/mod.rs +0 -11
- package/dist-engine-src/src/binary_cas/types.rs +0 -121
- package/dist-engine-src/src/catalog/context.rs +0 -412
- package/dist-engine-src/src/catalog/mod.rs +0 -10
- package/dist-engine-src/src/catalog/schema.rs +0 -4
- package/dist-engine-src/src/catalog/snapshot.rs +0 -1114
- package/dist-engine-src/src/cel/context.rs +0 -86
- package/dist-engine-src/src/cel/error.rs +0 -19
- package/dist-engine-src/src/cel/mod.rs +0 -8
- package/dist-engine-src/src/cel/provider.rs +0 -9
- package/dist-engine-src/src/cel/runtime.rs +0 -167
- package/dist-engine-src/src/cel/value.rs +0 -50
- package/dist-engine-src/src/commit_graph/context.rs +0 -901
- package/dist-engine-src/src/commit_graph/mod.rs +0 -11
- package/dist-engine-src/src/commit_graph/types.rs +0 -109
- package/dist-engine-src/src/commit_graph/walker.rs +0 -756
- 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/common/error.rs +0 -313
- package/dist-engine-src/src/common/fingerprint.rs +0 -3
- package/dist-engine-src/src/common/fs_path.rs +0 -1336
- package/dist-engine-src/src/common/identity.rs +0 -145
- package/dist-engine-src/src/common/json_pointer.rs +0 -67
- package/dist-engine-src/src/common/metadata.rs +0 -40
- package/dist-engine-src/src/common/mod.rs +0 -23
- package/dist-engine-src/src/common/types.rs +0 -105
- package/dist-engine-src/src/common/wire.rs +0 -222
- package/dist-engine-src/src/domain.rs +0 -324
- package/dist-engine-src/src/engine.rs +0 -225
- package/dist-engine-src/src/entity_identity.rs +0 -405
- package/dist-engine-src/src/functions/context.rs +0 -292
- package/dist-engine-src/src/functions/deterministic.rs +0 -113
- package/dist-engine-src/src/functions/mod.rs +0 -18
- package/dist-engine-src/src/functions/provider.rs +0 -130
- package/dist-engine-src/src/functions/state.rs +0 -336
- package/dist-engine-src/src/functions/types.rs +0 -37
- package/dist-engine-src/src/init.rs +0 -558
- package/dist-engine-src/src/json_store/compression.rs +0 -77
- package/dist-engine-src/src/json_store/context.rs +0 -423
- package/dist-engine-src/src/json_store/encoded.rs +0 -15
- package/dist-engine-src/src/json_store/mod.rs +0 -12
- package/dist-engine-src/src/json_store/store.rs +0 -1109
- package/dist-engine-src/src/json_store/types.rs +0 -217
- package/dist-engine-src/src/lib.rs +0 -62
- package/dist-engine-src/src/live_state/context.rs +0 -2019
- package/dist-engine-src/src/live_state/mod.rs +0 -15
- package/dist-engine-src/src/live_state/overlay.rs +0 -75
- package/dist-engine-src/src/live_state/reader.rs +0 -23
- package/dist-engine-src/src/live_state/types.rs +0 -222
- package/dist-engine-src/src/live_state/visibility.rs +0 -223
- package/dist-engine-src/src/plugin/archive.rs +0 -438
- package/dist-engine-src/src/plugin/component.rs +0 -183
- package/dist-engine-src/src/plugin/install.rs +0 -619
- package/dist-engine-src/src/plugin/manifest.rs +0 -516
- package/dist-engine-src/src/plugin/materializer.rs +0 -477
- package/dist-engine-src/src/plugin/mod.rs +0 -33
- package/dist-engine-src/src/plugin/plugin_manifest.json +0 -118
- package/dist-engine-src/src/plugin/storage.rs +0 -74
- package/dist-engine-src/src/schema/annotations/defaults.rs +0 -275
- package/dist-engine-src/src/schema/annotations/mod.rs +0 -1
- package/dist-engine-src/src/schema/builtin/lix_account.json +0 -21
- package/dist-engine-src/src/schema/builtin/lix_active_account.json +0 -29
- package/dist-engine-src/src/schema/builtin/lix_binary_blob_ref.json +0 -29
- package/dist-engine-src/src/schema/builtin/lix_change.json +0 -63
- package/dist-engine-src/src/schema/builtin/lix_change_author.json +0 -45
- package/dist-engine-src/src/schema/builtin/lix_commit.json +0 -24
- package/dist-engine-src/src/schema/builtin/lix_commit_edge.json +0 -53
- package/dist-engine-src/src/schema/builtin/lix_directory_descriptor.json +0 -52
- package/dist-engine-src/src/schema/builtin/lix_file_descriptor.json +0 -52
- package/dist-engine-src/src/schema/builtin/lix_key_value.json +0 -40
- package/dist-engine-src/src/schema/builtin/lix_label.json +0 -29
- package/dist-engine-src/src/schema/builtin/lix_label_assignment.json +0 -74
- package/dist-engine-src/src/schema/builtin/lix_registered_schema.json +0 -25
- 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/schema/builtin/mod.rs +0 -222
- package/dist-engine-src/src/schema/compatibility.rs +0 -787
- package/dist-engine-src/src/schema/definition.json +0 -187
- package/dist-engine-src/src/schema/definition.rs +0 -742
- package/dist-engine-src/src/schema/key.rs +0 -138
- package/dist-engine-src/src/schema/mod.rs +0 -20
- package/dist-engine-src/src/schema/seed.rs +0 -14
- package/dist-engine-src/src/schema/tests.rs +0 -780
- package/dist-engine-src/src/session/context.rs +0 -404
- package/dist-engine-src/src/session/create_version.rs +0 -88
- package/dist-engine-src/src/session/execute.rs +0 -541
- package/dist-engine-src/src/session/merge/analysis.rs +0 -102
- package/dist-engine-src/src/session/merge/apply.rs +0 -23
- package/dist-engine-src/src/session/merge/conflicts.rs +0 -63
- package/dist-engine-src/src/session/merge/mod.rs +0 -11
- package/dist-engine-src/src/session/merge/stats.rs +0 -65
- package/dist-engine-src/src/session/merge/version.rs +0 -427
- package/dist-engine-src/src/session/mod.rs +0 -27
- 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/session/transaction.rs +0 -76
- package/dist-engine-src/src/sql2/change_provider.rs +0 -331
- package/dist-engine-src/src/sql2/classify.rs +0 -174
- package/dist-engine-src/src/sql2/context.rs +0 -311
- package/dist-engine-src/src/sql2/directory_history_provider.rs +0 -631
- package/dist-engine-src/src/sql2/directory_provider.rs +0 -2453
- package/dist-engine-src/src/sql2/dml.rs +0 -148
- package/dist-engine-src/src/sql2/entity_history_provider.rs +0 -440
- package/dist-engine-src/src/sql2/entity_provider.rs +0 -3211
- package/dist-engine-src/src/sql2/error.rs +0 -215
- package/dist-engine-src/src/sql2/execute.rs +0 -3533
- package/dist-engine-src/src/sql2/file_history_provider.rs +0 -910
- package/dist-engine-src/src/sql2/file_provider.rs +0 -3679
- package/dist-engine-src/src/sql2/filesystem_planner.rs +0 -1490
- package/dist-engine-src/src/sql2/filesystem_predicates.rs +0 -159
- package/dist-engine-src/src/sql2/filesystem_visibility.rs +0 -383
- package/dist-engine-src/src/sql2/history_projection.rs +0 -56
- package/dist-engine-src/src/sql2/history_provider.rs +0 -412
- package/dist-engine-src/src/sql2/history_route.rs +0 -657
- package/dist-engine-src/src/sql2/lix_state_provider.rs +0 -2512
- package/dist-engine-src/src/sql2/mod.rs +0 -47
- package/dist-engine-src/src/sql2/predicate_typecheck.rs +0 -246
- 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/read_only.rs +0 -63
- package/dist-engine-src/src/sql2/record_batch.rs +0 -17
- package/dist-engine-src/src/sql2/result_metadata.rs +0 -29
- package/dist-engine-src/src/sql2/runtime.rs +0 -60
- package/dist-engine-src/src/sql2/session.rs +0 -132
- package/dist-engine-src/src/sql2/udfs/common.rs +0 -295
- package/dist-engine-src/src/sql2/udfs/lix_active_version_commit_id.rs +0 -53
- package/dist-engine-src/src/sql2/udfs/lix_empty_blob.rs +0 -47
- package/dist-engine-src/src/sql2/udfs/lix_json.rs +0 -100
- package/dist-engine-src/src/sql2/udfs/lix_json_get.rs +0 -99
- package/dist-engine-src/src/sql2/udfs/lix_json_get_text.rs +0 -99
- package/dist-engine-src/src/sql2/udfs/lix_text_decode.rs +0 -82
- package/dist-engine-src/src/sql2/udfs/lix_text_encode.rs +0 -85
- package/dist-engine-src/src/sql2/udfs/lix_timestamp.rs +0 -76
- package/dist-engine-src/src/sql2/udfs/lix_uuid_v7.rs +0 -76
- package/dist-engine-src/src/sql2/udfs/mod.rs +0 -89
- package/dist-engine-src/src/sql2/udfs/public_call.rs +0 -238
- package/dist-engine-src/src/sql2/version_provider.rs +0 -1202
- package/dist-engine-src/src/sql2/version_scope.rs +0 -394
- package/dist-engine-src/src/sql2/write_normalization.rs +0 -345
- package/dist-engine-src/src/storage/context.rs +0 -356
- package/dist-engine-src/src/storage/mod.rs +0 -14
- package/dist-engine-src/src/storage/read_scope.rs +0 -88
- package/dist-engine-src/src/storage/types.rs +0 -501
- package/dist-engine-src/src/storage_bench.rs +0 -4863
- package/dist-engine-src/src/test_support.rs +0 -228
- package/dist-engine-src/src/tracked_state/by_file_index.rs +0 -98
- package/dist-engine-src/src/tracked_state/codec.rs +0 -2085
- package/dist-engine-src/src/tracked_state/context.rs +0 -1867
- package/dist-engine-src/src/tracked_state/diff.rs +0 -686
- package/dist-engine-src/src/tracked_state/materialization.rs +0 -403
- package/dist-engine-src/src/tracked_state/materializer.rs +0 -488
- package/dist-engine-src/src/tracked_state/merge.rs +0 -492
- package/dist-engine-src/src/tracked_state/mod.rs +0 -32
- package/dist-engine-src/src/tracked_state/storage.rs +0 -375
- package/dist-engine-src/src/tracked_state/tree.rs +0 -3187
- package/dist-engine-src/src/tracked_state/types.rs +0 -231
- package/dist-engine-src/src/transaction/commit.rs +0 -1484
- package/dist-engine-src/src/transaction/context.rs +0 -1548
- package/dist-engine-src/src/transaction/live_state_overlay.rs +0 -35
- package/dist-engine-src/src/transaction/mod.rs +0 -13
- package/dist-engine-src/src/transaction/normalization.rs +0 -890
- package/dist-engine-src/src/transaction/prep.rs +0 -37
- package/dist-engine-src/src/transaction/schema_resolver.rs +0 -149
- package/dist-engine-src/src/transaction/staging.rs +0 -1731
- package/dist-engine-src/src/transaction/types.rs +0 -460
- package/dist-engine-src/src/transaction/validation.rs +0 -5830
- package/dist-engine-src/src/untracked_state/codec.rs +0 -307
- package/dist-engine-src/src/untracked_state/context.rs +0 -98
- package/dist-engine-src/src/untracked_state/materialization.rs +0 -63
- package/dist-engine-src/src/untracked_state/mod.rs +0 -15
- package/dist-engine-src/src/untracked_state/storage.rs +0 -396
- package/dist-engine-src/src/untracked_state/types.rs +0 -146
- package/dist-engine-src/src/version/context.rs +0 -40
- 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
- package/dist-engine-src/src/wasm/mod.rs +0 -60
|
@@ -1,658 +0,0 @@
|
|
|
1
|
-
use std::collections::BTreeMap;
|
|
2
|
-
use std::sync::{Arc, Mutex};
|
|
3
|
-
|
|
4
|
-
use async_trait::async_trait;
|
|
5
|
-
|
|
6
|
-
use crate::backend::{
|
|
7
|
-
Backend, BackendKvEntryPage, BackendKvExistsBatch, BackendKvExistsGroup, BackendKvGetRequest,
|
|
8
|
-
BackendKvKeyPage, BackendKvScanRange, BackendKvScanRequest, BackendKvValueBatch,
|
|
9
|
-
BackendKvValueGroup, BackendKvValuePage, BackendKvWriteBatch, BackendKvWriteStats,
|
|
10
|
-
BackendReadTransaction, BackendWriteTransaction, BytePageBuilder,
|
|
11
|
-
};
|
|
12
|
-
use crate::LixError;
|
|
13
|
-
|
|
14
|
-
type KvMap = BTreeMap<(String, Vec<u8>), Vec<u8>>;
|
|
15
|
-
|
|
16
|
-
/// In-memory backend for unit tests that need backend KV semantics without SQL.
|
|
17
|
-
///
|
|
18
|
-
/// SQL execution intentionally returns an error so new tests do not accidentally
|
|
19
|
-
/// couple to raw SQL while exercising storage-facing APIs.
|
|
20
|
-
#[derive(Debug, Clone, Default)]
|
|
21
|
-
pub(crate) struct UnitTestBackend {
|
|
22
|
-
kv: Arc<Mutex<KvMap>>,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
impl UnitTestBackend {
|
|
26
|
-
pub(crate) fn new() -> Self {
|
|
27
|
-
Self::default()
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
#[async_trait]
|
|
32
|
-
impl Backend for UnitTestBackend {
|
|
33
|
-
async fn begin_read_transaction(
|
|
34
|
-
&self,
|
|
35
|
-
) -> Result<Box<dyn BackendReadTransaction + Send + Sync + 'static>, LixError> {
|
|
36
|
-
let snapshot = self
|
|
37
|
-
.kv
|
|
38
|
-
.lock()
|
|
39
|
-
.map_err(|_| lock_error("unit test backend kv"))?
|
|
40
|
-
.clone();
|
|
41
|
-
Ok(Box::new(UnitTestTransaction {
|
|
42
|
-
parent: Arc::clone(&self.kv),
|
|
43
|
-
kv: snapshot,
|
|
44
|
-
}))
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async fn begin_write_transaction(
|
|
48
|
-
&self,
|
|
49
|
-
) -> Result<Box<dyn BackendWriteTransaction + Send + Sync + 'static>, LixError> {
|
|
50
|
-
let snapshot = self
|
|
51
|
-
.kv
|
|
52
|
-
.lock()
|
|
53
|
-
.map_err(|_| lock_error("unit test backend kv"))?
|
|
54
|
-
.clone();
|
|
55
|
-
Ok(Box::new(UnitTestTransaction {
|
|
56
|
-
parent: Arc::clone(&self.kv),
|
|
57
|
-
kv: snapshot,
|
|
58
|
-
}))
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
struct UnitTestTransaction {
|
|
63
|
-
parent: Arc<Mutex<KvMap>>,
|
|
64
|
-
kv: KvMap,
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
#[async_trait]
|
|
68
|
-
impl BackendReadTransaction for UnitTestTransaction {
|
|
69
|
-
async fn get_values(
|
|
70
|
-
&mut self,
|
|
71
|
-
request: BackendKvGetRequest,
|
|
72
|
-
) -> Result<BackendKvValueBatch, LixError> {
|
|
73
|
-
let mut groups = Vec::with_capacity(request.groups.len());
|
|
74
|
-
for group in request.groups {
|
|
75
|
-
let namespace = group.namespace.clone();
|
|
76
|
-
let mut values = BytePageBuilder::with_capacity(group.keys.len(), 0);
|
|
77
|
-
let mut present = Vec::with_capacity(group.keys.len());
|
|
78
|
-
for key in group.keys {
|
|
79
|
-
if let Some(value) = self.kv.get(&(namespace.clone(), key)) {
|
|
80
|
-
values.push(value);
|
|
81
|
-
present.push(true);
|
|
82
|
-
} else {
|
|
83
|
-
values.push([]);
|
|
84
|
-
present.push(false);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
groups.push(BackendKvValueGroup::new(
|
|
88
|
-
namespace,
|
|
89
|
-
values.finish(),
|
|
90
|
-
present,
|
|
91
|
-
));
|
|
92
|
-
}
|
|
93
|
-
Ok(BackendKvValueBatch { groups })
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async fn exists_many(
|
|
97
|
-
&mut self,
|
|
98
|
-
request: BackendKvGetRequest,
|
|
99
|
-
) -> Result<BackendKvExistsBatch, LixError> {
|
|
100
|
-
let mut groups = Vec::with_capacity(request.groups.len());
|
|
101
|
-
for group in request.groups {
|
|
102
|
-
let namespace = group.namespace.clone();
|
|
103
|
-
let exists = group
|
|
104
|
-
.keys
|
|
105
|
-
.into_iter()
|
|
106
|
-
.map(|key| self.kv.contains_key(&(namespace.clone(), key)))
|
|
107
|
-
.collect();
|
|
108
|
-
groups.push(BackendKvExistsGroup { namespace, exists });
|
|
109
|
-
}
|
|
110
|
-
Ok(BackendKvExistsBatch { groups })
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async fn scan_keys(
|
|
114
|
-
&mut self,
|
|
115
|
-
request: BackendKvScanRequest,
|
|
116
|
-
) -> Result<BackendKvKeyPage, LixError> {
|
|
117
|
-
Ok(scan_map_keys(&self.kv, request))
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async fn scan_values(
|
|
121
|
-
&mut self,
|
|
122
|
-
request: BackendKvScanRequest,
|
|
123
|
-
) -> Result<BackendKvValuePage, LixError> {
|
|
124
|
-
Ok(scan_map_values(&self.kv, request))
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
async fn scan_entries(
|
|
128
|
-
&mut self,
|
|
129
|
-
request: BackendKvScanRequest,
|
|
130
|
-
) -> Result<BackendKvEntryPage, LixError> {
|
|
131
|
-
Ok(scan_map_entries(&self.kv, request))
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async fn rollback(self: Box<Self>) -> Result<(), LixError> {
|
|
135
|
-
Ok(())
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
#[async_trait]
|
|
140
|
-
impl BackendWriteTransaction for UnitTestTransaction {
|
|
141
|
-
async fn write_kv_batch(
|
|
142
|
-
&mut self,
|
|
143
|
-
batch: BackendKvWriteBatch,
|
|
144
|
-
) -> Result<BackendKvWriteStats, LixError> {
|
|
145
|
-
let mut stats = BackendKvWriteStats::default();
|
|
146
|
-
for group in batch.groups {
|
|
147
|
-
let namespace = group.namespace().to_string();
|
|
148
|
-
for index in 0..group.put_count() {
|
|
149
|
-
let key = group.put_key(index).ok_or_else(|| {
|
|
150
|
-
LixError::new("LIX_ERROR_UNKNOWN", "backend write batch missing put key")
|
|
151
|
-
})?;
|
|
152
|
-
let value = group.put_value(index).ok_or_else(|| {
|
|
153
|
-
LixError::new("LIX_ERROR_UNKNOWN", "backend write batch missing put value")
|
|
154
|
-
})?;
|
|
155
|
-
stats.puts += 1;
|
|
156
|
-
stats.bytes_written += key.len() + value.len();
|
|
157
|
-
self.kv
|
|
158
|
-
.insert((namespace.clone(), key.to_vec()), value.to_vec());
|
|
159
|
-
}
|
|
160
|
-
for index in 0..group.delete_count() {
|
|
161
|
-
let key = group.delete_key(index).ok_or_else(|| {
|
|
162
|
-
LixError::new(
|
|
163
|
-
"LIX_ERROR_UNKNOWN",
|
|
164
|
-
"backend write batch missing delete key",
|
|
165
|
-
)
|
|
166
|
-
})?;
|
|
167
|
-
stats.deletes += 1;
|
|
168
|
-
stats.bytes_written += key.len();
|
|
169
|
-
self.kv.remove(&(namespace.clone(), key.to_vec()));
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
Ok(stats)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
async fn commit(self: Box<Self>) -> Result<(), LixError> {
|
|
176
|
-
*self
|
|
177
|
-
.parent
|
|
178
|
-
.lock()
|
|
179
|
-
.map_err(|_| lock_error("unit test backend kv"))? = self.kv;
|
|
180
|
-
Ok(())
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
#[async_trait]
|
|
185
|
-
impl Backend for Arc<UnitTestBackend> {
|
|
186
|
-
async fn begin_read_transaction(
|
|
187
|
-
&self,
|
|
188
|
-
) -> Result<Box<dyn BackendReadTransaction + Send + Sync + 'static>, LixError> {
|
|
189
|
-
self.as_ref().begin_read_transaction().await
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
async fn begin_write_transaction(
|
|
193
|
-
&self,
|
|
194
|
-
) -> Result<Box<dyn BackendWriteTransaction + Send + Sync + 'static>, LixError> {
|
|
195
|
-
self.as_ref().begin_write_transaction().await
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
fn scan_pairs<'a>(
|
|
200
|
-
kv: &'a KvMap,
|
|
201
|
-
namespace: &str,
|
|
202
|
-
range: &BackendKvScanRange,
|
|
203
|
-
limit: Option<usize>,
|
|
204
|
-
) -> Vec<(&'a Vec<u8>, &'a Vec<u8>)> {
|
|
205
|
-
let pairs = kv
|
|
206
|
-
.iter()
|
|
207
|
-
.filter(|((candidate_namespace, key), _)| {
|
|
208
|
-
candidate_namespace == namespace && key_matches_range(key, range)
|
|
209
|
-
})
|
|
210
|
-
.collect::<Vec<_>>();
|
|
211
|
-
let mut pairs = pairs;
|
|
212
|
-
pairs.sort_by(|left, right| left.0 .1.cmp(&right.0 .1));
|
|
213
|
-
if let Some(limit) = limit {
|
|
214
|
-
pairs.truncate(limit);
|
|
215
|
-
}
|
|
216
|
-
pairs
|
|
217
|
-
.into_iter()
|
|
218
|
-
.map(|((_, key), value)| (key, value))
|
|
219
|
-
.collect()
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
pub(crate) fn scan_map_keys(kv: &KvMap, request: BackendKvScanRequest) -> BackendKvKeyPage {
|
|
223
|
-
let pairs = scan_filtered_pairs(kv, &request);
|
|
224
|
-
let has_more = pairs.len() > request.limit;
|
|
225
|
-
let mut keys = BytePageBuilder::with_capacity(request.limit.min(pairs.len()), 0);
|
|
226
|
-
let mut resume_after = None;
|
|
227
|
-
for (index, (key, _)) in pairs.into_iter().enumerate() {
|
|
228
|
-
if index >= request.limit {
|
|
229
|
-
break;
|
|
230
|
-
}
|
|
231
|
-
resume_after = Some(key.clone());
|
|
232
|
-
keys.push(key);
|
|
233
|
-
}
|
|
234
|
-
let resume_after = has_more.then_some(resume_after).flatten();
|
|
235
|
-
BackendKvKeyPage {
|
|
236
|
-
keys: keys.finish(),
|
|
237
|
-
resume_after,
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
pub(crate) fn scan_map_values(kv: &KvMap, request: BackendKvScanRequest) -> BackendKvValuePage {
|
|
242
|
-
let pairs = scan_filtered_pairs(kv, &request);
|
|
243
|
-
let has_more = pairs.len() > request.limit;
|
|
244
|
-
let mut values = BytePageBuilder::with_capacity(request.limit.min(pairs.len()), 0);
|
|
245
|
-
let mut resume_after = None;
|
|
246
|
-
for (index, (key, value)) in pairs.into_iter().enumerate() {
|
|
247
|
-
if index >= request.limit {
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
resume_after = Some(key.clone());
|
|
251
|
-
values.push(value);
|
|
252
|
-
}
|
|
253
|
-
let resume_after = has_more.then_some(resume_after).flatten();
|
|
254
|
-
BackendKvValuePage {
|
|
255
|
-
values: values.finish(),
|
|
256
|
-
resume_after,
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
pub(crate) fn scan_map_entries(kv: &KvMap, request: BackendKvScanRequest) -> BackendKvEntryPage {
|
|
261
|
-
let pairs = scan_filtered_pairs(kv, &request);
|
|
262
|
-
let has_more = pairs.len() > request.limit;
|
|
263
|
-
let mut keys = BytePageBuilder::with_capacity(request.limit.min(pairs.len()), 0);
|
|
264
|
-
let mut values = BytePageBuilder::with_capacity(request.limit.min(pairs.len()), 0);
|
|
265
|
-
let mut resume_after = None;
|
|
266
|
-
for (index, (key, value)) in pairs.into_iter().enumerate() {
|
|
267
|
-
if index >= request.limit {
|
|
268
|
-
break;
|
|
269
|
-
}
|
|
270
|
-
resume_after = Some(key.clone());
|
|
271
|
-
keys.push(key);
|
|
272
|
-
values.push(value);
|
|
273
|
-
}
|
|
274
|
-
let resume_after = has_more.then_some(resume_after).flatten();
|
|
275
|
-
BackendKvEntryPage {
|
|
276
|
-
keys: keys.finish(),
|
|
277
|
-
values: values.finish(),
|
|
278
|
-
resume_after,
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
fn scan_filtered_pairs<'a>(
|
|
283
|
-
kv: &'a KvMap,
|
|
284
|
-
request: &BackendKvScanRequest,
|
|
285
|
-
) -> Vec<(&'a Vec<u8>, &'a Vec<u8>)> {
|
|
286
|
-
let scan_limit = request
|
|
287
|
-
.limit
|
|
288
|
-
.checked_add(1 + usize::from(request.after.is_some()))
|
|
289
|
-
.unwrap_or(request.limit);
|
|
290
|
-
scan_pairs(kv, &request.namespace, &request.range, Some(scan_limit))
|
|
291
|
-
.into_iter()
|
|
292
|
-
.filter(|(key, _)| {
|
|
293
|
-
request
|
|
294
|
-
.after
|
|
295
|
-
.as_deref()
|
|
296
|
-
.is_none_or(|after| key.as_slice() > after)
|
|
297
|
-
})
|
|
298
|
-
.collect()
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
fn key_matches_range(key: &[u8], range: &BackendKvScanRange) -> bool {
|
|
302
|
-
match range {
|
|
303
|
-
BackendKvScanRange::Prefix(prefix) => key.starts_with(prefix),
|
|
304
|
-
BackendKvScanRange::Range { start, end } => start.as_slice() <= key && key < end.as_slice(),
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
fn lock_error(name: &str) -> LixError {
|
|
309
|
-
LixError::new("LIX_ERROR_UNKNOWN", format!("{name} lock poisoned"))
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
#[cfg(test)]
|
|
313
|
-
mod tests {
|
|
314
|
-
use super::*;
|
|
315
|
-
use crate::backend::{
|
|
316
|
-
BackendKvGetGroup, BackendKvGetRequest, BackendKvScanRequest, BackendKvWriteBatch,
|
|
317
|
-
BackendKvWriteGroup,
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
async fn put(
|
|
321
|
-
transaction: &mut (dyn BackendWriteTransaction + Send + Sync),
|
|
322
|
-
namespace: &str,
|
|
323
|
-
key: &[u8],
|
|
324
|
-
value: &[u8],
|
|
325
|
-
) {
|
|
326
|
-
transaction
|
|
327
|
-
.write_kv_batch(BackendKvWriteBatch {
|
|
328
|
-
groups: {
|
|
329
|
-
let mut group = BackendKvWriteGroup::new(namespace);
|
|
330
|
-
group.put(key, value);
|
|
331
|
-
vec![group]
|
|
332
|
-
},
|
|
333
|
-
})
|
|
334
|
-
.await
|
|
335
|
-
.expect("put should succeed");
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
async fn delete(
|
|
339
|
-
transaction: &mut (dyn BackendWriteTransaction + Send + Sync),
|
|
340
|
-
namespace: &str,
|
|
341
|
-
key: &[u8],
|
|
342
|
-
) {
|
|
343
|
-
transaction
|
|
344
|
-
.write_kv_batch(BackendKvWriteBatch {
|
|
345
|
-
groups: {
|
|
346
|
-
let mut group = BackendKvWriteGroup::new(namespace);
|
|
347
|
-
group.delete(key);
|
|
348
|
-
vec![group]
|
|
349
|
-
},
|
|
350
|
-
})
|
|
351
|
-
.await
|
|
352
|
-
.expect("delete should succeed");
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
async fn get(backend: &UnitTestBackend, namespace: &str, key: &[u8]) -> Option<Vec<u8>> {
|
|
356
|
-
let mut transaction = backend
|
|
357
|
-
.begin_read_transaction()
|
|
358
|
-
.await
|
|
359
|
-
.expect("read transaction should open");
|
|
360
|
-
let result = transaction
|
|
361
|
-
.get_values(BackendKvGetRequest {
|
|
362
|
-
groups: vec![BackendKvGetGroup {
|
|
363
|
-
namespace: namespace.to_string(),
|
|
364
|
-
keys: vec![key.to_vec()],
|
|
365
|
-
}],
|
|
366
|
-
})
|
|
367
|
-
.await
|
|
368
|
-
.expect("get should succeed");
|
|
369
|
-
transaction
|
|
370
|
-
.rollback()
|
|
371
|
-
.await
|
|
372
|
-
.expect("rollback should succeed");
|
|
373
|
-
result
|
|
374
|
-
.groups
|
|
375
|
-
.into_iter()
|
|
376
|
-
.next()
|
|
377
|
-
.and_then(|group| group.value(0).flatten().map(<[u8]>::to_vec))
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
async fn scan(
|
|
381
|
-
backend: &UnitTestBackend,
|
|
382
|
-
namespace: &str,
|
|
383
|
-
range: BackendKvScanRange,
|
|
384
|
-
limit: usize,
|
|
385
|
-
) -> BackendKvEntryPage {
|
|
386
|
-
let mut transaction = backend
|
|
387
|
-
.begin_read_transaction()
|
|
388
|
-
.await
|
|
389
|
-
.expect("read transaction should open");
|
|
390
|
-
let result = transaction
|
|
391
|
-
.scan_entries(BackendKvScanRequest {
|
|
392
|
-
namespace: namespace.to_string(),
|
|
393
|
-
range,
|
|
394
|
-
after: None,
|
|
395
|
-
limit,
|
|
396
|
-
})
|
|
397
|
-
.await
|
|
398
|
-
.expect("scan should succeed");
|
|
399
|
-
transaction
|
|
400
|
-
.rollback()
|
|
401
|
-
.await
|
|
402
|
-
.expect("rollback should succeed");
|
|
403
|
-
result
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
fn assert_entries(page: &BackendKvEntryPage, expected: &[(&[u8], &[u8])]) {
|
|
407
|
-
assert_eq!(page.len(), expected.len());
|
|
408
|
-
for (index, (key, value)) in expected.iter().enumerate() {
|
|
409
|
-
assert_eq!(page.key(index).expect("key exists"), *key);
|
|
410
|
-
assert_eq!(page.value(index).expect("value exists"), *value);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
async fn scan_entries_request(
|
|
415
|
-
backend: &UnitTestBackend,
|
|
416
|
-
after: Option<&[u8]>,
|
|
417
|
-
limit: usize,
|
|
418
|
-
) -> BackendKvEntryPage {
|
|
419
|
-
let mut transaction = backend
|
|
420
|
-
.begin_read_transaction()
|
|
421
|
-
.await
|
|
422
|
-
.expect("read transaction should open");
|
|
423
|
-
let result = transaction
|
|
424
|
-
.scan_entries(BackendKvScanRequest {
|
|
425
|
-
namespace: "ns".to_string(),
|
|
426
|
-
range: BackendKvScanRange::prefix(Vec::new()),
|
|
427
|
-
after: after.map(Vec::from),
|
|
428
|
-
limit,
|
|
429
|
-
})
|
|
430
|
-
.await
|
|
431
|
-
.expect("scan should succeed");
|
|
432
|
-
transaction
|
|
433
|
-
.rollback()
|
|
434
|
-
.await
|
|
435
|
-
.expect("rollback should succeed");
|
|
436
|
-
result
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
async fn scan_keys_request(
|
|
440
|
-
backend: &UnitTestBackend,
|
|
441
|
-
after: Option<&[u8]>,
|
|
442
|
-
limit: usize,
|
|
443
|
-
) -> BackendKvKeyPage {
|
|
444
|
-
let mut transaction = backend
|
|
445
|
-
.begin_read_transaction()
|
|
446
|
-
.await
|
|
447
|
-
.expect("read transaction should open");
|
|
448
|
-
let result = transaction
|
|
449
|
-
.scan_keys(BackendKvScanRequest {
|
|
450
|
-
namespace: "ns".to_string(),
|
|
451
|
-
range: BackendKvScanRange::prefix(Vec::new()),
|
|
452
|
-
after: after.map(Vec::from),
|
|
453
|
-
limit,
|
|
454
|
-
})
|
|
455
|
-
.await
|
|
456
|
-
.expect("scan should succeed");
|
|
457
|
-
transaction
|
|
458
|
-
.rollback()
|
|
459
|
-
.await
|
|
460
|
-
.expect("rollback should succeed");
|
|
461
|
-
result
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
#[tokio::test]
|
|
465
|
-
async fn committed_put_is_visible_to_backend_reads() {
|
|
466
|
-
let backend = UnitTestBackend::new();
|
|
467
|
-
let mut transaction = backend
|
|
468
|
-
.begin_write_transaction()
|
|
469
|
-
.await
|
|
470
|
-
.expect("transaction should open");
|
|
471
|
-
put(transaction.as_mut(), "live_state", b"key", b"value").await;
|
|
472
|
-
transaction.commit().await.expect("commit should succeed");
|
|
473
|
-
|
|
474
|
-
assert_eq!(
|
|
475
|
-
get(&backend, "live_state", b"key").await,
|
|
476
|
-
Some(b"value".to_vec())
|
|
477
|
-
);
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
#[tokio::test]
|
|
481
|
-
async fn rollback_discards_puts() {
|
|
482
|
-
let backend = UnitTestBackend::new();
|
|
483
|
-
let mut transaction = backend
|
|
484
|
-
.begin_write_transaction()
|
|
485
|
-
.await
|
|
486
|
-
.expect("transaction should open");
|
|
487
|
-
put(transaction.as_mut(), "live_state", b"key", b"value").await;
|
|
488
|
-
transaction
|
|
489
|
-
.rollback()
|
|
490
|
-
.await
|
|
491
|
-
.expect("rollback should succeed");
|
|
492
|
-
|
|
493
|
-
assert_eq!(get(&backend, "live_state", b"key").await, None);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
#[tokio::test]
|
|
497
|
-
async fn close_is_idempotent_and_does_not_destroy_data() {
|
|
498
|
-
let backend = UnitTestBackend::new();
|
|
499
|
-
let mut transaction = backend
|
|
500
|
-
.begin_write_transaction()
|
|
501
|
-
.await
|
|
502
|
-
.expect("transaction should open");
|
|
503
|
-
put(transaction.as_mut(), "live_state", b"key", b"value").await;
|
|
504
|
-
transaction.commit().await.expect("commit should succeed");
|
|
505
|
-
|
|
506
|
-
backend.close().await.expect("first close should succeed");
|
|
507
|
-
backend.close().await.expect("second close should succeed");
|
|
508
|
-
|
|
509
|
-
assert_eq!(
|
|
510
|
-
get(&backend, "live_state", b"key").await,
|
|
511
|
-
Some(b"value".to_vec())
|
|
512
|
-
);
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
#[tokio::test]
|
|
516
|
-
async fn delete_removes_key_on_commit() {
|
|
517
|
-
let backend = UnitTestBackend::new();
|
|
518
|
-
let mut seed = backend
|
|
519
|
-
.begin_write_transaction()
|
|
520
|
-
.await
|
|
521
|
-
.expect("seed transaction should open");
|
|
522
|
-
put(seed.as_mut(), "live_state", b"key", b"value").await;
|
|
523
|
-
seed.commit().await.expect("seed commit should succeed");
|
|
524
|
-
|
|
525
|
-
let mut transaction = backend
|
|
526
|
-
.begin_write_transaction()
|
|
527
|
-
.await
|
|
528
|
-
.expect("delete transaction should open");
|
|
529
|
-
delete(transaction.as_mut(), "live_state", b"key").await;
|
|
530
|
-
transaction.commit().await.expect("commit should succeed");
|
|
531
|
-
|
|
532
|
-
assert_eq!(get(&backend, "live_state", b"key").await, None);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
#[tokio::test]
|
|
536
|
-
async fn prefix_scan_returns_lexicographic_order_with_limit() {
|
|
537
|
-
let backend = UnitTestBackend::new();
|
|
538
|
-
let mut transaction = backend
|
|
539
|
-
.begin_write_transaction()
|
|
540
|
-
.await
|
|
541
|
-
.expect("transaction should open");
|
|
542
|
-
put(transaction.as_mut(), "ns", b"b/2", b"2").await;
|
|
543
|
-
put(transaction.as_mut(), "ns", b"a/2", b"2").await;
|
|
544
|
-
put(transaction.as_mut(), "ns", b"a/1", b"1").await;
|
|
545
|
-
put(transaction.as_mut(), "other", b"a/0", b"0").await;
|
|
546
|
-
transaction.commit().await.unwrap();
|
|
547
|
-
|
|
548
|
-
let pairs = scan(&backend, "ns", BackendKvScanRange::prefix(b"a/"), 1).await;
|
|
549
|
-
assert_entries(&pairs, &[(b"a/1", b"1")]);
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
#[tokio::test]
|
|
553
|
-
async fn scan_sets_resume_after_only_when_more_rows_exist() {
|
|
554
|
-
let backend = UnitTestBackend::new();
|
|
555
|
-
let mut transaction = backend
|
|
556
|
-
.begin_write_transaction()
|
|
557
|
-
.await
|
|
558
|
-
.expect("transaction should open");
|
|
559
|
-
put(transaction.as_mut(), "ns", b"a", b"1").await;
|
|
560
|
-
put(transaction.as_mut(), "ns", b"b", b"2").await;
|
|
561
|
-
put(transaction.as_mut(), "ns", b"c", b"3").await;
|
|
562
|
-
transaction.commit().await.unwrap();
|
|
563
|
-
|
|
564
|
-
let first_page = scan_entries_request(&backend, None, 2).await;
|
|
565
|
-
assert_entries(&first_page, &[(b"a", b"1"), (b"b", b"2")]);
|
|
566
|
-
assert_eq!(first_page.resume_after, Some(b"b".to_vec()));
|
|
567
|
-
|
|
568
|
-
let second_page =
|
|
569
|
-
scan_entries_request(&backend, first_page.resume_after.as_deref(), 2).await;
|
|
570
|
-
assert_entries(&second_page, &[(b"c", b"3")]);
|
|
571
|
-
assert_eq!(second_page.resume_after, None);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
#[tokio::test]
|
|
575
|
-
async fn scan_exact_page_size_has_no_resume_after() {
|
|
576
|
-
let backend = UnitTestBackend::new();
|
|
577
|
-
let mut transaction = backend
|
|
578
|
-
.begin_write_transaction()
|
|
579
|
-
.await
|
|
580
|
-
.expect("transaction should open");
|
|
581
|
-
put(transaction.as_mut(), "ns", b"a", b"1").await;
|
|
582
|
-
put(transaction.as_mut(), "ns", b"b", b"2").await;
|
|
583
|
-
transaction.commit().await.unwrap();
|
|
584
|
-
|
|
585
|
-
let page = scan_entries_request(&backend, None, 2).await;
|
|
586
|
-
assert_entries(&page, &[(b"a", b"1"), (b"b", b"2")]);
|
|
587
|
-
assert_eq!(page.resume_after, None);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
#[tokio::test]
|
|
591
|
-
async fn key_only_scan_omits_values() {
|
|
592
|
-
let backend = UnitTestBackend::new();
|
|
593
|
-
let mut transaction = backend
|
|
594
|
-
.begin_write_transaction()
|
|
595
|
-
.await
|
|
596
|
-
.expect("transaction should open");
|
|
597
|
-
put(transaction.as_mut(), "ns", b"a", b"1").await;
|
|
598
|
-
put(transaction.as_mut(), "ns", b"b", b"2").await;
|
|
599
|
-
transaction.commit().await.unwrap();
|
|
600
|
-
|
|
601
|
-
let page = scan_keys_request(&backend, None, 2).await;
|
|
602
|
-
assert_eq!(page.keys.iter().collect::<Vec<_>>(), vec![b"a", b"b"]);
|
|
603
|
-
assert_eq!(page.resume_after, None);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
#[tokio::test]
|
|
607
|
-
async fn existence_get_omits_values() {
|
|
608
|
-
let backend = UnitTestBackend::new();
|
|
609
|
-
let mut transaction = backend
|
|
610
|
-
.begin_write_transaction()
|
|
611
|
-
.await
|
|
612
|
-
.expect("transaction should open");
|
|
613
|
-
put(transaction.as_mut(), "ns", b"a", b"1").await;
|
|
614
|
-
transaction.commit().await.unwrap();
|
|
615
|
-
|
|
616
|
-
let mut transaction = backend
|
|
617
|
-
.begin_read_transaction()
|
|
618
|
-
.await
|
|
619
|
-
.expect("read transaction should open");
|
|
620
|
-
let result = transaction
|
|
621
|
-
.exists_many(BackendKvGetRequest {
|
|
622
|
-
groups: vec![BackendKvGetGroup {
|
|
623
|
-
namespace: "ns".to_string(),
|
|
624
|
-
keys: vec![b"a".to_vec(), b"missing".to_vec()],
|
|
625
|
-
}],
|
|
626
|
-
})
|
|
627
|
-
.await
|
|
628
|
-
.expect("existence get should succeed");
|
|
629
|
-
transaction
|
|
630
|
-
.rollback()
|
|
631
|
-
.await
|
|
632
|
-
.expect("rollback should succeed");
|
|
633
|
-
|
|
634
|
-
assert_eq!(result.groups[0].exists, vec![true, false]);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
#[tokio::test]
|
|
638
|
-
async fn range_scan_is_half_open() {
|
|
639
|
-
let backend = UnitTestBackend::new();
|
|
640
|
-
let mut transaction = backend
|
|
641
|
-
.begin_write_transaction()
|
|
642
|
-
.await
|
|
643
|
-
.expect("transaction should open");
|
|
644
|
-
put(transaction.as_mut(), "ns", b"a", b"a").await;
|
|
645
|
-
put(transaction.as_mut(), "ns", b"b", b"b").await;
|
|
646
|
-
put(transaction.as_mut(), "ns", b"c", b"c").await;
|
|
647
|
-
transaction.commit().await.unwrap();
|
|
648
|
-
|
|
649
|
-
let pairs = scan(
|
|
650
|
-
&backend,
|
|
651
|
-
"ns",
|
|
652
|
-
BackendKvScanRange::range(b"a", b"c"),
|
|
653
|
-
usize::MAX,
|
|
654
|
-
)
|
|
655
|
-
.await;
|
|
656
|
-
assert_entries(&pairs, &[(b"a", b"a"), (b"b", b"b")]);
|
|
657
|
-
}
|
|
658
|
-
}
|