PluginsPrisma Next

Type variants

Multiple GraphQL types backed by the same contract model

Use variant to expose the same Prisma model as another GraphQL type. For example, a Viewer type can show signed-in users their own email and drafts, which the public User type leaves out:

const Viewer = builder.prismaObject('User', {
  variant: 'Viewer',
  fields: (t) => ({
    id: t.exposeID('id'),
    email: t.exposeString('email'),
    drafts: t.relation('posts', { query: { where: { published: 0 } } }),
  }),
});

Return a variant

Wherever you use the model name, such as 'User', you get the default type. To return the variant, pass its ref as type, for example from a root field:

builder.queryFields((t) => ({
  viewer: t.prismaField({
    type: Viewer,
    nullable: true,
    query: (_args, ctx) => ({ where: { id: ctx.userId } }),
  }),
}));

t.relation takes a variant's ref as type the same way.

Switch to another variant

t.variant adds a field that returns the same row as another variant, without another query. To return null for some rows, pass isNull, which needs a nullable field. It sees the primary key, the type's select, and the columns in the field's select. Here User.viewer returns the Viewer type only for the signed-in user:

builder.prismaObject('User', {
  fields: (t) => ({
    viewer: t.variant(Viewer, {
      nullable: true,
      isNull: (user, _args, ctx) => user.id !== ctx.userId,
    }),
  }),
});

Adding fields

To add fields to a variant, pass its ref to prismaObjectField or prismaObjectFields:

builder.prismaObjectField(Viewer, 'displayName', (t) =>
  t.string({
    select: { firstName: true, lastName: true },
    resolve: (user) => `${user.firstName} ${user.lastName}`,
  }),
);

To return either User or Viewer from one field, give them a shared GraphQL interface.