Prisma Nested Middleware
Util for calling Prisma middleware for nested write operations.
Existing Prisma middleware is called once for every operation, but due to some operations containing nested writes it can become complex to ensure middleware is applied in all scenarios. See the existing issue regarding nested middleware for more information.
Table of Contents
Installation
This module is distributed via npm which is bundled with node and should be installed as one of your project's dependencies:
npm install --save prisma-nested-middleware
Usage
Pass a middleware function to createNestedMiddleware
, the returned middleware can be passed to Prisma client's $use
method:
import { createNestedMiddleware } from 'prisma-nested-middleware'
client.$use(createNestedMiddleware(async (params, next) => {
// update params here
const result = await next(params)
// update result here
return result;
));
The middleware function passed to createNestedMiddleware
is called for every nested write operation.
There are some differences to note when using nested middleware:
- the list of actions that might be in params is expanded to include
connectOrCreate
- If a relation is not included using
include
then that middleware'snext
function will resolve withundefined
. - The parent operation's params have been added to the params of nested middleware as a
scope
object. This is useful when the parent is relevant, for example when handling aconnectOrCreate
and you need to know the parent being connected to. - when handling a nested
create
actionparams.args
does not include adata
field, that must be handled manually. You can use the existence ofparams.scope
to know when to handle a nestedcreate
.
It is helpful to walk through the lifecycle of an operation:
For the following update
client.country.update({
where: { id: 'imagination-land' },
data: {
nationalDish: {
update: {
where: { id: 'stardust-pie' },
data: {
keyIngredient: {
connectOrCreate: {
create: { name: 'Stardust' },
connect: { id: 'stardust' },
},
},
},
},
},
},
});
createNestedMiddleware
calls the passed middleware function with params in the following order:
{ model: 'Recipe', action: 'update', args: { where: { id: 'stardust-pie' }, data: {...} } }
{ model: 'Food', action: 'connectOrCreate', args: { create: {...}, connect: {...} } }
{ model: 'Country', action: 'update', args: { where: { id: 'imagination-land', data: {...} } }
Once all of the nested middleware have passed params to next
the params for the Country
model are updated with any changes made; these params are then passed to the Country
model's next
function.
When the Country
model's next
resolves the next
of the nested middleware are also resolved with the slice relevent to them. So the middleware called for the Recipe
model resolves with the nationalDish
, the middleware for the Food
resolves with the keyIngredient
.
Finally the return values from the nested middleware are used to modify the Country
result in a similar way to params, and that modified object is the one client.country.update
resolves with.
If any middleware throws an error then client.country.update
will throw with that error.
LICENSE
Apache 2.0