Expand description
§d1-orm
A lightweight ORM and SQL builder for Rust, perfectly suited for Cloudflare D1 and SQLite.
§Features
- Backend Agnostic: Bring your own database driver or use the built-in integrations for Cloudflare D1 (via
workercrate) and SQLite (viarusqlite). - Type-Safe SQL Builder:
define_sql!macro for type-safe parameter binding and zero-overhead declarative SQL queries. - Model Definition:
define_model!macro for defining structs, mapping database models, and generating update structs automatically. - WASM Compatible: Works flawlessly within WASM targets like Cloudflare Workers (non-Send environments).
- Async Trait: Implements an ecosystem agnostic
DatabaseExecutortrait for async database operations.
§Modules
error: Error types.types: Core types likeDatabaseValue.traits: Core traits likeDatabaseExecutor,Query.builder: SQL builder functions.macros: Helper macros.
§Backends
d1: Cloudflare D1 backend (requiresd1feature).sqlite: SQLite backend (requiressqlitefeature).
§Example usage
For a complete, runnable example using an in-memory SQL store, see examples/basic.rs.
use d1_orm::sqlite::SqliteExecutor;
use d1_orm::{build_update_sql, define_model, define_sql, DatabaseExecutor};
// 1. Define your model and update struct
define_model!(
/// A user in the system
User,
UserField,
UserUpdate {
id: i32 [pk],
username: String,
email: String,
}
);
// 2. Define your SQL queries
define_sql!(
MySql
// Simple parameterized query
GetUser { id: i32 } => "SELECT * FROM users WHERE id = ?",
// Insert query with multiple parameters
CreateUser { username: &'a str, email: &'a str } =>
"INSERT INTO users (username, email) VALUES (?, ?)",
// Dynamic update query using the generated UserUpdate enum
UpdateUser { updates: Vec<UserUpdate> [skip_primary_key], id: i32 } =>
build_update_sql("users", "id", &updates),
);
#[tokio::main]
async fn main() -> Result<(), d1_orm::Error> {
// 3. Initialize the database backend (SQLite in this case)
let conn = rusqlite::Connection::open_in_memory().unwrap();
conn.execute(
"CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT NOT NULL, email TEXT NOT NULL)",
[],
).unwrap();
let executor = SqliteExecutor::new(conn);
// 4. Execute queries using the type-safe builder
executor.execute(MySql::CreateUser {
username: "alice",
email: "alice@example.com",
}).await?;
// 5. Query results into strongly-typed models
let user: Option<User> = executor.query_first(MySql::GetUser { id: 1 }).await?;
println!("Found user: {:?}", user);
// 6. Dynamic Updates programmatically crafted
executor.execute(MySql::UpdateUser {
updates: vec![UserUpdate::email("alice.new@example.com".to_string())],
id: 1,
}).await?;
Ok(())
}Re-exports§
pub use builder::build_update_sql;pub use builder::build_upsert_sql;pub use builder::UpsertConfig;pub use error::Error;pub use traits::DatabaseExecutor;pub use traits::FieldMeta;pub use traits::FieldUpdate;pub use traits::IntoResultCow;pub use traits::MigrationInfo;pub use traits::MigrationMeta;pub use traits::Query;pub use traits::QueryExt;pub use traits::SqlBackend;pub use traits::ToParams;pub use types::DatabaseValue;