Your first entity
Maya signs up for the writing app. Start with her User and an in-memory SQLite
database. Rent generates a Rust client from the RSL schema. Your application gets
typed builders instead of stringly table and column names.
use generated::user_create::NewUser;
let maya = client
.create_user_from(NewUser {
name: "Maya".to_owned(),
})
.id(1)
.save()
.await?;
let maya = client
.user()
.id_eq(maya.id)
.only()
.await?;
let maya = client
.update_user_one(&maya)
.name("Maya Chen")
.save_one()
.await?;
client
.delete_user_one(&maya)
.exec()
.await?;NewUser is generated from required create fields, so the compiler points out a missing required value before the query runs. For conditional or progressively assembled input, use the fluent create_user() builder instead.
only() requires exactly one row. Use only_or_none() for optional lookup and all() for a collection. Mutation builders do nothing until save(), save_one(), or exec() is awaited.
Complete example
Download this project, or copy the files below into an empty directory.
Replace RENT_REPOSITORY_URL in Cargo.toml with the URL supplied with your preview access. Use the matching Rent CLI release.
rent generate
cargo runThe project includes its database setup. Each lesson uses a small, self-contained schema. You can run it without applying the earlier lessons.
Cargo.toml
[package]
name = "rent-lesson-01-crud"
version = "0.1.0"
edition = "2024"
[workspace]
[[bin]]
name = "rent-lesson-01-crud"
path = "main.rs"
[dependencies]
rent = { git = "RENT_REPOSITORY_URL", tag = "v0.8.6", default-features = false, features = ["sqlite", "migrate", "extensions"] }
anyhow = "1.0.104"
tokio = { version = "1.53.1", features = ["full"] }rent.toml
schema = "schema.rsl"
generated = "generated"
migrations = "migrations"
[database]
dialect = "sqlite"
backends = ["sqlite"]schema.rsl
datasource db {
provider = "sqlite"
}
model User {
id BigInt @id
name String
@@map("users")
}main.rs
use anyhow::{Result, ensure};
use rent::driver::DatabasePool;
use rent::sql::Dialect;
#[allow(dead_code, unused_imports)]
#[rustfmt::skip]
#[path = "generated/mod.rs"]
mod generated;
async fn exercise() -> Result<()> {
let pool = DatabasePool::connect(Dialect::Sqlite, "sqlite::memory:").await?;
pool.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
.await?;
let client = generated::client::Client::new(pool);
let maya = client
.create_user_from(generated::user_create::NewUser {
name: "Maya".to_owned(),
})
.id(1)
.save()
.await?;
ensure!(client.user().id_eq(maya.id).only().await? == maya);
let maya = client.update_user_one(&maya).name("Maya Chen").save_one().await?;
ensure!(maya.name == "Maya Chen");
ensure!(client.delete_user_one(&maya).exec().await? == 1);
ensure!(!client.user().exist().await?);
Ok(())
}
#[tokio::main]
async fn main() -> Result<()> {
exercise().await
}
#[cfg(test)]
mod tests {
#[tokio::test]
async fn example_runs() -> anyhow::Result<()> {
super::exercise().await
}
}