ubiquisync_sql/db/mod.rs
1//! The SQL backend abstraction: values, rows, batches, and the [`Db`] trait.
2
3mod batch;
4mod error;
5mod schema;
6mod value;
7
8pub use batch::{DbBatch, DbStatementResult, StmtId};
9pub use error::DbError;
10pub use schema::{DbColumnDescription, DbTableDescriptor, DbType};
11pub use value::{DbRow, DbValue, ValueBinder};
12
13use async_trait::async_trait;
14
15use crate::dialect::SqlDialect;
16
17/// A SQL backend: reads, one-off writes/DDL, and a factory for atomic batches.
18//
19// TODO(wasm): a Cloudflare D1 / Durable-Objects backend has `!Send` JS-Promise
20// futures; when it lands it must satisfy this `Send + Sync` bound internally
21// (wrap its handle/futures in `send_wrapper::SendWrapper`, sound on the
22// single-threaded Workers isolate) rather than relaxing the trait for every
23// target. Alternatively we can make the Send + Sync requirement conditional on
24// the build target. Deferred until that backend is built.
25#[async_trait]
26pub trait Db: Send + Sync {
27 /// The SQL dialect this backend speaks (placeholder syntax, upsert verbs,
28 /// type names). Synchronous: it's pure metadata, no I/O.
29 fn dialect(&self) -> SqlDialect;
30
31 /// Introspect a table's columns and primary key, or `None` if it does not
32 /// exist. Used for schema reconciliation *before* a batch is built.
33 async fn describe_table(&self, name: &str) -> Result<Option<DbTableDescriptor>, DbError>;
34
35 /// Execute a single statement outside any batch (autocommit). For DDL
36 /// (`CREATE TABLE`, `ALTER TABLE ... ADD COLUMN`) and one-off writes.
37 /// Returns the number of rows affected.
38 async fn exec(&self, sql: &str, params: &[DbValue]) -> Result<usize, DbError>;
39
40 /// Run a read query and return every row. Materializes the full result
41 /// set; not for unbounded scans.
42 async fn query(&self, sql: &str, params: &[DbValue]) -> Result<Vec<DbRow>, DbError>;
43
44 /// Open a fresh, empty batch. Allocation only — no transaction is started
45 /// and nothing touches the backend until [`DbBatch::commit`].
46 fn new_batch(&self) -> Box<dyn DbBatch>;
47}