Skip to main content

d1_orm/
lib.rs

1//! # d1-orm
2//!
3//! A lightweight ORM and SQL builder for Rust, perfectly suited for Cloudflare D1 and SQLite.
4//!
5//! ## Features
6//!
7//! - **Backend Agnostic**: Bring your own database driver or use the built-in integrations for Cloudflare D1 (via `worker` crate) and SQLite (via `rusqlite`).
8//! - **Type-Safe SQL Builder**: `define_sql!` macro for type-safe parameter binding and zero-overhead declarative SQL queries.
9//! - **Model Definition**: `define_model!` macro for defining structs, mapping database models, and generating update structs automatically.
10//! - **WASM Compatible**: Works flawlessly within WASM targets like Cloudflare Workers (non-Send environments).
11//! - **Async Trait**: Implements an ecosystem agnostic `DatabaseExecutor` trait for async database operations.
12//!
13//! ## Modules
14//!
15//! - `error`: Error types.
16//! - `types`: Core types like `DatabaseValue`.
17//! - `traits`: Core traits like `DatabaseExecutor`, `Query`.
18//! - `builder`: SQL builder functions.
19//! - `macros`: Helper macros.
20//!
21//! ## Backends
22//!
23//! - `d1`: Cloudflare D1 backend (requires `d1` feature).
24//! - `sqlite`: SQLite backend (requires `sqlite` feature).
25//!
26//! ## Example usage
27//!
28//! For a complete, runnable example using an in-memory SQL store, see [`examples/basic.rs`](https://github.com/Asutorufa/housou/blob/main/crates/d1-orm/examples/basic.rs).
29//!
30//! ```rust,no_run
31//! use d1_orm::sqlite::SqliteExecutor;
32//! use d1_orm::{build_update_sql, define_model, define_sql, DatabaseExecutor};
33//!
34//! // 1. Define your model and update struct
35//! define_model!(
36//!     /// A user in the system
37//!     User,
38//!     UserField,
39//!     UserUpdate {
40//!         id: i32 [pk],
41//!         username: String,
42//!         email: String,
43//!     }
44//! );
45//!
46//! // 2. Define your SQL queries
47//! define_sql!(
48//!     MySql
49//!     
50//!     // Simple parameterized query
51//!     GetUser { id: i32 } => "SELECT * FROM users WHERE id = ?",
52//!     
53//!     // Insert query with multiple parameters
54//!     CreateUser { username: &'a str, email: &'a str } =>
55//!         "INSERT INTO users (username, email) VALUES (?, ?)",
56//!         
57//!     // Dynamic update query using the generated UserUpdate enum
58//!     UpdateUser { updates: Vec<UserUpdate> [skip_primary_key], id: i32 } =>
59//!         build_update_sql("users", "id", &updates),
60//! );
61//!
62//! #[tokio::main]
63//! async fn main() -> Result<(), d1_orm::Error> {
64//!     // 3. Initialize the database backend (SQLite in this case)
65//!     let conn = rusqlite::Connection::open_in_memory().unwrap();
66//!     
67//!     conn.execute(
68//!         "CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT NOT NULL, email TEXT NOT NULL)",
69//!         [],
70//!     ).unwrap();
71//!     
72//!     let executor = SqliteExecutor::new(conn);
73//!
74//!     // 4. Execute queries using the type-safe builder
75//!     executor.execute(MySql::CreateUser {
76//!         username: "alice",
77//!         email: "alice@example.com",
78//!     }).await?;
79//!
80//!     // 5. Query results into strongly-typed models
81//!     let user: Option<User> = executor.query_first(MySql::GetUser { id: 1 }).await?;
82//!     println!("Found user: {:?}", user);
83//!     
84//!     // 6. Dynamic Updates programmatically crafted
85//!     executor.execute(MySql::UpdateUser {
86//!         updates: vec![UserUpdate::email("alice.new@example.com".to_string())],
87//!         id: 1,
88//!     }).await?;
89//!
90//!     Ok(())
91//! }
92//! ```
93
94pub mod builder;
95pub mod error;
96pub mod macros;
97pub mod traits;
98pub mod types;
99
100#[cfg(feature = "d1")]
101pub mod d1;
102#[cfg(feature = "sqlite")]
103pub mod sqlite;
104
105pub use builder::{build_update_sql, build_upsert_sql, UpsertConfig};
106pub use error::Error;
107pub use traits::{
108    DatabaseExecutor, FieldMeta, FieldUpdate, IntoResultCow, MigrationInfo, MigrationMeta, Query,
109    QueryExt, SqlBackend, ToParams,
110};
111pub use types::DatabaseValue;