Skip to main content

Crate rainier_database

Crate rainier_database 

Source
Expand description

§rainier-database

Rainier’s data layer, built on Rainier ORM — the multi-dialect DBAL where one #[derive(Entity)] serves SQLite, Cloudflare D1, MySQL and Postgres, and where the stack of hand-written per-engine repositories collapses to zero.

This crate adds the four things a framework needs on top of that:

Connection / Databasea dyn-safe port over Rainier ORM’s Executor, so a backend can live in the IoC container
Modelan entity the framework manages, with lifecycle hooks
Repository / EntityRepositorya contract to depend on, implemented once for every model
Criteria / Paginatedcomposable scopes and paging
ⓘ
use rainier_orm::{repo, Entity, SeaOrmExecutor, PoolConfig};
use rainier_database::{bind_executor, Criteria, Database, EntityRepository, Model, Repository};

#[derive(Entity, Clone)]
#[orm(table = "posts")]
struct Post {
    #[orm(pk, auto_increment)] id: u64,
    title: String,
    published: bool,
}
impl Model for Post {}

bind_executor!(SeaOrmExecutor);

let executor = SeaOrmExecutor::connect("sqlite::memory:", &PoolConfig::default()).await?;
let db = Database::new(executor);
let posts = EntityRepository::<Post>::new(db.clone());

// Through the repository contract…
let page = posts
    .paginate_matching(Criteria::new().where_eq("published", true), 1, 20)
    .await?;

// …or straight through Rainier ORM, since `Database` is an `Executor`.
let newest: Option<Post> = repo::query::<Post>().order_by_desc("id").first(&db).await?;

§The Executor problem, and how it is solved

Rainier ORM’s Executor uses async fn in trait and carries no Send + Sync bound — deliberately, so the same code runs in a single-threaded Cloudflare Worker over a !Send D1 binding. That makes it unusable as dyn Executor, which is exactly what a container needs to store.

Database resolves this by holding an Arc<dyn Connection> (Rainier’s dyn-safe mirror) and re-implementing Executor on top of it. The whole ORM surface therefore works against a Database unchanged — no wrapper per operation, and no gap between what Rainier ORM can do and what Rainier exposes. Register a concrete backend with bind_executor!.

Re-exports§

pub use connection::Connection;
pub use connection::Database;
pub use criteria::Constraint;
pub use criteria::Criteria;
pub use factory::Factory;
pub use factory::HasFactory;
pub use migrator::Down;
pub use migrator::Migration;
pub use migrator::Migrator;
pub use migrator::Step;
pub use model::Created;
pub use model::Creating;
pub use model::Deleted;
pub use model::Deleting;
pub use model::Model;
pub use model::Updated;
pub use model::Updating;
pub use pagination::Paginated;
pub use raw::RawQuery;
pub use relation::BelongsTo;
pub use relation::BelongsToMany;
pub use relation::HasMany;
pub use relation::HasOne;
pub use relation::PivotQuery;
pub use relation::Related;
pub use relation::RelatedCounts;
pub use relation::Relation;
pub use relation::RelationKey;
pub use repository::EntityRepository;
pub use repository::Repository;
pub use row::Cell;
pub use row::ColumnRequest;
pub use row::OwnedRow;
pub use statement::Prepared;
pub use rainier_orm;

Modules§

connection
The connection port — Connection and Database.
criteria
Composable query scopes — Criteria.
ddl
A declarative, dialect-portable schema-change language — the single way to express an incremental migration step.
factory
Test fixtures — Factory and HasFactory.
migrate
Schema migrations — an ordered list of steps applied idempotently, tracked in a _orm_migrations table, against one executor or many.
migrator
Schema migrations — the Migration contract, and the Migrator that runs and rolls them back.
model
The Model contract and its lifecycle hooks.
pagination
Paginated results — Paginated.
raw
Raw SQL, bound safely — RawQuery.
relation
Relationships — Eloquent’s hasOne, hasMany, belongsTo and belongsToMany, as values you load rather than properties that query themselves.
repo
Generic CRUD over any Entity, plus a keyset Cursor for walking large tables without holding them in memory.
repository
Repositories — the Repository contract and its generic implementation.
row
Owned row snapshots — OwnedRow, Cell and ColumnRequest.
schema
Generic DDL: turn an Entity’s metadata into CREATE TABLE + CREATE INDEX statements, rendered for any Dialect.
statement
Statement preparation — building SQL synchronously, so the futures that run it are Send.
testing
Test doubles — MemoryConnection and fake_database.

Macros§

bind_executor
Writes the Connection impl for a concrete Rainier ORM Executor.

Structs§

Blueprint
A table being created — Laravel’s Blueprint.
IndexDef
One index, described.
Query
A builder for reads (and WHERE-scoped deletes) over E. Conditions are AND-combined; use filter to add an OR group.
TableChanges
A change to a table that already exists — Laravel’s Schema::table.

Enums§

Action
What to do to rows on the other side when a referenced row goes.
ColumnKind
What a column holds.
Dialect
The SQL dialect a backend speaks. Cloudflare D1 maps to Sqlite (it is SQLite over HTTP); the executor handles the transport difference.

Traits§

Entity
A struct that maps to one table. Implemented by #[derive(Entity)]; hand impls are possible but the derive is the intended path.
Executor
A database backend. The single integration point: implement this and the generic CRUD layer works against your store unchanged.

Derive Macros§

Entity