Skip to main content

Db

Generates a repository implementation from a trait definition: annotate the trait, name your methods following a small set of conventions, and the SQL (Postgres, MySQL, or SQLite — one backend, chosen at compile time) gets written for you.

Picking a backend​

Exactly one of the postgres / mysql / sqlite Cargo features must be enabled. This is a compile-time choice because SQL placeholder syntax and RETURNING availability are baked into generated queries at macro-expansion time — enabling zero or more than one is a compile error.

axumstart = { version = "...", features = ["postgres"] }

#[repository(table = "...")]​

Annotate a trait to generate:

  • a Db{TraitName} struct with a pool: DbPool field and new(pool: DbPool) -> Self,
  • impl {TraitName} for Db{TraitName}, with method bodies generated from method names.
#[repository(table = "user_stats")]
pub trait UserStatsRepository: Repository {
async fn first_by_user_id(&self, user_id: i32) -> sqlx::Result<Option<UserStatsRow>>;
async fn insert(&self, values: UserStatsValues) -> sqlx::Result<UserStatsRow>;
}

Methods with a default body are emitted as-is (no codegen applied). A method name that matches none of the patterns below is a compile error naming the method and listing the valid patterns.

Method name conventions​

See dsl for the full grammar (operators, connectors, ordering, pagination, #[transactional], and more) — this is the map:

Function typePattern
first_byfirst_by_{filter}
find_random_byfind_random_by_{filter}
find_allfind_all_by_{filter}, find_all, find_all_order_by_{col}, find_all_{bool_field}
count_bycount_by_{filter}
exists_byexists_by_{filter}
delete_bydelete_by_{filter}
set_byset_{field}_by_{filter}
insertinsert
insert_allinsert_all
insert_or_ignoreinsert_or_ignore
upsertupsert
upsert_allupsert_all
updateupdate
poolpool

Relations — belongs_to / has_one / has_many / belongs_to_many​

Declare related tables so method names can reference their columns — see relations.

#[derive(SqlxInsert)] / #[derive(SqlxUpdate)]​

The values-struct side of insert/insert_all/insert_or_ignore/upsert/upsert_all (#[derive(SqlxInsert)]) and update (#[derive(SqlxUpdate)]) — see each method's page for the exact derive mechanics and per-dialect SQL.

Combining with mockall​

Add mock to the macro to generate #[cfg_attr(test, ::mockall::automock)] on the trait:

#[repository(table = "onboarding_test", mock)]
pub trait OnboardingTestRepository: Repository { /* ... */ }