Skip to main content

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}