Skip to main content

keelson_sqlx/
lib.rs

1//! The sqlx backend for keelson.
2//!
3//! One crate, three drivers behind features — `psql`, `mysql`, `sqlite`
4//! — each exposing a `Pool` (and the transaction machinery via
5//! [`keelson_exec::Begin`]) that implements [`keelson_exec::Executor`]. An
6//! application constructs a pool here, in `main`, and everything above it —
7//! generated models, hooks, plain query code — talks `keelson_exec` traits
8//! and never names sqlx.
9//!
10//! Per-database drivers, not `sqlx::Any`: `Any` erases exactly what
11//! `docs/type-mappings.md` requires kept (native `uuid`/temporal/decimal
12//! parameter binds on the engines that have them).
13//!
14//! Each driver module owns two functions that make the type-mappings table
15//! executable: `bind_value` (a total map `Value` → driver parameter, per the
16//! "binds as" column) and `decode_value` (native row → `Value`, per the
17//! column-type column). The round-trip suites in `tests/` are those two
18//! functions' tests.
19//!
20//! # Where this sits
21//!
22//! The backend half of Layer 2: it implements
23//! [keelson-exec](https://docs.rs/keelson-exec)'s traits and is the only crate in keelson
24//! that links a database driver. Application code names it once, in `main`,
25//! to build a pool; everything above talks `keelson_exec` traits. The
26//! statements it runs come from a Layer 1 dialect ([keelson-psql](https://docs.rs/keelson-psql),
27//! [keelson-mysql](https://docs.rs/keelson-mysql), [keelson-sqlite](https://docs.rs/keelson-sqlite)) or
28//! from a generated model. The whole map is the [keelson](https://docs.rs/keelson) facade
29//! crate.
30#![warn(missing_docs)]
31
32#[cfg(feature = "mysql")]
33pub mod mysql;
34#[cfg(feature = "psql")]
35pub mod psql;
36#[cfg(feature = "sqlite")]
37pub mod sqlite;
38
39#[cfg(any(feature = "psql", feature = "mysql", feature = "sqlite"))]
40mod common {
41    use keelson_exec::ExecError;
42
43    /// A driver refusal while reading a column, with the column named.
44    pub(crate) fn decode_err(column: &str, e: sqlx::Error) -> ExecError {
45        ExecError::Decode {
46            column: column.to_owned(),
47            source: keelson_core::Error::other(e.to_string()),
48        }
49    }
50
51    /// A column type whose decode needs a cargo feature that is off. Unused
52    /// (and allowed dead) when every type feature is on, since the arms that
53    /// call it compile out.
54    #[allow(dead_code)]
55    pub(crate) fn need_feature(column: &str, ty: &str, feature: &str) -> ExecError {
56        ExecError::Decode {
57            column: column.to_owned(),
58            source: keelson_core::Error::other(format!(
59                "column type {ty} needs the keelson-sqlx \"{feature}\" feature"
60            )),
61        }
62    }
63
64    /// A column type this backend has no mapping for. Loud, never guessed.
65    pub(crate) fn unhandled(column: &str, ty: &str) -> ExecError {
66        ExecError::Decode {
67            column: column.to_owned(),
68            source: keelson_core::Error::other(format!("unsupported column type {ty}")),
69        }
70    }
71}