rainier-database 1.0.0

Rainier ORM integration for Rainier: the connection port, models, repositories and pagination.
Documentation
rainier-database-1.0.0 has been yanked.

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] / [Database] a dyn-safe port over Rainier ORM's Executor, so a backend can live in the IoC container
[Model] an entity the framework manages, with lifecycle hooks
[Repository] / [EntityRepository] a contract to depend on, implemented once for every model
[Criteria] / [Paginated] composable 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);

# async fn run() -> rainier_support::Result<()> {
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?;
# Ok(()) }

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!].