rust-d1-orm 0.0.1

Query builder / ORM for Cloudflare D1, targeting wasm32-unknown-unknown
Documentation
  • Coverage
  • 0%
    0 out of 17 items documented0 out of 0 items with examples
  • Size
  • Source code size: 39.94 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 804.85 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 25s Average build duration of successful builds.
  • all releases: 24s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • maulanasdqn/rust-d1-orm
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • maulanasdqn

d1-orm

Query builder and ORM for Cloudflare D1, written in Rust, targeting wasm32-unknown-unknown.

Works with workers-rs 0.4.

Install

[dependencies]
d1-orm = "0.0.1"

Usage

Define a model

Implement D1Model on any Deserialize struct that maps to a D1 table:

use d1_orm::{D1Model, opt_js};
use serde::Deserialize;
use worker::wasm_bindgen::JsValue;

#[derive(Deserialize)]
struct UserRow {
    id: String,
    email: String,
    name: String,
    bio: Option<String>,
    created_at: String,
}

impl D1Model for UserRow {
    const TABLE: &'static str = "users";
    const COLUMNS: &'static [&'static str] = &["id", "email", "name", "bio", "created_at"];
    fn values(&self) -> Vec<JsValue> {
        vec![
            self.id.clone().into(),
            self.email.clone().into(),
            self.name.clone().into(),
            opt_js(self.bio.clone()),   // Option<T> → NULL when None
            self.created_at.clone().into(),
        ]
    }
}

CRUD

use d1_orm::{Order, Query, Set, Table};

let table = Table::<UserRow>::new(&db);

// INSERT ... RETURNING *
let user = table.insert(&row).await?;

// INSERT batch — single D1 batch() round trip
let users = table.insert_batch(&rows).await?;

// SELECT
let user  = table.find_one(Query::new().eq("id", id)).await?;
let users = table.find_all(Query::new().eq("active", true).order_by("created_at", Order::Desc).limit(50)).await?;

// UPDATE ... RETURNING *
let updated = table.update(
    Set::new().field("name", "Alice").nullable_field("bio", None::<String>),
    Query::new().eq("id", id),
).await?;

// DELETE
table.delete(Query::new().eq("id", id)).await?;

// COUNT
let n = table.count(Query::new().eq("active", true)).await?;

Query builder reference

Method SQL fragment
.eq("col", val) col = ?N
.ne("col", val) col != ?N
.gt("col", val) col > ?N
.gte("col", val) col >= ?N
.lt("col", val) col < ?N
.lte("col", val) col <= ?N
.is_null("col") col IS NULL
.is_not_null("col") col IS NOT NULL
.filter_optional("col", opt) (?N IS NULL OR col = ?N)
.filter_optional_gte("col", opt) (?N IS NULL OR col >= ?N)
.filter_optional_lte("col", opt) (?N IS NULL OR col <= ?N)
.order_by("col", Order::Desc) ORDER BY col DESC
.limit(n) LIMIT n
.offset(n) OFFSET n

filter_optional* methods accept Option<T> — pass None to skip the filter (match all rows).

Set builder reference

Method Behavior
.field("col", val) col = ?N with a non-null value
.nullable_field("col", opt) col = ?N — binds NULL when opt is None

Notes

  • All writes use RETURNING * — no second SELECT after insert/update.
  • insert_batch uses D1's batch() API — all rows in one round trip.
  • JOINs are not supported by the query builder. Drop to raw D1 for those.

License

MIT