Hello everybody, have a few questions: I’ve got 2...
# orm-help
j
Hello everybody, have a few questions: I’ve got 2 schemas: prisma schema and app schema. Prisma generated types for me, also I’ve generated types for the app schema using
graphql-code-generator
. 1. How to properly ‘type’ the resolvers ? I typed the resolvers itself with types generated from the
graphql-code-generator
for example:
Copy code
const updateUser: MutationResolvers['updateUser'] = <resolver code>
But the problem is - return type from the resolver (
prisma.user.update
call ) is User (prisma) and it does not include the relations, and here is the conflict ( ’Type ‘User’ is missing the following properties from type ‘User’: adminOf, employeeOf, accounts’ or similar ones ). Basically for every model/type I’ve got 2 type definitions and in many cases they differ. Here is the User type in the app schema:
Copy code
type User {
  email: String!
  firstName: String!
  lastName: String!
  phone: String
  billingAddress: Address
  shippingAddress: Address
  adminOf: [Company!]!
  employeeOf: [Company!]!
  accounts: [Account!]!
  adminOfVendors: [Vendor]
}
Here is typings for the User model (prisma):
Copy code
export type User = {
  id: string
  emailVerificationToken: string | null
  passwordResetToken: string | null
  superUser: boolean
  email: string
  firstName: string
  lastName: string
  password: string
  phone: string | null
  billingAddress: Prisma.JsonValue | null
  shippingAddress: Prisma.JsonValue | null
}
Here is typings for the User type (graphql-code-generator):
Copy code
export type User = {
  __typename?: 'User';
  email: Scalars['String'];
  firstName: Scalars['String'];
  lastName: Scalars['String'];
  phone?: Maybe<Scalars['String']>;
  billingAddress?: Maybe<Address>;
  shippingAddress?: Maybe<Address>;
  adminOf: Array<Company>;
  employeeOf: Array<Company>;
  accounts: Array<Account>;
  adminOfVendors?: Maybe<Array<Maybe<Vendor>>>;
};
Maybe there is some universal practice of typing the API with 2 main type files (for the prisma datamodel and app schema) ? I’m new to the typescript. 2. If my app schema defines some fields which are relations (User example):
Copy code
adminOf: [Company!]!
  employeeOf: [Company!]!
  accounts: [Account!]!
  adminOfVendors: [Vendor]
I do need to use
include
in the Prisma Client in every resolver that should return User type? Because they are not returned by default. 3. T*ype resolvers:* For example I’ve got
Company
type and it has field
admin
which is of type User. When I write type resolvers for the
Company
type, specifically for the
admin
field, do I also need to use
include
in it (to get relations of the User) ? Example:
Copy code
const resolvers = {
  Query: {
    // ... 
  },
  Mutation: {
    // ... 
  },
  Company: {
    admin: (parent, args, context) => {
       return context.prisma.company.findUnique({
         where: { id: parent.id }
       }).user()

       // Or something like that
       return context.prisma.user.findUnique({
        where: { id: parent.userId },
        include: {
          some_relation_field: true
        }
      })
     }
   },
}
Sorry for a lot questions, thank you.
e
Hello @jasci! Which server are you using for your GraphQL? I have a similar setup using
apollo-server
with
graphql-code-generator
. The basic concepts are the same in most GraphQL servers. Let me try to answer your questions one by one: 1. How to match Prisma and GraphQL types: use
typescript-resolvers
‘s “mappers”. Documentation. Example config and example mapper file . If you use Prisma’s type as the mapper, you can return Prisma objects directly into resolvers. You will have to write field resolvers to make sure fields are converted to the correct value and types. For example, your Prisma
billingAddress
is
Prisma.JsonValue | null
. So you will have to have
User.billingAdress
resolver to convert it to
Maybe<Address>
Copy code
User: {
  ...
  billingAddress: ({ billingAddress }) => {
    // Business logic to convert `Prisma.JsonValue | null` to `Maybe<Address>`
    return convertToGraphBillingAddress(billingAddress);
  }
}
2. For fields that are relationships, the best way to handle them is to create resolvers for the
User
type. This way, you will not overfetch the
User
object and only will load relationships if requested by the client. e.g.
Copy code
User: { 
  ...
  adminOf: ({ id }, args, { prisma } ) => { 
    // Use prisma to find the relationship here. Something like this? I can't remember the syntax
    return prisma.user.findUnique({ where: { id } }).includes(...)
  } 
}
3. If you set up mappers correctly in 1. you can use
findUnique
to return
User
Prisma object
Copy code
Company: {
    ...
    admin: (parent, args, context) => {
       return context.prisma.company.findUnique({
         where: { id: parent.id }
       }).user()
      })
     }
   },
1
j
Hello, Eddy, thanks a lot! A few more questions: 1.So basically with mappers I redefine what
User
means in this resolver? And when I add type for
updateUser
resolver from
graphql-code-generator
types, it now expects to return
User
(Prisma User, not the one from the app schema), right ? 2. I need to create mappings for all my models which have conflicts, right ?
I’m using ApolloServer too.
e
Hi @jasci, 1. Yes, once you have the mappers wired in and regenerate, you will see that all your Graph resolvers that previously returned Graph
User
will need to return Prisma
User
type 2. Yes, every model should be mapped in my opinion for ease of use and consistency. I think you can map directly using the Prisma generated types (
@prisma/client
) instead of going through the mapper file. However, I haven’t tried this so it might or might not work
1
j
Thank you.
e
No worries! Happy to help 😃