For a contrived example, what if I wanted to add s...
# orm-help
a
For a contrived example, what if I wanted to add some field to a user called
has_commented_100_times
, which doesn't exist in the DB, but in the resolver you query for the number of comments associated with them and return true if it's >= 100
d
You would need to handle this in your GraphQL server. So when you define the schema the client accesses, you can add that property. Then create a custom resolver for that type and in that resolver specify your field and write the resolver for it. This resolver has access to the standard params like context, args, parent.
r
Documented here: https://www.apollographql.com/docs/apollo-server/v2/essentials/data.html So each resolver represents a field, so any field can be handled by a resolver using parent -> child relationships!
@aria I got the resolver working, but I can't figure out how to modify my schema to handle returning a type that diverges from the generated schema. because the generated
type User
is not an interface, we cannot extend it for virtual fields it seems?
Copy code
export const UserExtended = {
  hasMemberships: (parent, args, ctx, info) => {
    return ctx.user.memberships && ctx.user.memberships.length > 0
  },
}
export const resolvers = {
  Query,
  Mutation,
  Subscription,
  UserExtended,
}
This worked for getting the resolver working
but my graphql-yoga schema won't let me do this, as it shouldn't:
Copy code
type UserExtended implements User {
  hasMemberships: Boolean!
}
adding the field to the dataschema type (the source
User
definition) i think would add a column, thus not a virtual field. hmm @devan what would you do here?
oh nice... it does work as a virtual field if i add it to the prisma schema def. @aria check this out:
Copy code
// resolvers
export const User = {
 hasMemberships: (parent, args, ctx, info) => {
   return ctx.user.memberships && ctx.user.memberships.length > 0
 },
}
export const resolvers = {
 Query,
 Mutation,
 Subscription,
 User,
}

// datamodel.graphql

type User {
   id: ID! @unique
   hasMemberships: Boolean!
}
in this case,
hasMemberships
does not generate a column in the database, so i guess prisma cleverly handles child field resolvers virtually 🙂
a
@rikki hmm why would it not generate a column? Aren't migrations generated based on your datamodel?
r
ah yeah, i was wrong, it did add the column. yeah it wouldnt make sense for that to work
a
@devan same question basically. I know you can do it on the server, but given that your schema is generated from the data model how do I add an extra field to the prisma generated schema...short of literally editing the generated file, which I don't think is a good idea.
r
@aria yeah the other option is to do what i did above, and recreate the type for that schema and add the field
the only way around it would be if the cli generated interface versions of every model type definition
d
Sorry, you seem to be confusing your datamodel.graphl (the thing you tell Prisma about to auto-generate db fields and such) with the schema for your graphql server
r
Copy code
// resolvers

const UserOverride = {
 hasMemberships: (parent, args, ctx, info) => {
   return ctx.user.memberships && ctx.user.memberships.length > 0
 },
}

export {
 Query,
 Mutation,
 Subscription,
 UserOverride,
}


// schema.graphql

type UserOverride  {
 id: ID!
 hasMemberships: Boolean!
 // duplicated fields from datamodel here
}
a
@devan but doesn't that also generate your graphql schema? Unless you're saying I should write another graphql schema on top of the schema that is generated by Prisma?
d
Correct. Just a second
r
@aria my bad, i thought you were doing that already! haha
d
This is your data model and Prisma
Remember that you still have a graphql server that has a separate schema
The terms can be confusing… your datamodel.graphql powers your Prisma server. While your schema.graphql powers your GraphQL server (that the client requests to, and you delegate executions to your Prisma server from)
a
@devan hmmm so wouldn't I be basically duplicating most of what prisma already generates in my
schema.graphql
?
r
Copy code
# import * from "./generated/prisma.graphql"

type Query {
  users(
    where: UserWhereInput
  ): [Users]
}
@aria you can reuse the types, inputs and whatnot generated from your
datamodel.graphql
in your
schema.graphql
😮 1
the prisma cli takes
datamodel.graphql
and generates the
prisma.graphql
d
@aria looks like you may understand it now 🙂
👍 1
a
hmmm so to make this super concrete, how what would my
schema.graphql
look like if I wanted to reuse the types in
prisma.graphql
, but add/hide fields?
Is that possible? Or would I just be copy/pasting
r
@aria what i showed you would do that, essentially, but it would mean manually duplicating the types. unless @devan knows a way around that
👍 1
the only idea i thought of is that prisma cli could generate a
type User
and
interface UserInterface
as a helper, though it would bloat the prisma.graphql
a
Yeah exactly. Curious if there's a copy/paste-free way.
d
Nope, I don’t know of a way around that. I consider that security, and I usually duplicate the types, so I can not expose specific properties.
👍 2
a
@devan okay awesome. This was* honestly making/breaking prisma for me, and I'm glad that I understand what's actually going on now.
👍 1
r
@devan what of the aforementioned interface idea?
User
being an example. is that a potential feature request?
d
I’ve never tried that @rikki. Someone like @nilan could shed light on that type of usage.
r
thanks @devan!
d
No problem! Curious if reusing the types like that works out. Let me know!
r
@devan it would in theory, but prisma CLI would need a PR to make that possible
Copy code
type AppDomainUser implements User {
  virtualField: Boolean!
}
would currently throw an error because
User
is a
type
, not an
interface
(like
Node
). I guess this means that if you use interfaces a lot in your datamodel you might be in luck, but mine are all types.
Copy code
// datamodel.graphql
interface NodeExtended implements Node {
  createdBy: User!
  createdDate: DateTime!
  updatedDate: DateTime!
}

type Document implements NodeExtended {
  name: String!
}

// schema.graphql
type AppDocument implements NodeExtended {
   name: String! // duplicate fields from Document here
   readCount: Int!
}
type Query {
  documents: [AppDocument]
}
// resolvers/index.js

const AppDocument = {
   readCount: () => {
      return ctx.db.query.
   }
}

export {
  Query,
  Mutations,
  AppDocument
}
@devan i think this shortcut would work. it doesnt get rid of all the duplication, but like you said maybe thats not a big deal
ah no that wouldnt, because the interface wouldnt pick up on all the generated fields added to the Document type
@devan seems that in order for prisma cli to add the extra interfaces, it would require changes to `graphql-js`'s
printSchema
, however I thought of a somewhat brittle workaround that I was gonna make a PR for... 😄
the other approach would be for prisma to have a @virtual directive to tell it not to add a column