Batching
PrismaClient::_batch
allows you to sequentially execute multiple queries in a single transaction.
If one of the queries fails, all changes will be rolled back.
Data provided to _batch
falls under two categories:
-
Containers: Root level collections that contain all items in the batch. Can be either a tuple or a type implementing
IntoIter
. -
Items: Either a query or a collection (
Vec
or tuple) of nested queries.
Containers
Even if your batch doesn't include nested items, you still need to put queries inside some sort of container.
Tuple
Using a tuple allows for multiple types of queries to be used at once.
The return type of _batch
will be a tuple of the results of each item.
use prisma::user;
let (user_one, user_two, user_count): (user::Data, user::Data, i64) = client
._batch((
client.user().create(..),
client.user().create(..),
client.user().count(vec![]),
))
.await?;
assert_eq!(user_count, 2);
Iterator
Using a type that implements IntoIter
such as Vec
allows for
a dynamic number of items to be batched together.
The return type will be a Vec
of the result of the item.
use prisma::user;
let users: Vec<user::Data> = client
._batch(vec![
client.user().create(..),
client.user().create(..),
client.user().create(..)
])
.await?;
assert_eq!(users.len(), 3);
IntoIter
includes regular iterators,
so you can pass them straight into _batch
and
collect
will be called internally.
use prisma::user;
let user_ids = vec![1, 2, 3, 4, 5];
let user_creates = user_ids
.into_iter()
.map(|id| client
.user()
.create(..)
); // _batch will collect internally!
let users: Vec<user::Data> = client
._batch(user_creates)
.await?;
assert_eq!(users.len(), 5);
Items
Items can be either individual queries or a collection.
Tuple
The same logic applies to a tuple item as a tuple container, with the item's result being a 1-1 mapping of each query to its result type.
let data: Vec<(user::Data, post::Data)> = client
._batch(vec![
(client.user().create(..), client.post().create(..)),
(client.user().create(..), client.post().create(..)),
])
.await?;
Vec
Unlike containers, only Vec
can be used for dynamic collections of queries.
Apart from that, the behaviour is the same.
let data: (Vec<user::Data>, Vec<post::Data>) = client
._batch((
vec![client.user().create(..), client.user().create(..)],
vec![client.post().create(..), client.post().create(..)],
))
.await?;
Nesting
Any combination and nesting of items can be put inside a container, allowing for heavily nested return types.
This example isn't really practical, but it's possible.
let data: Vec<(
Vec<(user::Data, post::data)>,
(Vec<user::Data>, Vec<post::Data>),
)> = client._batch(vec![(
vec![
(client.user().create(..), client.post().create(..)),
(client.user().create(..), client.post().create(..)),
],
(vec![client.user().create(..)], vec![client.post().create(..)]),
)]);