Pothos

Type variants

The prisma plugin supports defining multiple GraphQL types based on the same prisma model. Additional types are called variants. You will always need to have a "Primary" variant (defined as described above). Additional variants can be defined by providing a variant option instead of a name option when creating the type:

const Viewer = builder.prismaObject('User', {
  variant: 'Viewer',
  fields: (t) => ({
    id: t.exposeID('id'),
  });
});

You can define variant fields that reference one variant from another:

const Viewer = builder.prismaObject('User', {
  variant: 'Viewer',
  fields: (t) => ({
    id: t.exposeID('id'),
    // Using the model name ('User') will reference the primary variant
    user: t.variant('User'),
  });
});

const User = builder.prismaNode('User', {
  id: {
    resolve: (user) => user.id,
  },
  fields: (t) => ({
    // To reference another variant, use the returned object Ref instead of the model name:
    viewer: t.variant(Viewer, {
      // return null for viewer if the parent User is not the current user
      isNull: (user, args, ctx) => user.id !== ctx.user.id,
    }),
    email: t.exposeString('email'),
  }),
});

You can also use variants when defining relations by providing a type option:

const PostDraft = builder.prismaNode('Post', {
  variant: 'PostDraft'
  // This set's what database field to use for the nodes id field
  id: { field: 'id' },
  // fields work just like they do for builder.prismaObject
  fields: (t) => ({
    title: t.exposeString('title'),
    author: t.relation('author'),
  }),
});

const Viewer = builder.prismaObject('User', {
  variant: 'Viewer',
  fields: (t) => ({
    id: t.exposeID('id'),
    drafts: t.relation('posts', {
      // This will cause this relation to use the PostDraft variant rather than the default Post variant
      type: PostDraft,
      query: { where: { draft: true } },
    }),
  });
});

You may run into circular reference issues if you use 2 prisma object refs to reference each other. To avoid this, you can split out the field definition for one of the relationships using builder.prismaObjectField

const Viewer = builder.prismaObject('User', {
  variant: 'Viewer',
  fields: (t) => ({
    id: t.exposeID('id'),
    user: t.variant(User),
  });
});

const User = builder.prismaNode('User', {
  interfaces: [Named],
  id: {
    resolve: (user) => user.id,
  },
  fields: (t) => ({
    email: t.exposeString('email'),
  }),
});

// Viewer references the `User` ref in its field definition,
// referencing the `User` in fields would cause a circular type issue
builder.prismaObjectField(Viewer, 'user', t.variant(User));

This same workaround applies when defining relations using variants.