commit 9526bd48f30c5b3da3d739c8a4b8296a91f9b791
parent 93790dae176aca559c1e587a0c0198e5bc1a9051
Author: triesap <triesap@radroots.dev>
Date: Mon, 19 Jan 2026 00:56:04 +0000
app-core: add sql engine types
- define sql exec outcome, params, and row types
- add sql engine and encrypted store traits
- model migration state and engine configuration structs
- add unit test for positional sql params
Diffstat:
5 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -1151,6 +1151,7 @@ version = "0.1.0"
dependencies = [
"async-trait",
"serde",
+ "serde_json",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
@@ -16,6 +16,7 @@ license = "AGPL-3.0"
leptos = { version = "0.8.5", default-features = false }
wasm-bindgen = "=0.2.100"
serde = { version = "1", features = ["derive"] }
+serde_json = "1"
[profile.release]
codegen-units = 1
diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml
@@ -12,3 +12,4 @@ crate-type = ["rlib"]
[dependencies]
async-trait = "0.1.83"
serde = { workspace = true }
+serde_json = { workspace = true }
diff --git a/crates/core/src/sql/mod.rs b/crates/core/src/sql/mod.rs
@@ -1,3 +1,16 @@
pub mod error;
+pub mod types;
pub use error::{RadrootsClientSqlError, RadrootsClientSqlErrorMessage};
+pub use types::{
+ RadrootsClientSqlEncryptedStore,
+ RadrootsClientSqlEngine,
+ RadrootsClientSqlEngineConfig,
+ RadrootsClientSqlExecOutcome,
+ RadrootsClientSqlMigrationRow,
+ RadrootsClientSqlMigrationState,
+ RadrootsClientSqlParams,
+ RadrootsClientSqlResultRow,
+ RadrootsClientSqlResult,
+ RadrootsClientSqlValue,
+};
diff --git a/crates/core/src/sql/types.rs b/crates/core/src/sql/types.rs
@@ -0,0 +1,98 @@
+use std::collections::BTreeMap;
+
+use async_trait::async_trait;
+use serde_json::Value;
+
+use crate::backup::RadrootsClientBackupSqlPayload;
+use crate::idb::RadrootsClientIdbConfig;
+
+use super::RadrootsClientSqlError;
+
+pub type RadrootsClientSqlResult<T> = Result<T, RadrootsClientSqlError>;
+pub type RadrootsClientSqlValue = Value;
+pub type RadrootsClientSqlResultRow = BTreeMap<String, Value>;
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct RadrootsClientSqlExecOutcome {
+ pub changes: i64,
+ pub last_insert_id: i64,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct RadrootsClientSqlMigrationRow {
+ pub id: i64,
+ pub name: String,
+ pub applied_at: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct RadrootsClientSqlMigrationState {
+ pub applied_names: Vec<String>,
+ pub applied_count: usize,
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum RadrootsClientSqlParams {
+ Named(BTreeMap<String, Value>),
+ Positional(Vec<Value>),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct RadrootsClientSqlEngineConfig {
+ pub store_key: String,
+ pub idb_config: RadrootsClientIdbConfig,
+ pub cipher_config: Option<RadrootsClientIdbConfig>,
+ pub sql_wasm_path: Option<String>,
+}
+
+#[async_trait(?Send)]
+pub trait RadrootsClientSqlEncryptedStore {
+ async fn load(&self) -> RadrootsClientSqlResult<Option<Vec<u8>>>;
+ async fn save(&self, bytes: &[u8]) -> RadrootsClientSqlResult<()>;
+ async fn remove(&self) -> RadrootsClientSqlResult<()>;
+}
+
+#[async_trait(?Send)]
+pub trait RadrootsClientSqlEngine {
+ async fn close(&self) -> RadrootsClientSqlResult<()>;
+ async fn purge_storage(&self) -> RadrootsClientSqlResult<()>;
+ fn exec(
+ &self,
+ sql: &str,
+ params: RadrootsClientSqlParams,
+ ) -> RadrootsClientSqlResult<RadrootsClientSqlExecOutcome>;
+ fn query(
+ &self,
+ sql: &str,
+ params: RadrootsClientSqlParams,
+ ) -> RadrootsClientSqlResult<Vec<RadrootsClientSqlResultRow>>;
+ fn export_bytes(&self) -> RadrootsClientSqlResult<Vec<u8>>;
+ async fn import_bytes(&self, bytes: &[u8]) -> RadrootsClientSqlResult<()>;
+ async fn export_backup(
+ &self,
+ ) -> RadrootsClientSqlResult<RadrootsClientBackupSqlPayload>;
+ async fn import_backup(
+ &self,
+ payload: RadrootsClientBackupSqlPayload,
+ ) -> RadrootsClientSqlResult<()>;
+ fn get_store_id(&self) -> &str;
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{RadrootsClientSqlParams, RadrootsClientSqlValue};
+
+ #[test]
+ fn params_accept_positional_values() {
+ let params = RadrootsClientSqlParams::Positional(vec![
+ RadrootsClientSqlValue::from(1),
+ RadrootsClientSqlValue::from("two"),
+ ]);
+ match params {
+ RadrootsClientSqlParams::Positional(values) => {
+ assert_eq!(values.len(), 2);
+ }
+ RadrootsClientSqlParams::Named(_) => panic!("expected positional params"),
+ }
+ }
+}