Skip to content

Repository

ModelRepository implements the Repository<T, ID> trait and provides the standard set of create, read, update, and delete operations for a model type. Obtain one from any #[derive(Model)] struct using User::repository(&mut conn).

Obtaining a repository

use rust_web_server::model::DbPool;
let pool = DbPool::from_env()?;
let mut conn = pool.get()?;
// User::repository is generated by #[derive(Model)]
let mut repo = User::repository(&mut *conn);

The repository borrows the connection mutably for its lifetime, so only one repository can be active at a time per connection.

Repository<T, ID> trait

pub trait Repository<T: Model, ID> {
fn find_by_id(&mut self, id: ID) -> Result<Option<T>, DbError>;
fn find_all(&mut self) -> Result<Vec<T>, DbError>;
fn save(&mut self, entity: &T) -> Result<T, DbError>;
fn save_all(&mut self, entities: &[T]) -> Result<Vec<T>, DbError>;
fn delete_by_id(&mut self, id: ID) -> Result<(), DbError>;
fn delete_all_by_id(&mut self, ids: &[ID]) -> Result<(), DbError>;
fn count(&mut self) -> Result<i64, DbError>;
fn exists_by_id(&mut self, id: ID) -> Result<bool, DbError>;
}

The ID type is always i64 for the built-in ModelRepository implementation.

Method reference

find_by_id

Executes SELECT * FROM users WHERE id = ? and returns the first matching row, or None if no row exists.

match repo.find_by_id(42)? {
Some(user) => println!("found: {}", user.email),
None => println!("not found"),
}

find_all

Executes SELECT * FROM users and returns every row in the table.

let all_users: Vec<User> = repo.find_all()?;

Use the Query Builder when you need filtering, ordering, or pagination.

save

Inserts or updates a single entity.

  • INSERT — when the primary key field is 0 (or Value::Null), or when #[primary_key(auto_increment)] is set and the pk is zero.
  • UPDATE — when the primary key is non-zero.

save returns the persisted entity with the primary key filled in (important for auto-increment inserts).

let mut user = User {
id: 0, // 0 triggers INSERT with auto_increment
name: "Alice".into(),
email: "alice@example.com".into(),
role: "user".into(),
active: true,
score: 0.0,
bio: None,
display_label: String::new(),
};
let saved = repo.save(&user)?;
println!("new id: {}", saved.id); // id assigned by the database

To update, set a non-zero primary key:

let updated = repo.save(&User { id: saved.id, role: "admin".into(), ..saved })?;

save_all

Calls save for each entity in the slice, returning a Vec<T> of the persisted entities.

let users = vec![
User { id: 0, name: "Bob".into(), email: "bob@example.com".into(), .. },
User { id: 0, name: "Carol".into(), email: "carol@example.com".into(), .. },
];
let saved = repo.save_all(&users)?;

delete_by_id

Executes DELETE FROM users WHERE id = ?.

repo.delete_by_id(42)?;

delete_all_by_id

Calls delete_by_id for each id in the slice (one DELETE per id).

repo.delete_all_by_id(&[1, 2, 3])?;

count

Executes SELECT COUNT(*) FROM users and returns the result as i64.

let total: i64 = repo.count()?;
println!("{total} users in database");

exists_by_id

Returns true if a row with the given id exists.

if repo.exists_by_id(99)? {
println!("user 99 exists");
}

Internally calls find_by_id and checks for Some.

Auto-increment PK retrieval

After an INSERT, the newly assigned primary key is retrieved differently per backend:

BackendMechanism
SQLitelast_insert_rowid()
PostgreSQLINSERT … RETURNING id
MySQLlast_insert_id()

In all cases, save re-fetches the inserted row via SELECT * FROM … WHERE id = ? and returns the complete, database-consistent entity.

Full CRUD example

use rust_web_server::model::{DbPool, Repository};
use rust_web_server::Model;
#[derive(Model, Debug, Clone)]
#[table(name = "users")]
pub struct User {
#[primary_key(auto_increment)]
pub id: i64,
#[column(name = "first_name")]
pub name: String,
#[column(unique)]
pub email: String,
pub role: String,
pub active: bool,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let pool = DbPool::from_env()?;
let mut conn = pool.get()?;
let mut repo = User::repository(&mut *conn);
// CREATE
let alice = repo.save(&User {
id: 0,
name: "Alice".into(),
email: "alice@example.com".into(),
role: "user".into(),
active: true,
})?;
println!("created user #{}", alice.id);
// READ
let found = repo.find_by_id(alice.id)?.expect("user exists");
println!("fetched: {} ({})", found.name, found.email);
// UPDATE
let promoted = repo.save(&User { role: "admin".into(), ..found })?;
println!("role is now: {}", promoted.role);
// EXISTS / COUNT
println!("exists: {}", repo.exists_by_id(alice.id)?);
println!("total: {}", repo.count()?);
// DELETE
repo.delete_by_id(alice.id)?;
println!("deleted");
Ok(())
}