-
-
Notifications
You must be signed in to change notification settings - Fork 162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
create prisma utils plugin #348
Conversation
This pull request is being automatically deployed with Vercel (learn more). 🔍 Inspect: https://vercel.com/mhayes/pothos/HesXVKxajV2RqBTEcNseHPAWZQfF |
|
baacd76
to
e73ada1
Compare
e73ada1
to
30e8f74
Compare
30e8f74
to
89f122a
Compare
Any progress on this? If you need ideas on crud look at the typegraphql-prisma module which uses ts decorators. Pothos is much nicer imo, since decorators in ts is terrible. |
Not yet. I've been working on the new tracing plugin, and haven't had a lot of extra time to build this out. The API for this is pretty complex, and something I specifically want to do differently than some of existing options for building crud schemas using Prisma. Its still something I want to build, but it will take some time before I have anything that is usable. |
89f122a
to
8c5c41a
Compare
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Great talk in Prisma day |
I think that Pothos + Prisma + Crud will be the next better way to build Graphql APIs. Recently (27 Jan 2021), Nexus integration with prisma was suddenly discontinued due to an "better alternative" that never cames. I read your comments inside #428 and... Said that, all we need is: generated Input Objects With this, we will reach this to Pothos Prisma Plugin:
By only adding this input type as args of the A second goal to this, is a plugin to auto-generate crud based on the Prisma Schema (like you commented too at #428) I think a good API is:
// Models be like: User, Post, Like, Follow, ...
// Generating crud in 3 scenarios
// 1. ALL: Generating all crud for all Models
// src/schema/index.ts
builder.prismaCrud()
// 2. SPECIFIC: Generating only models, queries or mutations
// src/schema/index.ts
builder.queryFields((t) => t.prismaCrud() // findCount, findFirst, findMany, findUnique, aggregate for all models
builder.mutationFields((t) => t.prismaCrud() // createOne, createMany, deleteMany, deleteOne, updateOne, updateMany, upsertOne for all models
builder.prismaCrudObjects() // create all objects, with all fields
// Auto generate for specific Models
builder.queryFields((t) => t.prismaCrud({ include: ["Post"] }) // operations for User only.
builder.mutationFields((t) => t.prismaCrud({ exclude: ["User"] }) // operations for all but User.
builder.prismaCrudObjects({ exclude: ["User"] }) // create all objects but User, with all fields
// 3. CUSTOMIZE EVERYTING
// src/schema/user/objects.ts
builder.prismaCrudObject('User', {
fields: (t) => {
const { password, ...publicFields } = t.prismaCrudFields;
console.log(`This ${password} is never sent to user`)
return {
...publicFields,
// custom field
openedWelcomeEmail: t.boolean({
resolve: (user) => mailService.openedWelcomeEmail(user.email),
}),
}
},
});
// src/schema/user/queries.ts
builder.queryFields((t) => ({
findManyUser: t.prismaCrudField(), // default find one (with all options)
findOneUser: t.prismaCrudField(t => ({
resolve: (query, root, args, ctx) =>
db.post.findUnique({
...query,
where: { id: ctx.user.id },
}),
})),
}))
// src/schema/user/mutations.ts
builder.mutationFields((t) => ({
createManyUser: t.prismaCrudField(), // default find one (with all options)
createOneUser: t.prismaCrudField(t => ({
args: {
...t.prismaCrudArgs,
sendEmail: t.arg({ type: "Boolean", defaultValue: true }), // custom args for crud
},
resolve: (query, root, args, ctx) => {
if (args.sendEmail) mailService.sendWelcomeEmail(args.data);
return db.post.findUnique({
...query,
where: { id: ctx.user.id },
})
},
})),
})) Questions:
If possible I would like to help with development, I feel that this functionality would fill a very big hole in the Graphql/Prisma ecosystem. |
I know this is a popular feature that a lot of people are excited about, just want to temper expectations a bit, I haven't had a lot of time to make significant progress on this yet. I also want to be clear that this will NOT be an attempt to replicate the same behavior that the old nexus prisma plugin provided. I have discussed this in a few places, but automatically generating crud operations form your database is not in line with the core principles behind Pothos, and is a non-goal for the change. The goal here will be to simplify and streamline the processes of building curd APIs by providing building blocks, which eventually could be put together to generate crud APIs, but will require some helpers defined at the application level to reach parity with what you might have been able to do in the nexus plugin. Things I want this plugin to help with:
Things that this plugin won't do
I should probably document more about why these limitations are important, but I think the end result should result in a better experience for most use cases. The simplest apps will have slightly more overhead in the inital set up, but this should be relatively easy to overcome. |
@Cauen let me address some of your comments more directly, there is a lot there to unpack:
This is definitely the thing that's people are asking for. I see this as a asking for faster horses instead of cars situation. There are some good reasons that prisma tried to go in a new direction with their second version of a nexus plugin.
This is likely what the initial version of this plugin will contain
The basics for this already exists: t.relation('posts', {
args: {
first: t.int()
},
query: (args) => ({ limit: args.first ?? 10 })
}) The above mentioned input type helpers will help create types to use in args that can automatically be passed into the query part of a relation, or used in a prisma field, which will help with more complex filters (includes, negations, startsWith, etc).
This is a little more complicated. There are a LOT of options when it comes to relations when crating/deleting/mutation a record. Automatically supporting connecting/creating/cascading deletes on every operation is a bad idea. Schemas should be constrained to the operations you actually want to allow, and I think a lot of apps are going to want to make different choices on how they want to support things like nested creates or connecting to existing entities. This can't be generated in a way that I think is good, so the solution here will be improved APIs for manually defining input types for creates/updates related to specific prisma types, and examples of how to create your own utilities that use those methods to generate things for you.
This is very specifically NOT a goal I think the code examples are probably fairly far off from the API I am imagining, but an example that shows how to build a similar API yourself using the provided helpers would probably be reasonable, and hopefully not too complex.
I hope the above comments have some indication on what I think makes sense in pothos vs what belongs somewhere else.
Yes, I would absolutely be open to help working on this. This is a very important API to get right, and will need to be highly composable, and will probably take a lot if iteration. My general approach to development for pothos is to build out the entire API in the type-system first without any implementation, because that tends to be that hardest piece. If you are serious about wanting to work on this, I'd be happy to help you get familiar how to get set up working in the repo and answer questions. I am usually pretty active in the Pothos discord channel, so that might be a good place for a more real time conversation about this. |
Hi @hayes, thanks for providing better specs for your expectations for the plugin.
I'm quite interested in hearing your thoughts on this. In my experience, keeping a "super power" resolver with restrictions based on role/access is the most productive way to work (Especially if fullstack). This was why I liked the Nexus integration so much. I believe that was not the reason for the "new direction with their second version" but because according to them: "accumulated a lot of technical debt".
Really thanks for your willingness to help. With that in mind, I put into practice the development of a The roadmap:
The first version was published at prisma-generator-pothos-codegen - npm It's my first open source project, so any contribution is more than welcome. ---- Edit 2022-07-13 ---- Published version 0.2.0 with generator for all Click to see configs options{
inputs?: {
prismaImporter?: string // default: import { Prisma } from ".prisma/client"
builderImporter?: string // default: import { builder } from "./builder"
excludeInputs?: string[] // default: undefined
excludeScalars?: string[] // default: undefined
outputFilePath?: string // path to generate file, from project root
replacer?: (generated: string, position: ReplacerPosition) => string // a function to replace generated source
},
crud?: {
disabled?: boolean // disable generaton of crud. default: false
includeResolversExact?: string[] // generate only resolvers with name in the list. default: undefined. ie: ['createOneUser']
includeResolversContain?: string[] // generate only resolvers with name included in the list. default: undefined. ie: ['User'].
excludeResolversExact?: string[] // default: undefined. ie: ['createOneComment']
excludeResolversContain?: string[] // default: undefined. ie: ['createOne']
resolversImports?: string // default: what to import inside resolver
dbCaller?: string // how to call prisma. default: context.db
inputsImporter?: string // default: import * as Inputs from "@/generated/inputs";
builderImporter?: string // default: import { builder } from "./builder"
outputFolderPath?: string // path to generate files, from project root. default: ./generated
replacer?: (generated: string, position: ReplacerPosition) => string // a function to replace generated source
},
global?: {
replacer?: (generated: string, position: ReplacerPosition) => string // a function to replace generated source
}
} See example: click here |
@Cauen that's great! I think that's exactly the right direction. There will be a lot of people who want something like what you are describing. What I want to build are building blocks to make that generated code simpler. In my opinion, there are too many choices and tradeoffs to make to design something that solves everyones use case, which is why I am starting with the building blocks that enable some of these higher level APIs. |
8c5c41a
to
40239fb
Compare
@Cauen Have you considered to build a pal.js generator class for Pothos before starting prisma-generator-pothos-codegen? |
@izziaraffaele No, i wanted to build my own specific alternative. That's because I saw that his code revolves around the Nexus. |
dddc53b
to
58fe79a
Compare
Hi all. Just wanted to chime in and say thanks for all the work and to offer a suggestion that may make a path forward easier-- Would it make sense to either (i) move the filter / orderBy generator to its own package (@pothos/plugin-prisma-inputs?) or (ii) move them into the prisma-plug-in itself? At the very least I feel like there's a disconnect between the label "crud" and what I'm particularly looking for -- just creation of Filter and OrderBy args. Crud implies more of what I think you're trying to avoid -- generating resolvers (cf., |
Yes, it will be renamed before release. I created the initial branch and empty plugin without thinking through it much. It will be its own package (at least for early versions) so it can be versined independently. |
58fe79a
to
e7a3070
Compare
148e135
to
72ac176
Compare
72ac176
to
d764c3b
Compare
I know several of you have been waiting for movement on this PR for a long time. The scope of what I want to do with this had become a bit of a blocker for getting started, and I have been focusing on smaller iterative changes in other parts of Pothos. Instead of trying to tackle implementing full crud support in a single PR, I built out some of the first building blocks needed. This is still an early iteration, but I'm hoping that what I have so far can serve as a way to prove out the concept. I've merged this PR and published an initial version that includes a few features:
These utilities generate input types that are automatically normalized so they can be passed to prisma without having to coerce nulls to undefined (the args themselves currently can still be null, but anything nested in the input object will be a real value or undefined). Definitions for these types are still completely explicit. For each filter type, you provide the list of filter operations. Same thing applies to order by and where objects, the set of fields and relations you can order or filter by is explicitly defined for each object. That means this isnt the auto-generation that some people have been asking for, but this makes writing tools to automatically generate these filters a lot easier Last thing to note is filters for scalars are based on your graphql types not prisma types. The basic idea is that there are frequently more db types than there are graphql types, and your user doesn't care how something is stored in your db. All input types are built based on typescript compatibility. This also means that different db variants with different primatives can all be supported automatically, as long as you can define a graphql scalar that has a compatible typescript type. Docs still need to be written, and I'll open a discussion or something for feedback soon. |
No description provided.