SuperAPI AI Directory

sea-orm

Coding & development

View repository

Updated 10-15 20:31

About this skill

SeaORM

ORM async on Tokio. HTTP: axum (DatabaseConnection in State). SQL compile-time / explicit queries: sqlx. Diesel: diesel. Motor: postgres. Do not mix SeaORM and sqlx in the same aggregate.

Preserve the backend (sqlx-postgres etc.) that the crate already uses. Do not introduce SeaORM if the repo is already sqlx/Diesel.

Stack

Crate Role
sea-orm Entities, queries, tx
sea-orm-migration Async Migrator
sea-orm-cli generate entity if the team already generates

Organization

migration/           # crate migrator (ou pasta do repo)
src/
  entities/          # Model, ActiveModel, Column
  db.rs              # connect, pool
  • Generated entities or hand-written — the project's flow. Do not edit generated and hand-written in the same file without a boundary.
  • Relationships in the aggregate module, not a entities.rs of 3k lines.

Non-negotiable rules

  • Pool at boot; clone in the State. No Database::connect per request.
  • Transaction on composite writes (db.transaction(|txn| async move { … })).
  • Tenancy/user_id in the filter. Consistent soft delete if the schema has it.
  • ActiveModel for mutation; not blind UPDATE of all fields if the domain is partial.
  • Errors: map DbErr → AppError (404/409). No SQL in the JSON.

Models

  • #[derive(Clone, Debug, PartialEq, DeriveEntityModel)] + enum Relation.
  • Column / Entity::find_by_id. find().filter().one/all.
  • Cursor/keyset in hot lists — not deep offset (postgres).
  • JSON: Json / JsonBinary only for unstable shape; invariants in columns.

Axum

async fn get_order(
    State(db): State<DatabaseConnection>,
    Path(id): Path<Uuid>,
) -> Result<Json<Order>, AppError> {
    let row = Order::find_by_id(id).one(&db).await?;
    // …
}
  • Handler does not build an SQL string. Services if the aggregate is fat.
  • Migrations in the deploy before the serve (rust-axum-production). auto-migrate only in dev if the repo already does it.

Anti-patterns

  • find().all() without a limit
  • God Entity with 40 eager relations
  • unwrap in DbErr
  • SeaORM + sqlx::query! in the same use case “because the generate failed”
  • Sync/diesel Connection in the SeaORM handler

Integration with other skills

  • Runtime: tokio
  • HTTP: axum
  • Raw SQL: sqlx
  • Classic ORM: diesel
  • Observability: tracing (instrument in the repository)
  • Tests: rust-unit-testing

Completion criteria

  • Pool in the State; tx in composite writes
  • Ownership/tenant filter
  • Versioned migration if the schema changed
  • DbErr mapped; no SQL in the response
  • One persistence style per aggregate