@lix-js/sdk 0.6.0-preview.5 → 0.6.1
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 +38 -207
- 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 +38 -71
- package/SKILL.md +0 -507
- 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 -833
- package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
- package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +0 -27
- 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 -359
- package/dist-engine-src/README.md +0 -18
- package/dist-engine-src/src/backend/capabilities.rs +0 -67
- package/dist-engine-src/src/backend/conformance/baseline.rs +0 -1127
- package/dist-engine-src/src/backend/conformance/factory.rs +0 -93
- package/dist-engine-src/src/backend/conformance/failure_tests.rs +0 -608
- package/dist-engine-src/src/backend/conformance/fixtures.rs +0 -26
- package/dist-engine-src/src/backend/conformance/mod.rs +0 -75
- package/dist-engine-src/src/backend/conformance/model.rs +0 -28
- package/dist-engine-src/src/backend/conformance/model_based.rs +0 -257
- package/dist-engine-src/src/backend/conformance/persistence.rs +0 -204
- package/dist-engine-src/src/backend/conformance/projection.rs +0 -21
- package/dist-engine-src/src/backend/conformance/pushdown.rs +0 -24
- package/dist-engine-src/src/backend/conformance/runner.rs +0 -90
- package/dist-engine-src/src/backend/conformance/scan.rs +0 -24
- package/dist-engine-src/src/backend/conformance/write.rs +0 -16
- package/dist-engine-src/src/backend/error.rs +0 -94
- package/dist-engine-src/src/backend/in_memory.rs +0 -670
- package/dist-engine-src/src/backend/mod.rs +0 -39
- package/dist-engine-src/src/backend/predicate.rs +0 -80
- package/dist-engine-src/src/backend/traits.rs +0 -260
- package/dist-engine-src/src/backend/types.rs +0 -239
- 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 -1038
- 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/branch/context.rs +0 -40
- package/dist-engine-src/src/branch/lifecycle.rs +0 -221
- package/dist-engine-src/src/branch/mod.rs +0 -13
- package/dist-engine-src/src/branch/refs.rs +0 -321
- package/dist-engine-src/src/branch/stage_rows.rs +0 -67
- package/dist-engine-src/src/branch/types.rs +0 -21
- 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/changelog/bench_support.rs +0 -785
- package/dist-engine-src/src/changelog/change.rs +0 -1
- package/dist-engine-src/src/changelog/codec.rs +0 -497
- package/dist-engine-src/src/changelog/commit.rs +0 -1
- package/dist-engine-src/src/changelog/context.rs +0 -1614
- package/dist-engine-src/src/changelog/mod.rs +0 -29
- package/dist-engine-src/src/changelog/store.rs +0 -163
- package/dist-engine-src/src/changelog/test_support.rs +0 -54
- package/dist-engine-src/src/changelog/types.rs +0 -213
- package/dist-engine-src/src/commit_graph/context.rs +0 -944
- package/dist-engine-src/src/commit_graph/mod.rs +0 -9
- package/dist-engine-src/src/commit_graph/types.rs +0 -89
- package/dist-engine-src/src/commit_graph/walker.rs +0 -786
- package/dist-engine-src/src/common/error.rs +0 -347
- 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 -320
- package/dist-engine-src/src/engine.rs +0 -203
- package/dist-engine-src/src/entity_pk.rs +0 -402
- package/dist-engine-src/src/functions/context.rs +0 -296
- 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 -335
- package/dist-engine-src/src/functions/types.rs +0 -37
- package/dist-engine-src/src/init.rs +0 -692
- package/dist-engine-src/src/json_store/compression.rs +0 -77
- package/dist-engine-src/src/json_store/context.rs +0 -172
- package/dist-engine-src/src/json_store/encoded.rs +0 -15
- package/dist-engine-src/src/json_store/mod.rs +0 -38
- package/dist-engine-src/src/json_store/store.rs +0 -494
- package/dist-engine-src/src/json_store/types.rs +0 -212
- package/dist-engine-src/src/lib.rs +0 -92
- package/dist-engine-src/src/live_state/context.rs +0 -1883
- package/dist-engine-src/src/live_state/mod.rs +0 -21
- 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 -231
- package/dist-engine-src/src/live_state/visibility.rs +0 -666
- 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 -202
- package/dist-engine-src/src/plugin/mod.rs +0 -33
- package/dist-engine-src/src/plugin/plugin_manifest.json +0 -119
- 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_branch_descriptor.json +0 -34
- package/dist-engine-src/src/schema/builtin/lix_branch_ref.json +0 -48
- 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/mod.rs +0 -220
- 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 -1059
- package/dist-engine-src/src/session/create_branch.rs +0 -94
- package/dist-engine-src/src/session/execute.rs +0 -681
- package/dist-engine-src/src/session/merge/analysis.rs +0 -108
- package/dist-engine-src/src/session/merge/branch.rs +0 -417
- package/dist-engine-src/src/session/merge/conflicts.rs +0 -63
- package/dist-engine-src/src/session/merge/mod.rs +0 -10
- package/dist-engine-src/src/session/merge/stats.rs +0 -61
- package/dist-engine-src/src/session/mod.rs +0 -30
- package/dist-engine-src/src/session/switch_branch.rs +0 -113
- package/dist-engine-src/src/session/transaction.rs +0 -557
- package/dist-engine-src/src/sql2/bind/classify.rs +0 -102
- package/dist-engine-src/src/sql2/bind/error.rs +0 -5
- package/dist-engine-src/src/sql2/bind/expr.rs +0 -29
- package/dist-engine-src/src/sql2/bind/mod.rs +0 -12
- package/dist-engine-src/src/sql2/bind/public_udf.rs +0 -306
- package/dist-engine-src/src/sql2/bind/read.rs +0 -65
- package/dist-engine-src/src/sql2/bind/statement.rs +0 -2236
- package/dist-engine-src/src/sql2/bind/table.rs +0 -273
- package/dist-engine-src/src/sql2/bind/write.rs +0 -86
- package/dist-engine-src/src/sql2/branch_scope.rs +0 -436
- package/dist-engine-src/src/sql2/catalog/capability.rs +0 -20
- package/dist-engine-src/src/sql2/catalog/entity_surface.rs +0 -296
- package/dist-engine-src/src/sql2/catalog/mod.rs +0 -15
- package/dist-engine-src/src/sql2/catalog/registry.rs +0 -556
- package/dist-engine-src/src/sql2/catalog/schema.rs +0 -88
- package/dist-engine-src/src/sql2/catalog/surface.rs +0 -41
- package/dist-engine-src/src/sql2/change_materialization.rs +0 -122
- package/dist-engine-src/src/sql2/context.rs +0 -317
- package/dist-engine-src/src/sql2/dml.rs +0 -148
- package/dist-engine-src/src/sql2/error.rs +0 -215
- package/dist-engine-src/src/sql2/exec/bound_public_write.rs +0 -1593
- package/dist-engine-src/src/sql2/exec/datafusion.rs +0 -5266
- package/dist-engine-src/src/sql2/exec/fast_write.rs +0 -82
- package/dist-engine-src/src/sql2/exec/mod.rs +0 -24
- package/dist-engine-src/src/sql2/exec/write.rs +0 -661
- package/dist-engine-src/src/sql2/filesystem_planner.rs +0 -1485
- 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_route.rs +0 -661
- package/dist-engine-src/src/sql2/mod.rs +0 -52
- package/dist-engine-src/src/sql2/optimize/datafusion.rs +0 -1
- package/dist-engine-src/src/sql2/optimize/mod.rs +0 -2
- package/dist-engine-src/src/sql2/optimize/simple_write.rs +0 -116
- package/dist-engine-src/src/sql2/parse/mod.rs +0 -69
- package/dist-engine-src/src/sql2/parse/normalize.rs +0 -1
- package/dist-engine-src/src/sql2/plan/branch_scope.rs +0 -24
- package/dist-engine-src/src/sql2/plan/mod.rs +0 -5
- package/dist-engine-src/src/sql2/plan/predicate.rs +0 -22
- package/dist-engine-src/src/sql2/plan/write.rs +0 -147
- package/dist-engine-src/src/sql2/predicate_typecheck.rs +0 -504
- package/dist-engine-src/src/sql2/providers/branch.rs +0 -1206
- package/dist-engine-src/src/sql2/providers/change.rs +0 -445
- package/dist-engine-src/src/sql2/providers/directory.rs +0 -2422
- package/dist-engine-src/src/sql2/providers/directory_history.rs +0 -645
- package/dist-engine-src/src/sql2/providers/entity.rs +0 -1484
- package/dist-engine-src/src/sql2/providers/entity_history.rs +0 -452
- package/dist-engine-src/src/sql2/providers/file.rs +0 -3686
- package/dist-engine-src/src/sql2/providers/file_history.rs +0 -924
- package/dist-engine-src/src/sql2/providers/history.rs +0 -426
- package/dist-engine-src/src/sql2/providers/lix_state.rs +0 -2542
- package/dist-engine-src/src/sql2/providers/mod.rs +0 -508
- 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 -83
- package/dist-engine-src/src/sql2/storage/constraints.rs +0 -1
- package/dist-engine-src/src/sql2/storage/mod.rs +0 -1
- package/dist-engine-src/src/sql2/test_support/differential.rs +0 -712
- package/dist-engine-src/src/sql2/test_support/generators.rs +0 -354
- package/dist-engine-src/src/sql2/test_support/mod.rs +0 -2
- package/dist-engine-src/src/sql2/udfs/common.rs +0 -295
- package/dist-engine-src/src/sql2/udfs/lix_active_branch_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 -86
- package/dist-engine-src/src/sql2/write_normalization.rs +0 -368
- package/dist-engine-src/src/storage/conformance.rs +0 -399
- package/dist-engine-src/src/storage/context.rs +0 -620
- package/dist-engine-src/src/storage/mod.rs +0 -52
- package/dist-engine-src/src/storage/point.rs +0 -440
- package/dist-engine-src/src/storage/read_scope.rs +0 -67
- package/dist-engine-src/src/storage/reader.rs +0 -867
- package/dist-engine-src/src/storage/scan.rs +0 -784
- package/dist-engine-src/src/storage/spaces.rs +0 -236
- package/dist-engine-src/src/storage/stats.rs +0 -80
- package/dist-engine-src/src/storage/write_set.rs +0 -962
- package/dist-engine-src/src/storage_bench.rs +0 -171
- package/dist-engine-src/src/test_support.rs +0 -450
- package/dist-engine-src/src/tracked_state/bench_support.rs +0 -394
- package/dist-engine-src/src/tracked_state/codec.rs +0 -1183
- package/dist-engine-src/src/tracked_state/commit_root_rebuild.rs +0 -358
- package/dist-engine-src/src/tracked_state/context.rs +0 -2801
- package/dist-engine-src/src/tracked_state/diff.rs +0 -2140
- package/dist-engine-src/src/tracked_state/merge.rs +0 -478
- package/dist-engine-src/src/tracked_state/mod.rs +0 -35
- package/dist-engine-src/src/tracked_state/row_materialization.rs +0 -275
- package/dist-engine-src/src/tracked_state/storage.rs +0 -427
- package/dist-engine-src/src/tracked_state/tree.rs +0 -3063
- package/dist-engine-src/src/tracked_state/types.rs +0 -238
- package/dist-engine-src/src/transaction/bench_support.rs +0 -407
- package/dist-engine-src/src/transaction/commit.rs +0 -1592
- package/dist-engine-src/src/transaction/context.rs +0 -1653
- package/dist-engine-src/src/transaction/mod.rs +0 -24
- package/dist-engine-src/src/transaction/normalization.rs +0 -877
- package/dist-engine-src/src/transaction/prep.rs +0 -37
- package/dist-engine-src/src/transaction/schema_resolver.rs +0 -163
- package/dist-engine-src/src/transaction/staging.rs +0 -1525
- package/dist-engine-src/src/transaction/types.rs +0 -403
- package/dist-engine-src/src/transaction/validation.rs +0 -5766
- package/dist-engine-src/src/untracked_state/codec.rs +0 -615
- 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 -898
- package/dist-engine-src/src/untracked_state/types.rs +0 -146
- package/dist-engine-src/src/wasm/mod.rs +0 -60
|
@@ -1,681 +0,0 @@
|
|
|
1
|
-
use std::sync::Arc;
|
|
2
|
-
|
|
3
|
-
use crate::functions::FunctionContext;
|
|
4
|
-
use crate::sql2;
|
|
5
|
-
use crate::storage::{StorageBackend, StorageReadOptions, StorageWriteOptions, StorageWriteSet};
|
|
6
|
-
use crate::transaction::{begin_commit_boundary, commit_at_boundary};
|
|
7
|
-
use crate::{LixError, LixNotice, SqlQueryResult, Value};
|
|
8
|
-
|
|
9
|
-
use super::context::{SessionContext, SessionSqlExecutionContext, SessionWriteAccess};
|
|
10
|
-
use super::transaction::SessionTransaction;
|
|
11
|
-
|
|
12
|
-
/// Result of executing one SQL statement through engine.
|
|
13
|
-
///
|
|
14
|
-
/// Column names live once at the result-set level. Individual rows only own
|
|
15
|
-
/// values, which keeps the public API row-oriented without copying schema
|
|
16
|
-
/// metadata into every row.
|
|
17
|
-
#[derive(Debug, Clone, PartialEq)]
|
|
18
|
-
pub struct ExecuteResult {
|
|
19
|
-
columns: Vec<String>,
|
|
20
|
-
rows: Vec<Row>,
|
|
21
|
-
rows_affected: u64,
|
|
22
|
-
notices: Vec<LixNotice>,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
impl ExecuteResult {
|
|
26
|
-
fn from_sql_query_result(result: SqlQueryResult) -> Self {
|
|
27
|
-
Self {
|
|
28
|
-
columns: result.columns,
|
|
29
|
-
rows: Vec::new(),
|
|
30
|
-
rows_affected: 0,
|
|
31
|
-
notices: result.notices,
|
|
32
|
-
}
|
|
33
|
-
.with_rows(result.rows)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
pub fn from_rows_affected(rows_affected: u64) -> Self {
|
|
37
|
-
Self {
|
|
38
|
-
columns: Vec::new(),
|
|
39
|
-
rows: Vec::new(),
|
|
40
|
-
rows_affected,
|
|
41
|
-
notices: Vec::new(),
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
pub fn from_rows(columns: Vec<String>, rows: Vec<Vec<Value>>) -> Self {
|
|
46
|
-
Self {
|
|
47
|
-
columns,
|
|
48
|
-
rows: Vec::new(),
|
|
49
|
-
rows_affected: 0,
|
|
50
|
-
notices: Vec::new(),
|
|
51
|
-
}
|
|
52
|
-
.with_rows(rows)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
fn with_rows(mut self, rows: Vec<Vec<Value>>) -> Self {
|
|
56
|
-
let columns = Arc::<[String]>::from(self.columns.clone().into_boxed_slice());
|
|
57
|
-
self.rows = rows
|
|
58
|
-
.into_iter()
|
|
59
|
-
.map(|values| Row {
|
|
60
|
-
columns: Arc::clone(&columns),
|
|
61
|
-
values,
|
|
62
|
-
})
|
|
63
|
-
.collect();
|
|
64
|
-
self
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/// Returns the result-set column names in row value order.
|
|
68
|
-
pub fn columns(&self) -> &[String] {
|
|
69
|
-
&self.columns
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/// Returns the owned rows. Use `iter()` for name-based access.
|
|
73
|
-
pub fn rows(&self) -> &[Row] {
|
|
74
|
-
&self.rows
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/// Iterates rows with borrowed access to the shared column metadata.
|
|
78
|
-
pub fn iter(&self) -> impl Iterator<Item = RowRef<'_>> {
|
|
79
|
-
self.rows.iter().map(|row| RowRef {
|
|
80
|
-
columns: self.columns.as_slice(),
|
|
81
|
-
values: row.values.as_slice(),
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/// Returns the number of rows in this result set.
|
|
86
|
-
pub fn len(&self) -> usize {
|
|
87
|
-
self.rows.len()
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/// Returns true when this result set has no rows.
|
|
91
|
-
pub fn is_empty(&self) -> bool {
|
|
92
|
-
self.rows.is_empty()
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/// Returns the number of rows affected by a mutation statement.
|
|
96
|
-
pub fn rows_affected(&self) -> u64 {
|
|
97
|
-
self.rows_affected
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/// Returns non-fatal diagnostics produced while executing the statement.
|
|
101
|
-
pub fn notices(&self) -> &[LixNotice] {
|
|
102
|
-
&self.notices
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/// Looks up the value for `column_name` on an owned row from this set.
|
|
106
|
-
pub fn get<'a>(&self, row: &'a Row, column_name: &str) -> Option<&'a Value> {
|
|
107
|
-
let index = self.column_index(column_name)?;
|
|
108
|
-
row.get_index(index)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/// Returns the index for a column name.
|
|
112
|
-
pub fn column_index(&self, column_name: &str) -> Option<usize> {
|
|
113
|
-
self.columns.iter().position(|column| column == column_name)
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/// One owned row returned by a query.
|
|
118
|
-
#[derive(Debug, Clone, PartialEq)]
|
|
119
|
-
pub struct Row {
|
|
120
|
-
columns: Arc<[String]>,
|
|
121
|
-
values: Vec<Value>,
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
impl Row {
|
|
125
|
-
/// Returns the values in result-set column order.
|
|
126
|
-
pub fn values(&self) -> &[Value] {
|
|
127
|
-
&self.values
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/// Returns the value at `index`.
|
|
131
|
-
pub fn get_index(&self, index: usize) -> Option<&Value> {
|
|
132
|
-
self.values.get(index)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/// Returns the raw value for `column_name`, or an error when the column is absent.
|
|
136
|
-
pub fn value(&self, column_name: &str) -> Result<&Value, LixError> {
|
|
137
|
-
let index = self.column_index(column_name)?;
|
|
138
|
-
self.values.get(index).ok_or_else(|| {
|
|
139
|
-
LixError::new(
|
|
140
|
-
LixError::CODE_COLUMN_NOT_FOUND,
|
|
141
|
-
format!(
|
|
142
|
-
"column '{}' points past row width {}; available columns: {}",
|
|
143
|
-
column_name,
|
|
144
|
-
self.values.len(),
|
|
145
|
-
self.available_columns()
|
|
146
|
-
),
|
|
147
|
-
)
|
|
148
|
-
})
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/// Converts the named column to a native Rust value.
|
|
152
|
-
pub fn get<T>(&self, column_name: &str) -> Result<T, LixError>
|
|
153
|
-
where
|
|
154
|
-
T: TryFromValue,
|
|
155
|
-
{
|
|
156
|
-
T::try_from_value(self.value(column_name)?)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
fn column_index(&self, column_name: &str) -> Result<usize, LixError> {
|
|
160
|
-
self.columns
|
|
161
|
-
.iter()
|
|
162
|
-
.position(|column| column == column_name)
|
|
163
|
-
.ok_or_else(|| {
|
|
164
|
-
LixError::new(
|
|
165
|
-
LixError::CODE_COLUMN_NOT_FOUND,
|
|
166
|
-
format!(
|
|
167
|
-
"column '{}' does not exist; available columns: {}",
|
|
168
|
-
column_name,
|
|
169
|
-
self.available_columns()
|
|
170
|
-
),
|
|
171
|
-
)
|
|
172
|
-
})
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
fn available_columns(&self) -> String {
|
|
176
|
-
if self.columns.is_empty() {
|
|
177
|
-
"<none>".to_string()
|
|
178
|
-
} else {
|
|
179
|
-
self.columns.join(", ")
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
pub trait TryFromValue: Sized {
|
|
185
|
-
fn try_from_value(value: &Value) -> Result<Self, LixError>;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
impl TryFromValue for Value {
|
|
189
|
-
fn try_from_value(value: &Value) -> Result<Self, LixError> {
|
|
190
|
-
Ok(value.clone())
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
impl TryFromValue for String {
|
|
195
|
-
fn try_from_value(value: &Value) -> Result<Self, LixError> {
|
|
196
|
-
match value {
|
|
197
|
-
Value::Text(value) => Ok(value.clone()),
|
|
198
|
-
other => Err(value_type_error("text", other)),
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
impl TryFromValue for bool {
|
|
204
|
-
fn try_from_value(value: &Value) -> Result<Self, LixError> {
|
|
205
|
-
match value {
|
|
206
|
-
Value::Boolean(value) => Ok(*value),
|
|
207
|
-
other => Err(value_type_error("boolean", other)),
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
impl TryFromValue for i64 {
|
|
213
|
-
fn try_from_value(value: &Value) -> Result<Self, LixError> {
|
|
214
|
-
match value {
|
|
215
|
-
Value::Integer(value) => Ok(*value),
|
|
216
|
-
other => Err(value_type_error("integer", other)),
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
impl TryFromValue for f64 {
|
|
222
|
-
fn try_from_value(value: &Value) -> Result<Self, LixError> {
|
|
223
|
-
match value {
|
|
224
|
-
Value::Real(value) => Ok(*value),
|
|
225
|
-
other => Err(value_type_error("real", other)),
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
impl TryFromValue for serde_json::Value {
|
|
231
|
-
fn try_from_value(value: &Value) -> Result<Self, LixError> {
|
|
232
|
-
match value {
|
|
233
|
-
Value::Json(value) => Ok(value.clone()),
|
|
234
|
-
other => Err(value_type_error("json", other)),
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
impl TryFromValue for Vec<u8> {
|
|
240
|
-
fn try_from_value(value: &Value) -> Result<Self, LixError> {
|
|
241
|
-
match value {
|
|
242
|
-
Value::Blob(value) => Ok(value.clone()),
|
|
243
|
-
other => Err(value_type_error("blob", other)),
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
fn value_type_error(expected: &str, actual: &Value) -> LixError {
|
|
249
|
-
LixError::new(
|
|
250
|
-
"LIX_ERROR_VALUE_TYPE",
|
|
251
|
-
format!("expected {expected} value, got {actual:?}"),
|
|
252
|
-
)
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/// Zero-copy row view with access to the result-set column names.
|
|
256
|
-
///
|
|
257
|
-
/// This is the ergonomic path for callers that want `row.get("column")`
|
|
258
|
-
/// without storing column metadata on every owned row.
|
|
259
|
-
#[derive(Debug, Clone, Copy)]
|
|
260
|
-
pub struct RowRef<'a> {
|
|
261
|
-
columns: &'a [String],
|
|
262
|
-
values: &'a [Value],
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
impl RowRef<'_> {
|
|
266
|
-
/// Returns the result-set column names in row value order.
|
|
267
|
-
pub fn columns(&self) -> &[String] {
|
|
268
|
-
self.columns
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/// Returns the row values in result-set column order.
|
|
272
|
-
pub fn values(&self) -> &[Value] {
|
|
273
|
-
self.values
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/// Returns the value for `column_name`.
|
|
277
|
-
pub fn get(&self, column_name: &str) -> Option<&Value> {
|
|
278
|
-
let index = self
|
|
279
|
-
.columns
|
|
280
|
-
.iter()
|
|
281
|
-
.position(|column| column == column_name)?;
|
|
282
|
-
self.values.get(index)
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/// Returns the value at `index`.
|
|
286
|
-
pub fn get_index(&self, index: usize) -> Option<&Value> {
|
|
287
|
-
self.values.get(index)
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
impl<B> SessionContext<B>
|
|
292
|
-
where
|
|
293
|
-
B: StorageBackend + Clone + Send + Sync + 'static,
|
|
294
|
-
for<'backend> B::Read<'backend>: Clone + Send + Sync + 'static,
|
|
295
|
-
for<'backend> B::Write<'backend>: Send,
|
|
296
|
-
{
|
|
297
|
-
/// Executes one DataFusion SQL statement against this Lix session.
|
|
298
|
-
///
|
|
299
|
-
/// The SQL dialect is DataFusion SQL, not SQLite SQL. Positional
|
|
300
|
-
/// placeholders use `?` or `$1`, `$2`, and so on. SQLite-specific catalog tables
|
|
301
|
-
/// and transaction statements such as `sqlite_master`, `BEGIN`, and
|
|
302
|
-
/// `COMMIT` are not part of this contract; use `information_schema` for
|
|
303
|
-
/// catalog inspection. Lix owns transaction boundaries for each statement.
|
|
304
|
-
pub async fn execute(&self, sql: &str, params: &[Value]) -> Result<ExecuteResult, LixError> {
|
|
305
|
-
self.ensure_open()?;
|
|
306
|
-
let statement = sql2::parse_statement(sql)?;
|
|
307
|
-
if sql2::bind_statement_route(&statement)? == sql2::BoundStatementRoute::Write {
|
|
308
|
-
let write_access = self.begin_session_write_access().await?;
|
|
309
|
-
let sql_for_error = sql.to_string();
|
|
310
|
-
let params = params.to_vec();
|
|
311
|
-
return self
|
|
312
|
-
.with_write_transaction_reserved(write_access, |transaction| {
|
|
313
|
-
Box::pin(async move {
|
|
314
|
-
// Re-plan against the transaction-backed write
|
|
315
|
-
// session so provider hooks read and stage through the
|
|
316
|
-
// transaction-owned SQL write context.
|
|
317
|
-
transaction.prepare_sql_visible_schemas().await?;
|
|
318
|
-
let tx_plan =
|
|
319
|
-
sql2::create_write_logical_plan_from_parsed(transaction, statement)
|
|
320
|
-
.await?;
|
|
321
|
-
let affected_rows =
|
|
322
|
-
sql2::execute_write_logical_plan(transaction, tx_plan, ¶ms).await?;
|
|
323
|
-
Ok(ExecuteResult::from_rows_affected(affected_rows))
|
|
324
|
-
})
|
|
325
|
-
})
|
|
326
|
-
.await
|
|
327
|
-
.map_err(|error| normalize_sql_surface_error(error, &sql_for_error));
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
let runtime_write_access = if sql2::statement_has_durable_runtime_function(&statement) {
|
|
331
|
-
Some(self.begin_session_write_access().await?)
|
|
332
|
-
} else {
|
|
333
|
-
None
|
|
334
|
-
};
|
|
335
|
-
let _operation_guard = if runtime_write_access.is_some() {
|
|
336
|
-
None
|
|
337
|
-
} else {
|
|
338
|
-
Some(self.begin_session_operation()?)
|
|
339
|
-
};
|
|
340
|
-
let read_scope = self.storage.begin_read(StorageReadOptions::default())?;
|
|
341
|
-
let read_result = async {
|
|
342
|
-
let mut read_store = read_scope.store();
|
|
343
|
-
let live_state: Arc<dyn crate::live_state::LiveStateReader> =
|
|
344
|
-
Arc::new(self.live_state.reader(read_store.clone()));
|
|
345
|
-
let runtime_functions = FunctionContext::prepare(live_state.as_ref()).await?;
|
|
346
|
-
let functions = runtime_functions.provider();
|
|
347
|
-
let active_branch_id = self.active_branch_id_from_reader(&mut read_store).await?;
|
|
348
|
-
let visible_schemas = self
|
|
349
|
-
.catalog_context
|
|
350
|
-
.schema_jsons_for_sql_read_planning(live_state.as_ref(), &active_branch_id)
|
|
351
|
-
.await?;
|
|
352
|
-
let ctx = SessionSqlExecutionContext {
|
|
353
|
-
active_branch_id: &active_branch_id,
|
|
354
|
-
read_store,
|
|
355
|
-
live_state: Arc::clone(&self.live_state),
|
|
356
|
-
binary_cas: Arc::clone(&self.binary_cas),
|
|
357
|
-
branch_ctx: Arc::clone(&self.branch_ctx),
|
|
358
|
-
visible_schemas,
|
|
359
|
-
functions: functions.clone(),
|
|
360
|
-
};
|
|
361
|
-
|
|
362
|
-
let plan = sql2::create_logical_plan_from_parsed(&ctx, sql, statement).await?;
|
|
363
|
-
let result = sql2::execute_logical_plan(plan, params).await?;
|
|
364
|
-
drop(ctx);
|
|
365
|
-
drop(live_state);
|
|
366
|
-
Ok::<_, LixError>((runtime_functions, result))
|
|
367
|
-
};
|
|
368
|
-
let (runtime_functions, result) = match read_result.await {
|
|
369
|
-
Ok(result) => {
|
|
370
|
-
read_scope.close()?;
|
|
371
|
-
result
|
|
372
|
-
}
|
|
373
|
-
Err(error) => {
|
|
374
|
-
let _ = read_scope.close();
|
|
375
|
-
return Err(normalize_sql_surface_error(error, sql));
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
self.persist_runtime_functions_if_needed(&runtime_functions, runtime_write_access.as_ref())
|
|
379
|
-
.await?;
|
|
380
|
-
Ok(ExecuteResult::from_sql_query_result(result))
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
#[cfg(test)]
|
|
384
|
-
pub(crate) async fn execute_with_write_executor_mode(
|
|
385
|
-
&self,
|
|
386
|
-
sql: &str,
|
|
387
|
-
params: &[Value],
|
|
388
|
-
mode: sql2::WriteExecutorMode,
|
|
389
|
-
) -> Result<ExecuteResult, LixError> {
|
|
390
|
-
self.ensure_open()?;
|
|
391
|
-
let statement = sql2::parse_statement(sql)?;
|
|
392
|
-
if sql2::bind_statement_route(&statement)? == sql2::BoundStatementRoute::Write {
|
|
393
|
-
let write_access = self.begin_session_write_access().await?;
|
|
394
|
-
let sql_for_error = sql.to_string();
|
|
395
|
-
let params = params.to_vec();
|
|
396
|
-
return self
|
|
397
|
-
.with_write_transaction_reserved(write_access, |transaction| {
|
|
398
|
-
Box::pin(async move {
|
|
399
|
-
transaction.prepare_sql_visible_schemas().await?;
|
|
400
|
-
let tx_plan =
|
|
401
|
-
sql2::create_write_logical_plan_from_parsed(transaction, statement)
|
|
402
|
-
.await?;
|
|
403
|
-
let affected_rows = sql2::execute_write_logical_plan_with_mode(
|
|
404
|
-
transaction,
|
|
405
|
-
tx_plan,
|
|
406
|
-
¶ms,
|
|
407
|
-
mode,
|
|
408
|
-
)
|
|
409
|
-
.await?;
|
|
410
|
-
Ok(ExecuteResult::from_rows_affected(affected_rows))
|
|
411
|
-
})
|
|
412
|
-
})
|
|
413
|
-
.await
|
|
414
|
-
.map_err(|error| normalize_sql_surface_error(error, &sql_for_error));
|
|
415
|
-
}
|
|
416
|
-
self.execute(sql, params).await
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/// Persists execution-scoped runtime function state after a successful read.
|
|
420
|
-
///
|
|
421
|
-
/// Reads do not otherwise own a write transaction, but SQL functions such as
|
|
422
|
-
/// `lix_uuid_v7()` can still advance runtime state. Persisting happens only
|
|
423
|
-
/// after successful execution so failed reads do not consume durable
|
|
424
|
-
/// sequence state.
|
|
425
|
-
async fn persist_runtime_functions_if_needed(
|
|
426
|
-
&self,
|
|
427
|
-
runtime_functions: &FunctionContext,
|
|
428
|
-
runtime_write_access: Option<&SessionWriteAccess>,
|
|
429
|
-
) -> Result<(), LixError> {
|
|
430
|
-
let mut writes = StorageWriteSet::new();
|
|
431
|
-
runtime_functions
|
|
432
|
-
.stage_persist_if_needed(&mut writes)
|
|
433
|
-
.await?;
|
|
434
|
-
if writes.is_empty() {
|
|
435
|
-
return Ok(());
|
|
436
|
-
}
|
|
437
|
-
if runtime_write_access.is_none() {
|
|
438
|
-
return Err(LixError::new(
|
|
439
|
-
LixError::CODE_INTERNAL_ERROR,
|
|
440
|
-
"runtime function state changed without reserved write access",
|
|
441
|
-
));
|
|
442
|
-
}
|
|
443
|
-
let commit_boundary = self.transaction_commit_boundary();
|
|
444
|
-
let _commit_guard = begin_commit_boundary(Some(&commit_boundary));
|
|
445
|
-
commit_at_boundary(Some(&commit_boundary), || {
|
|
446
|
-
self.storage
|
|
447
|
-
.commit_write_set(writes, StorageWriteOptions::default())?;
|
|
448
|
-
Ok(())
|
|
449
|
-
})?;
|
|
450
|
-
Ok(())
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
impl<B> SessionTransaction<B>
|
|
455
|
-
where
|
|
456
|
-
B: StorageBackend + Clone + Send + Sync + 'static,
|
|
457
|
-
for<'backend> B::Read<'backend>: Clone + Send + Sync + 'static,
|
|
458
|
-
for<'backend> B::Write<'backend>: Send,
|
|
459
|
-
{
|
|
460
|
-
/// Executes one SQL statement inside this transaction.
|
|
461
|
-
///
|
|
462
|
-
/// Write statements are staged until `commit()`. Read statements use the
|
|
463
|
-
/// transaction overlay, so they can observe writes staged by earlier calls
|
|
464
|
-
/// on this transaction handle.
|
|
465
|
-
pub async fn execute(
|
|
466
|
-
&mut self,
|
|
467
|
-
sql: &str,
|
|
468
|
-
params: &[Value],
|
|
469
|
-
) -> Result<ExecuteResult, LixError> {
|
|
470
|
-
let _operation_guard = self.begin_session_operation()?;
|
|
471
|
-
let statement = sql2::parse_statement(sql)?;
|
|
472
|
-
let transaction = self.transaction_mut()?;
|
|
473
|
-
match sql2::bind_statement_route(&statement)? {
|
|
474
|
-
sql2::BoundStatementRoute::Write => {
|
|
475
|
-
execute_transaction_write_auto(transaction, statement, params)
|
|
476
|
-
.await
|
|
477
|
-
.map_err(|error| normalize_sql_surface_error(error, sql))
|
|
478
|
-
}
|
|
479
|
-
sql2::BoundStatementRoute::Read => {
|
|
480
|
-
let read_ctx = transaction.sql_read_execution_context().await?;
|
|
481
|
-
let read_result = async {
|
|
482
|
-
let plan = sql2::create_transaction_read_logical_plan_from_parsed(
|
|
483
|
-
&read_ctx,
|
|
484
|
-
transaction,
|
|
485
|
-
sql,
|
|
486
|
-
statement,
|
|
487
|
-
)
|
|
488
|
-
.await?;
|
|
489
|
-
sql2::execute_logical_plan(plan, params).await
|
|
490
|
-
}
|
|
491
|
-
.await;
|
|
492
|
-
let close_result = read_ctx.close();
|
|
493
|
-
let result = match read_result {
|
|
494
|
-
Ok(result) => {
|
|
495
|
-
close_result?;
|
|
496
|
-
result
|
|
497
|
-
}
|
|
498
|
-
Err(error) => {
|
|
499
|
-
let _ = close_result;
|
|
500
|
-
return Err(normalize_sql_surface_error(error, sql));
|
|
501
|
-
}
|
|
502
|
-
};
|
|
503
|
-
Ok(ExecuteResult::from_sql_query_result(result))
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
#[cfg(test)]
|
|
509
|
-
pub(crate) async fn execute_with_write_executor_mode(
|
|
510
|
-
&mut self,
|
|
511
|
-
sql: &str,
|
|
512
|
-
params: &[Value],
|
|
513
|
-
mode: sql2::WriteExecutorMode,
|
|
514
|
-
) -> Result<ExecuteResult, LixError> {
|
|
515
|
-
let _operation_guard = self.begin_session_operation()?;
|
|
516
|
-
let statement = sql2::parse_statement(sql)?;
|
|
517
|
-
let transaction = self.transaction_mut()?;
|
|
518
|
-
match sql2::bind_statement_route(&statement)? {
|
|
519
|
-
sql2::BoundStatementRoute::Write => {
|
|
520
|
-
execute_transaction_write_with_mode(transaction, statement, params, mode)
|
|
521
|
-
.await
|
|
522
|
-
.map_err(|error| normalize_sql_surface_error(error, sql))
|
|
523
|
-
}
|
|
524
|
-
sql2::BoundStatementRoute::Read => self.execute(sql, params).await,
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
#[cfg(test)]
|
|
529
|
-
pub(crate) async fn execute_with_write_executor_mode_and_trace(
|
|
530
|
-
&mut self,
|
|
531
|
-
sql: &str,
|
|
532
|
-
params: &[Value],
|
|
533
|
-
mode: sql2::WriteExecutorMode,
|
|
534
|
-
) -> Result<(ExecuteResult, Option<sql2::WriteExecutorPath>), LixError> {
|
|
535
|
-
let _operation_guard = self.begin_session_operation()?;
|
|
536
|
-
let statement = sql2::parse_statement(sql)?;
|
|
537
|
-
let transaction = self.transaction_mut()?;
|
|
538
|
-
match sql2::bind_statement_route(&statement)? {
|
|
539
|
-
sql2::BoundStatementRoute::Write => {
|
|
540
|
-
execute_transaction_write_with_mode_and_trace(transaction, statement, params, mode)
|
|
541
|
-
.await
|
|
542
|
-
.map_err(|error| normalize_sql_surface_error(error, sql))
|
|
543
|
-
}
|
|
544
|
-
sql2::BoundStatementRoute::Read => {
|
|
545
|
-
self.execute(sql, params).await.map(|result| (result, None))
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
#[cfg(test)]
|
|
551
|
-
pub(crate) async fn scan_live_state_for_test(
|
|
552
|
-
&mut self,
|
|
553
|
-
request: &crate::live_state::LiveStateScanRequest,
|
|
554
|
-
) -> Result<Vec<crate::live_state::MaterializedLiveStateRow>, LixError> {
|
|
555
|
-
let _operation_guard = self.begin_session_operation()?;
|
|
556
|
-
let transaction = self.transaction_mut()?;
|
|
557
|
-
<crate::transaction::Transaction<B> as sql2::SqlWriteExecutionContext>::scan_live_state(
|
|
558
|
-
transaction,
|
|
559
|
-
request,
|
|
560
|
-
)
|
|
561
|
-
.await
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
async fn execute_transaction_write_auto<B>(
|
|
566
|
-
transaction: &mut crate::transaction::Transaction<B>,
|
|
567
|
-
statement: datafusion::sql::parser::Statement,
|
|
568
|
-
params: &[Value],
|
|
569
|
-
) -> Result<ExecuteResult, LixError>
|
|
570
|
-
where
|
|
571
|
-
B: StorageBackend + Clone + Send + Sync + 'static,
|
|
572
|
-
for<'backend> B::Read<'backend>: Clone + Send + Sync + 'static,
|
|
573
|
-
for<'backend> B::Write<'backend>: Send,
|
|
574
|
-
{
|
|
575
|
-
transaction.prepare_sql_visible_schemas().await?;
|
|
576
|
-
let tx_plan = sql2::create_write_logical_plan_from_parsed(transaction, statement).await?;
|
|
577
|
-
let affected_rows = sql2::execute_write_logical_plan(transaction, tx_plan, params).await?;
|
|
578
|
-
Ok(ExecuteResult::from_rows_affected(affected_rows))
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
#[cfg(test)]
|
|
582
|
-
async fn execute_transaction_write_with_mode<B>(
|
|
583
|
-
transaction: &mut crate::transaction::Transaction<B>,
|
|
584
|
-
statement: datafusion::sql::parser::Statement,
|
|
585
|
-
params: &[Value],
|
|
586
|
-
mode: sql2::WriteExecutorMode,
|
|
587
|
-
) -> Result<ExecuteResult, LixError>
|
|
588
|
-
where
|
|
589
|
-
B: StorageBackend + Clone + Send + Sync + 'static,
|
|
590
|
-
for<'backend> B::Read<'backend>: Clone + Send + Sync + 'static,
|
|
591
|
-
for<'backend> B::Write<'backend>: Send,
|
|
592
|
-
{
|
|
593
|
-
transaction.prepare_sql_visible_schemas().await?;
|
|
594
|
-
let tx_plan = sql2::create_write_logical_plan_from_parsed(transaction, statement).await?;
|
|
595
|
-
let affected_rows =
|
|
596
|
-
sql2::execute_write_logical_plan_with_mode(transaction, tx_plan, params, mode).await?;
|
|
597
|
-
Ok(ExecuteResult::from_rows_affected(affected_rows))
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
#[cfg(test)]
|
|
601
|
-
async fn execute_transaction_write_with_mode_and_trace<B>(
|
|
602
|
-
transaction: &mut crate::transaction::Transaction<B>,
|
|
603
|
-
statement: datafusion::sql::parser::Statement,
|
|
604
|
-
params: &[Value],
|
|
605
|
-
mode: sql2::WriteExecutorMode,
|
|
606
|
-
) -> Result<(ExecuteResult, Option<sql2::WriteExecutorPath>), LixError>
|
|
607
|
-
where
|
|
608
|
-
B: StorageBackend + Clone + Send + Sync + 'static,
|
|
609
|
-
for<'backend> B::Read<'backend>: Clone + Send + Sync + 'static,
|
|
610
|
-
for<'backend> B::Write<'backend>: Send,
|
|
611
|
-
{
|
|
612
|
-
transaction.prepare_sql_visible_schemas().await?;
|
|
613
|
-
let tx_plan = sql2::create_write_logical_plan_from_parsed(transaction, statement).await?;
|
|
614
|
-
let (affected_rows, path) =
|
|
615
|
-
sql2::execute_write_logical_plan_with_mode_and_trace(transaction, tx_plan, params, mode)
|
|
616
|
-
.await?;
|
|
617
|
-
Ok((ExecuteResult::from_rows_affected(affected_rows), Some(path)))
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
fn normalize_sql_surface_error(error: LixError, sql: &str) -> LixError {
|
|
621
|
-
if error.code.starts_with("LIX_ERROR_PATH_") && sql_uses_public_filesystem_path_surface(sql) {
|
|
622
|
-
return LixError {
|
|
623
|
-
code: LixError::CODE_INVALID_PARAM.to_string(),
|
|
624
|
-
..error
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
if error.code == LixError::CODE_INVALID_JSON_PATH
|
|
628
|
-
&& error
|
|
629
|
-
.message
|
|
630
|
-
.to_ascii_lowercase()
|
|
631
|
-
.contains("uses variadic path segments")
|
|
632
|
-
{
|
|
633
|
-
return LixError {
|
|
634
|
-
code: LixError::CODE_INVALID_PARAM.to_string(),
|
|
635
|
-
..error
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
error
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
fn sql_uses_public_filesystem_path_surface(sql: &str) -> bool {
|
|
642
|
-
let lower = sql.to_ascii_lowercase();
|
|
643
|
-
(lower.contains("lix_file") || lower.contains("lix_directory")) && lower.contains("path")
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
#[cfg(test)]
|
|
647
|
-
mod tests {
|
|
648
|
-
use super::*;
|
|
649
|
-
|
|
650
|
-
#[test]
|
|
651
|
-
fn row_get_converts_native_values_and_value_keeps_wrapper() {
|
|
652
|
-
let result = ExecuteResult::from_rows(
|
|
653
|
-
vec!["title".to_string(), "done".to_string()],
|
|
654
|
-
vec![vec![Value::Text("Hello".to_string()), Value::Boolean(true)]],
|
|
655
|
-
);
|
|
656
|
-
let row = &result.rows()[0];
|
|
657
|
-
|
|
658
|
-
assert_eq!(row.get::<String>("title").unwrap(), "Hello");
|
|
659
|
-
assert!(row.get::<bool>("done").unwrap());
|
|
660
|
-
assert_eq!(
|
|
661
|
-
row.value("title").unwrap(),
|
|
662
|
-
&Value::Text("Hello".to_string())
|
|
663
|
-
);
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
#[test]
|
|
667
|
-
fn row_get_errors_on_missing_column_and_wrong_type() {
|
|
668
|
-
let result = ExecuteResult::from_rows(
|
|
669
|
-
vec!["title".to_string()],
|
|
670
|
-
vec![vec![Value::Text("Hello".to_string())]],
|
|
671
|
-
);
|
|
672
|
-
let row = &result.rows()[0];
|
|
673
|
-
|
|
674
|
-
let missing = row.get::<String>("missing").unwrap_err();
|
|
675
|
-
assert_eq!(missing.code, LixError::CODE_COLUMN_NOT_FOUND);
|
|
676
|
-
assert!(missing.message.contains("available columns: title"));
|
|
677
|
-
|
|
678
|
-
let wrong_type = row.get::<bool>("title").unwrap_err();
|
|
679
|
-
assert_eq!(wrong_type.code, "LIX_ERROR_VALUE_TYPE");
|
|
680
|
-
}
|
|
681
|
-
}
|