Prisma Client Rust
website·Indexed 32 days ago
https://prisma.brendonovich.devA Rust-specific client for using Prisma in Rust projects. Documentation covers installation, setup, and data operations including find, create, update, delete, and upsert queries. It also provides guidance on advanced features such as pagination, relational fetching, transactions, batching, raw queries, mocking, and integration with rspc.
What's inside Prisma Client Rust
- Prisma Client Rust is a community-developed client for using Prisma with Rust projects. While not an official Prisma product, it is supported via the Prisma FOSS Fund. It shares core concepts with the official Prisma documentation, so users are encouraged to refer to the main Prisma docs for general schema and database concepts.
Overview of PCR Query Traits
Query Traits (available since version 0.6.4) allow developers to modify query builders in a typesafe and decoupled manner. Instead of writing repetitive query functions for every specific query type, these traits provide a standardized way to add parameters to different types of query builders.Deploy pending migrations in production with _migrate_deploy
UsePrismaClient::_migrate_deployto apply all pending migrations that were previously generated via the Prisma CLI. This should be used after schema changes have been finalized and migrations have been created usingmigrate dev.Handle dynamic raw SQL queries using the `Raw` struct
When SQL queries are constructed dynamically and cannot be used within theraw!macro, use theRawstruct. Create aRawinstance by callingRaw::new(query, values), wherequeryis the SQL string andvaluesis aVec<PrismaValue>.Instantiate the Prisma Client in Rust
The Prisma Client requires the
tokioasync runtime. UsePrismaClient::_builder().build().awaitto instantiate the client.If you need to connect to a specific database dynamically (e.g., for desktop apps where environment variables are impractical), use the
.with_url()method on the builder.// Stops the client from outputting a huge number of warnings during compilation. #[allow(warnings, unused)] mod prisma; use prisma::PrismaClient; use prisma_client_rust::NewClientError; #[tokio::main] async fn main() { let client: Result<PrismaClient, NewClientError> = PrismaClient::_builder().build().await; }Implement cursor-based pagination
Use the.cursor()method to start pagination from a specific record. Thecursormethod requires a unique filter as its argument. This is often used in combination withorder_byfor efficient pagination.use prisma::post; let posts: Vec<post::Data> = client .post() .find_many(vec![]) .cursor(post::id::equals("abc".to_string())) .exec() .await?;Manage transactions manually
For fine-grained control over commits and rollbacks, useclient._transaction().begin(). This returns a tuple containing aTransactionManagerand a dedicatedPrismaClient. To finalize the transaction, calltx.commit(client)ortx.rollback(client). Note that these methods consume the transaction-specific client to prevent its use after the transaction ends.let (tx, client) = client ._transaction() .begin() .await?; // ... perform operations using the transaction client ... tx.commit(client).await?; // or tx.rollback(client).await?;Use dedicated update and delete actions in v0.6.0
Update and delete operations no longer chain off offind_uniqueorfind_many. Instead, use the dedicated.update(),.delete(),.update_many(), and.delete_many()methods, passing the filter as the first argument.// Single record: Before client.user().find_unique(user::id::equals(0)).update(vec![]) // Single record: After client.user().update(user::id::equals(0), vec![]) // Multiple records: Before client.user().find_many(vec![user::name::contains("Brendan".to_string())]).delete() // Multiple records: After client.user().delete_many(vec![user::name::contains("Brendan".to_string())])Filter queries using model and field modules
Prisma generates Rust modules for each model and field in the schema, followingsnake_casenaming conventions. These modules provide functions to construct modifiers for filtering queries. To filter, pass these modifiers into the query method (e.g.,find_many).use prisma::post; client .post() .find_many(vec![ // Pattern: model::field::method() post::title::equals("Test".to_string()) ]) .exec() .await;Update relations in Prisma queries
Relations can be modified using
connectanddisconnectwithinupdatequeries for single records.Caveat: Using
connectordisconnectwithinupdate_manywill cause the query to return an error. To update relations for multiple records, you must set the relation's scalar fields (foreign keys) directly.// Single record: Disconnecting a relation use prisma::{comment, post}; let updated_comment: comment::Data = client .post() .update( comment::id::equals("id".to_string()), vec![comment::post::disconnect()] ) .exec() .await?; // Many records: Updating relation via scalar field (foreign key) let updated_comments_count: i64 = client .post() .update_many( vec![comment::post::is( post::id::equals("id".to_string()) )], vec![comment::post_id::set("post".to_string())] ) .exec() .await?;Define named types for selections to use outside queries
By adding a name before the root selection in the macro, Prisma generates a module with that name containing aDatastruct and a helper function. This allows you to use the selection's type in function signatures (e.g., as a return type).// Generates mod post_only_title { pub struct Data { title: String }, pub fn select() } post::select!(post_only_title { title }) async fn do_query() -> Vec<post_only_title::Data> { client .post() .find_many(vec![]) .select(post_only_title::select()) .exec() .await .unwrap() }Execute transactions using closures
Useclient._transaction().run()to execute a series of queries within a transaction closure. The closure must return anasync moveblock that accepts a dedicatedPrismaClientinstance and returns aResult. If the closure returnsOk, the transaction commits; if it returnsErr, it rolls back.let (user, post) = client ._transaction() .run(|client| async move { let user = client .user() .create("brendan".to_string(), vec![]) .exec() .await?; client .post() .create( "test".to_string(), true, vec![post::author::connect( user::id::equals(user.id.clone()))], ), .exec() .await // if query succeeds, return user + post from transaction .map(|post| (user, post)) }) .await?;