Skip to main content

sqlx_cloudflare_d1/
lib.rs

1//! A Cloudflare D1 driver for sqlx.
2//!
3//! [`D1`] is an [`sqlx::Database`](sqlx_core::database::Database) over the
4//! Workers D1 binding, so code written against sqlx's runtime API --
5//! `sqlx::query`, `sqlx::query_as`, `#[derive(sqlx::FromRow)]`, `Executor` --
6//! runs inside a Rust Worker with the database type swapped.
7//!
8//! ```no_run
9//! use sqlx_cloudflare_d1::{D1Connection, D1};
10//!
11//! #[derive(sqlx::FromRow)]
12//! struct User {
13//!     id: i64,
14//!     name: String,
15//! }
16//!
17//! async fn user(env: &worker::Env, id: i64) -> Result<User, Box<dyn std::error::Error>> {
18//!     // One connection per request, straight from the binding.
19//!     let conn = D1Connection::from_env(env, "DB")?;
20//!
21//!     let user = sqlx::query_as::<D1, User>("SELECT id, name FROM users WHERE id = ?")
22//!         .bind(id)
23//!         .fetch_one(&conn)
24//!         .await?;
25//!
26//!     Ok(user)
27//! }
28//! ```
29//!
30//! # What D1 cannot do
31//!
32//! Each of these fails loudly rather than pretending:
33//!
34//! - **Transactions.** `begin()` returns an error; D1 cannot hold a
35//!   transaction open across calls. [`D1Connection::execute_batch`] runs several
36//!   statements atomically in one round trip instead.
37//! - **Integers beyond ±(2^53 − 1).** D1 passes values as JavaScript numbers,
38//!   so binding a wider `i64` is an encode error rather than a rounded value.
39//!   See [`types`].
40//! - **`query!` and `describe`.** sqlx's macros only know its built-in
41//!   drivers, and D1 cannot describe a statement without running it.
42//!
43//! There is no `sqlx::Pool` either -- a binding has nothing to pool -- and no
44//! `sqlx::migrate!`: apply migrations with `wrangler d1 migrations`.
45//!
46//! This crate only *runs* on `wasm32-unknown-unknown`, inside a Worker. It
47//! compiles on other targets so that docs, unit tests and `cargo check` work,
48//! but its `Send` impls lean on Workers being single-threaded: do not call it
49//! from a threaded host.
50
51mod arguments;
52mod batch;
53mod column;
54mod connection;
55mod database;
56mod error;
57mod executor;
58mod js;
59mod row;
60mod statement;
61mod transaction;
62pub mod types;
63mod value;
64
65pub use arguments::D1Arguments;
66pub use column::D1Column;
67pub use connection::{D1ConnectOptions, D1Connection};
68pub use database::D1;
69pub use row::D1Row;
70pub use statement::D1Statement;
71pub use transaction::D1TransactionManager;
72pub use value::{D1Value, D1ValueRef};
73
74// The types D1 shares with Durable Object storage, under D1's names: both are
75// SQLite behind a JavaScript API, so they are the same types underneath.
76#[doc(inline)]
77pub use sqlx_cloudflare_core::{
78    DatabaseError as D1DatabaseError, QueryResult as D1QueryResult, TypeInfo as D1TypeInfo,
79    Value as D1ArgumentValue,
80};
81
82/// What one statement of a [`D1Connection::fetch_batch`] did, and the rows it
83/// returned.
84pub type D1BatchResult = sqlx_cloudflare_core::BatchResult<D1Row>;
85
86/// An executor for D1: `&D1Connection` or `&mut D1Connection`.
87pub trait D1Executor<'c>: sqlx_core::executor::Executor<'c, Database = D1> {}
88impl<'c, T: sqlx_core::executor::Executor<'c, Database = D1>> D1Executor<'c> for T {}
89
90// NOTE: required due to the lack of lazy normalization
91sqlx_core::impl_into_arguments_for_arguments!(D1Arguments);
92sqlx_core::impl_column_index_for_row!(D1Row);
93sqlx_core::impl_column_index_for_statement!(D1Statement);
94sqlx_core::impl_acquire!(D1, D1Connection);
95sqlx_core::impl_encode_for_option!(D1);