hayes / pothos

Pothos GraphQL is library for creating GraphQL schemas in typescript using a strongly typed code first approach
https://pothos-graphql.dev
ISC License
2.35k stars 163 forks source link

Add composite types for prisma plugin #411

Closed boenni23 closed 4 months ago

boenni23 commented 2 years ago

Please add composite types to the PrismaTypes of the @pothos/plugin-prisma

https://www.prisma.io/docs/concepts/components/prisma-client/composite-types

At the moment you have to define them all by hand. I a bigger project this is a lot of code.

hayes commented 2 years ago

I think this will require some more extensive design around the API, and isn't as simple as just adding it to the gerates types. Do you have a more complete idea of what specific features you want supported for compsite types? I haven't really used prisma with mongo yet, so I don't have a full grasp of everything involved here, but there are issues like composite types not being directly queryable which makes this a little complicated.

hayes commented 2 years ago

Started looking at this a bit today, it seems like adding a new builder.prismaCompositeObject should be relatively straight forward. I'll need to do some more research on where composite types are headed in the future to make sure this isn't something that will become hard to expand on as the concept gets developed further.

2coo commented 1 year ago

We are very glad that you created and you are actively supporting it. Very thank you. Adding a feature that supports composite types would be really helpful.

hayes commented 1 year ago

@giva9712 the biggest blocker here is that I haven't used composite types, and it's not clear to me how this should actually work. They don't follow the rules.for normal Prisma models, so I can't just extend the existing prismaObject method to support them.

Creating a method that creates object types from composit types is pretty trivial, but also doesn't add much value because doing it with objectRef is equally trivial.

The interesting parts are around how relations between composite types work, how selections work, etc. If you had a detailed idea of what you would actually want the plugin to do, I could investigate the feasibility, but I'm not confident I could provide a comparable API that isn't wildly inefficient

2coo commented 1 year ago

Composite type use cases

To improve performance

when many-to-many relations and big data comes together composite type can be used as a fragment that contains only low details of the real object in order to improve performance by excluding join queries.

For example:

type CourseType {
  courseId   String @db.ObjectId
  courseName String
}

model Student {
  id        String       @id @default(auto()) @map("_id") @db.ObjectId
  firstName String
  lastName  String
  courses   CourseType[]
  ...
}

model Course {
  id          String       @id @default(auto()) @map("_id") @db.ObjectId
  name        String
  description String
  assessments Assessment[]
  ...
}

model Assessment {
  id       String @id @default(auto()) @map("_id") @db.ObjectId
  courseId String @db.ObjectId
  course   Course @relation(fields: [courseId], references: [id])
  ....
}

Note that the data related to the course is duplicated - the course name and id are present in both collections. You can also note that these details will not change often (or may not change at all). This is feasible, though you have the same data in both collections. And, this also makes querying simpler.

To group/simplify

for example, let's say there is a user model which contains links (githubLink, instagramLink, twitterLink) and we can group them by using a composite type called socialLinks then now we have:

type SocialLinks {
  githubLink String?
  instagramLink String?
  twitterLink String?
}

model User {
  ...
  socialLinks SocialLinks
}
hayes commented 1 year ago

Thanks for sharing these use cases. I'd be curious if you are running into anything here you can't simply create with Pothos existing APIs.

eg:

const SocialLinks = builder.objectRef<SocialLinksTypeImportedFromPrisma>('SocialLinks').implement({
  fields: t => ({
    githubLink: t.exposeString('githubLink', nullable: true),
    instagramLink: t.exposeString('githubLink', nullable: true),
    twitterLink: t.exposeString('githubLink', nullable: true),
  }),
})

builder.prismaObject('User', {
  fields: t => ({
     ....
     socialLinks: t.field({
       type: SocialLinks,
       select: {
         socialLinks: true,
       },
       resolve: user => user.socialLinks
     })
  })
})

this does require that your composite types are selected in their entirety (so you can't just select specific parts) but I imagine most of the time that is a reasonable tradeoff and the nested composite types won't be huge (this may be a bad assumption)

harish-github35 commented 11 months ago

@hayes nexus supports composite object. why cant pothos. this is very basic feature.

hayes commented 11 months ago

@hayes nexus supports composite object. why cant pothos. this is very basic feature.

Can you elaborate on what you would expect the API to look like that would be significantly different than just using Pothos directly as described above?

harish-github35 commented 11 months ago

@hayes nexus supports composite object. why cant pothos. this is very basic feature.

Can you elaborate on what you would expect the API to look like that would be significantly different than just using Pothos directly as described above?

"this does require that your composite types are selected in their entirety" fields of them should be selectable individually by user of the api.

hayes commented 11 months ago

fields of them should be selectable individually by user of the api.

That's referring to how selection works at the prisma level, and doesn't affect how users query the API.

I can't find anything in the prisma docs indicating that there is a way to select specific pieces of a composite type. It was something they had indicated might be supported in the future, but I haven't seen anything related to that since this feature was first introduced

hayes commented 4 months ago

I have not found any compelling reasons to add something beyond using builder.objectRef for composite types, so I am closing this for now