olivierwilkinson / prisma-nested-middleware Goto Github PK
View Code? Open in Web Editor NEWUtil for calling Prisma middleware with nested relations
License: Apache License 2.0
Util for calling Prisma middleware with nested relations
License: Apache License 2.0
If I perform a nested upsert, then next()
will always return undefined
.
I expect that next()
should return the upserted document, if it is available due to an include
statement.
Below is minimal reproduction of the issue:
Schema:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
bio String?
age Int?
user User? @relation(fields: [userId], references: [id])
userId Int? @unique
meta Json?
}
Code
import { PrismaClient } from "@prisma/client";
import { createNestedMiddleware } from "prisma-nested-middleware";
const prisma = new PrismaClient();
prisma.$use(
createNestedMiddleware(async (params, next) => {
const result = await next(params);
if (params.model === "Profile" && params.action === "upsert") {
console.log("mdlwr Profile", result);
console.log("mdlwr Params", params);
}
return result;
}),
);
const run = async () => {
const user = await prisma.user.upsert({
create: {
name: "Alice",
email: "[email protected]",
},
update: {
name: "Alice",
email: "[email protected]",
},
where: {
email: "[email protected]",
},
});
await prisma.user.update({
where: {
id: user.id,
},
data: {
name: "Bob",
profile: {
upsert: {
create: {
bio: "I like turtles",
},
update: {
bio: "I like turtles",
},
},
},
},
include: {
profile: true,
},
});
};
run();
When you run this code, the result
value in the middleware is always undefined
for Profile
upserts.
Looking at the code, it seems that next()
will always resolve to undefined
if a write query is being performed.
If I comment out this line https://github.com/olivierwilkinson/prisma-nested-middleware/blob/main/src/lib/utils/targets.ts#L103 then the code behaves as expected, however I'm not 100% sure why this exists, and the prisma-nested-middleware
unit tests fail if I remove it.
Hey, haven't had the time to test the new update in a more practical sense, however I did update it on my project as I still had it running with a pass-through middleware, and noticed that it created errors with https://github.com/maoosi/prisma-appsync when trying to list models, querying their relationships, and getting results where the relationship was empty.
Here is a short example of the behavior difference:
With this schema:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "rhel-openssl-1.0.x"]
// previewFeatures = ["clientExtensions"]
}
generator appsync {
provider = "prisma-appsync"
}
model User {
uuid String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String
post Post?
}
model Post {
uuid String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
content String
userUuid String @unique
user User @relation(fields: [userUuid], references: [uuid])
}
After adding some data, run this example code:
import { PrismaClient } from "@prisma/client";
import { createNestedMiddleware } from "prisma-nested-middleware";
const prisma = new PrismaClient();
(async () => {
console.log("Pre Nested Middleware");
console.log(
await prisma.user.findMany({
select: {
uuid: true,
name: true,
post: {
select: {
uuid: true,
content: true,
},
},
},
})
);
console.log("Adding Nested Middleware");
prisma.$use(
createNestedMiddleware(async (params, next) => {
return await next(params);
})
);
console.log("Post Nested Middleware");
console.log(
await prisma.user.findMany({
select: {
uuid: true,
name: true,
post: {
select: {
uuid: true,
content: true,
},
},
},
})
);
})();
As you can see, post
becomes an empty object if it can't find a relationship, instead of null
, which causes issues with a GraphQL API, which will see fields of that relationship as null
when they are not meant to be.
Thank you so much for putting together this marvelous library. It has helped us a lot, and we appreciate your work.
Prisma has "deprecated" middleware via $use
, and is going all-in on client extensions. Unfortunately the new client extensions share the same downside of the old middleware, meaning that model-specific extensions are not called when models are nested.
Do you have any plans on porting the library to use the client extensions API?
Thanks again for your hard work on this.
Hey Olivier!
Thanks for putting this package together.
Any thoughts on what it would take to support nested reads as well?
main
branch failed. π¨I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again.
You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. Iβm sure you can fix this πͺ.
Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.
Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the main
branch. You can also manually restart the failed CI job that runs semantic-release.
If you are not sure how to resolve this, here are some links that can help you:
If those donβt help, or if this issue is reporting something you think isnβt right, you can always ask the humans behind semantic-release.
1.1.1
on branch main
cannot be published as it is out of range.Based on the releases published on other branches, only versions within the range >=1.1.0 <1.1.1
can be published from branch main
.
The following commits are responsible for the invalid release:
Those commits should be moved to a valid branch with git merge or git cherry-pick and removed from branch main
with git revert or git reset.
A valid branch could be next
.
See the workflow configuration documentation for more details.
Good luck with your project β¨
Your semantic-release bot π¦π
DbNull and JsonNull are used for json fields, using createNestedMiddleware makes it impossible to use them because they are transformed into undefined and the prisma call fails since it expects either DbNull / JsonNull or a valid JSON.
Thanks you very much!. I spent a week implementing nested middlewares, but still couldn't cover all their use cases. You saved everyone a many of nerve cells!
p.s It is very strange that Prisma core team did not implement this in 3 years.
In v2, you could find field values in nested create action under params.args.data
. As of v3, when doing a nested create, these field values are directly under params.args
. As a result I have to write logic to handle both cases, by looking at the scope
value. e.g.
const data = params.scope ? params.args : params.args.data;
This change isn't mentioned in the v3 release notes, so I'm presuming that it's unintentional.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.