nestrs-prisma 0.3.7

Prisma integration helpers and providers for nestrs.
Documentation

nestrs-prisma

Nest-style PrismaModule / PrismaService for nestrs: configuration, optional SQLx pooling (DATABASE_URL), and helpers that stay ORM-agnostic so you can choose how models are represented in Rust.

Docs: docs.rs/nestrs-prisma · Repo: github.com/Joshyahweh/nestrs

[dependencies]
async-trait = "0.1"
nestrs-prisma = { version = "0.3.7", features = ["sqlx", "sqlx-sqlite"] }
nestrs = "0.3.7"

When enabling sqlx, choose exactly one backend feature in your app: sqlx-sqlite, sqlx-postgres, or sqlx-mysql. If more than one is enabled (for example through workspace --all-features), the concrete driver is selected in priority order: Postgres, then MySQL, then SQLite.

The async-trait crate must be a direct dependency of any crate that invokes prisma_model!, because the generated repository trait uses #[async_trait::async_trait].

Generated type dependencies

Generated bindings can include native Rust types based on Prisma scalar/native DB type mapping. Add the crates your schema requires:

[dependencies]
chrono = { version = "0.4", features = ["clock"] } # DateTime/Timestamp/Date/Time mappings
uuid = { version = "1", features = ["v4"] }        # @db.Uuid
serde_json = "1"                                    # Json/JsonB
rust_decimal = "1"                                  # Decimal/Numeric
ipnetwork = "0.21"                                  # @db.Cidr
bit-vec = "0.6"                                     # @db.Bit/@db.VarBit

If your schema does not use a given type family, you can omit that dependency.

Run the quickstart example

There are two ways to run quickstart:

A) From this repository (maintainers/contributors)

From the nestrs workspace root:

cargo run -p nestrs-prisma --example quickstart --features "sqlx,sqlx-sqlite"

B) From your own app (crate consumers on nestrs-prisma = "0.3.7")

cargo run -p nestrs-prisma ... will not work in your app, because -p targets a package in your current workspace. Instead:

  1. Add dependency:
nestrs-prisma = { version = "0.3.7", features = ["sqlx", "sqlx-postgres"] }
nestrs = "0.3.7"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
  1. Fetch quickstart source into your app as examples/quickstart.rs (no manual copying):
mkdir -p examples
curl -fsSL "https://raw.githubusercontent.com/Joshyahweh/nestrs/v0.3.7/nestrs-prisma/examples/quickstart.rs" -o examples/quickstart.rs

Alternative (fetch from crates.io source):

cargo install cargo-download
cargo download nestrs-prisma==0.3.7 --extract
mkdir -p examples
cp nestrs-prisma-0.3.7/examples/quickstart.rs examples/quickstart.rs
  1. Run from your app root:
cargo run --example quickstart

If DATABASE_URL is not set, the example defaults to sqlite:quickstart.db. With prisma/schema.prisma present, it also generates bindings and writes src/models/prisma_generated.rs.

1. Write models in Prisma

Add a schema next to your app (convention: prisma/schema.prisma):

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  name  String
}

Use prisma migrate, prisma db push, or your own SQL migrations to apply it to the database.

2. Map rows in Rust (SQLx path, no codegen)

Enable sqlx on nestrs-prisma. Mirror columns with sqlx::FromRow and load via PrismaService::query_all_as:

#[derive(Debug, sqlx::FromRow, serde::Serialize)]
struct UserRow {
    id: i64,
    email: String,
    name: String,
}

let users: Vec<UserRow> = prisma
    .query_all_as(r#"SELECT "id", "email", "name" FROM "User""#)
    .await?;

Use PrismaService::execute for DDL/DML without a row mapper (e.g. migration scripts).

3. Declarative prisma_model! (NestJS / Prisma-shaped repository)

With sqlx enabled, you can declare a table-bound model once. The macro expands to:

  • A #[derive(sqlx::FromRow)] struct for the row shape.
  • UserWhere (per model) with And / Or / Not, per-field equals / not, and helpers under a lowercase module (e.g. user::id::equals(1)).
  • UserUpdate with Option fields and user::email::set("…")-style builders.
  • UserCreateInput: if the first field is id: i64, it is omitted from create input (auto-increment inserts).
  • UserOrderBy and user::id::order(SortOrder::Desc).
  • PrismaUserRepository (async trait) implemented for ModelRepository<User> with: find_unique, find_first, find_many, find_many_with_options, count, create, create_many, update, update_many, upsert, delete, delete_many.
  • PrismaUserClientExt on Arc<PrismaService> so you can write prisma.user().find_unique(…).

Errors: PrismaError maps to nestrs::HttpException via impl From<PrismaError> for HttpException (404 for missing rows, 409 for unique violations, 503-style for pool issues).

Example:

nestrs_prisma::prisma_model!(User => "users", {
    id: i64,
    email: String,
    name: String,
});

// `PrismaUserRepository` + `PrismaUserClientExt` live in this module after the macro expands.
async fn demo(prisma: std::sync::Arc<nestrs_prisma::PrismaService>) -> Result<(), nestrs_prisma::PrismaError> {
    let _ = prisma
        .user()
        .create(UserCreateInput {
            email: "a@b.c".into(),
            name: "Ada".into(),
        })
        .await?;
    Ok(())
}

Supported field types today: integer scalars (i8..i64, u8..u64), String, bool, chrono date/time types, uuid::Uuid, serde_json::Value, Vec<u8>, rust_decimal::Decimal, and provider-native mappings like std::net::IpAddr / ipnetwork::IpNetwork / bit_vec::BitVec when your schema uses corresponding native DB types.

Note: In-memory SQLite with SQLx Any works most reliably with a single-connection pool (pool_max(1)) so DDL and queries share one database. File-backed URLs avoid that limitation.

4. Optional: Prisma Client Rust (cargo prisma generate)

For generated model APIs, add prisma-client-rust to your app, run:

cargo prisma generate --schema prisma/schema.prisma

Register the generated client as an extra #[injectable] / module provider alongside PrismaService. This crate does not embed the codegen CLI; it focuses on connectivity and a PrismaService shape familiar to Nest users.

5. Generate command hint

After PrismaModule::for_root, you can surface the documented generate line with:

let hint = PrismaModule::generate_command_hint();