turso_orm_driver/lib.rs
1//! Execution layer: connection pool, transactions and typed rows for Turso.
2//!
3//! This crate is the execution layer of [turso-orm]. It wraps the [`turso`]
4//! client in a small connection pool and gives the layers above a uniform
5//! way to run a [`Statement`] — on the pooled handle or inside a
6//! transaction — and to read the rows back by the Rust type they want. It
7//! owns everything that touches a live connection: opening, pooling,
8//! per-connection pragmas, transactions and savepoints, statement execution,
9//! streaming, value decoding and error classification. It deliberately does
10//! not own SQL generation, which is `turso-sql`'s job, nor entity mapping,
11//! which is `turso-orm`'s.
12//!
13//! # Design
14//!
15//! - The pool hands out connections created with `db.connect()`, one per
16//! slot, and never multiplies a slot by cloning a `turso::Connection`:
17//! clones share one engine connection and would serialise on it. A
18//! connection goes back to the idle list only when it is in autocommit
19//! mode, so a transaction that was dropped mid-way can never leak into
20//! the next borrower.
21//! - A [`Transaction`] pins one pooled connection for its whole life.
22//! Nested transactions are `SAVEPOINT`s on that same connection. Because
23//! `Drop` cannot await, rolling back a dropped transaction is deferred: a
24//! top-level one discards its connection, a nested one records its depth
25//! and the rollback runs before the parent's next statement.
26//! - Rows keep their storage class and are decoded on access through
27//! [`FromValue`], with SQLite-style leniency — integers become booleans,
28//! text parses into dates and UUIDs — so the same column can be read as
29//! whatever the caller asks for.
30//! - `turso::Error` carries only strings for most variants, so
31//! [`ErrorKind`] is derived by variant and, for MVCC conflicts, by message.
32//!
33//! # Example
34//!
35//! ```no_run
36//! use turso_orm_driver::{ConnectOptions, ConnectionTrait, Database};
37//! use turso_sql::Statement;
38//!
39//! # async fn boot() -> Result<(), turso_orm_driver::Error> {
40//! let db = Database::connect(ConnectOptions::new("app.db")).await?;
41//! db.execute_unprepared("CREATE TABLE IF NOT EXISTS t (id INTEGER PRIMARY KEY, n TEXT)").await?;
42//! let row = db.query_one(Statement::from_string("SELECT COUNT(*) AS n FROM t")).await?;
43//! let count: i64 = row.expect("one row").get("n")?;
44//! # Ok(())
45//! # }
46//! ```
47//!
48//! [turso-orm]: https://github.com/aartintelligent/turso-orm
49#![cfg_attr(docsrs, feature(doc_cfg))]
50
51mod connection;
52mod database;
53mod decode;
54mod error;
55mod executor;
56mod options;
57mod transaction;
58
59pub use connection::{ConnectionTrait, StreamTrait, TransactionTrait};
60pub use database::Database;
61pub use decode::FromValue;
62pub use error::{ConstraintKind, Error, ErrorKind, Result};
63pub use executor::{ExecResult, Row, RowStream};
64#[cfg(feature = "serverless")]
65pub use options::RemoteOptions;
66#[cfg(feature = "sync")]
67pub use options::SyncOptions;
68pub use options::{ConnectOptions, Encryption, Experimental, Source};
69pub use transaction::{Transaction, TransactionMode};
70
71/// Re-export of the underlying Turso client, so callers can reach engine
72/// types such as `turso::Value` without depending on the crate themselves.
73pub use turso;
74/// Re-export of the SQL layer, so a single dependency gives the whole
75/// query language.
76pub use turso_sql;
77pub use turso_sql::{Statement, Value};