Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prototype create and update input types for prisma #703

Merged
merged 23 commits into from
Mar 20, 2023

Conversation

hayes
Copy link
Owner

@hayes hayes commented Dec 10, 2022

This adds support for new utils for creating Create/Update input types.

To test this out install the snapshot packages below:
🦋 @pothos/plugin-prisma@0.0.0-preview-20230107233924
🦋 @pothos/plugin-prisma-utils@0.0.0-preview-20230107233924

New methods:

  • builder.prismaCreate
    • Creates an input for a create mutation (eg UserCreateInput)
  • builder.prismaCreateRelation
    • Creates an input type for a relation field in a create (eg PostCreateNestedManyWithoutAuthorInput)
    • This is intended to be used as a field inside a builder.prismaCreate
  • builder.prismaWhereUnique
    • Creates a unique filter for the given model (eg UserWhereUniqueInput)
  • builder.prismaUpdate
    • Creates an input for an update mutation (eg UserUpdate)
  • builder.prismaUpdateRelation
    • Creates an input type for a relation field in an update (eg PostUpdateManyWithoutAuthorNestedInput)

example usage:

// Create a few nested input types that support a subset of specifically selected fields
const CreateUserPostsInput = builder.prismaCreateRelation('User', 'posts', {
  fields: () => ({
    create: CreatePostInput,
    connect: PostWhereUnique,
  }),
});

const CreateUserInput = builder.prismaCreate('User', {
  fields: () => ({
    email: 'String',
    name: 'String',
    posts: CreateUserPostsInput,
  }),
});

const PostWhereUnique = builder.prismaWhereUnique('Post', {
  name: 'PostWhereUnique',
  fields: {
    id: 'Int',
  },
});

const CreatePostInput = builder.prismaCreate('Post', {
  fields: {
    title: 'String',
  },
});

builder.prismaObject('User', {
  fields: (t) => ({
    id: t.exposeID('id'),
    email: t.exposeString('email'),
    posts: t.relation('posts'),
  }),
});

builder.mutationType({
  fields: (t) => ({
    createUser: t.prismaField({
      type: 'User',
      args: {
        data: t.arg({ type: CreateUserInput, required: true }),
      },
      resolve: (query, _, args) => prisma.user.create({ ...query, data: args.data }),
    }),
  }),
});

Example generator

Here is an example generator class that can be used with @pothos/plugin-prisma-utils to automatically generate input types following some reasonable conventions. This can be modified to fit the patterns and use cases that make sense for your app:

Click here to expand generator code
import {
  BaseEnum,
  EnumRef,
  InputObjectRef,
  InputType,
  InputTypeParam,
  SchemaTypes,
} from '@pothos/core';
import { getModel, PrismaModelTypes } from '@pothos/plugin-prisma';
import { FilterOps } from '../../../src';
import * as Prisma from '../../client';

const filterOps = ['equals', 'in', 'notIn', 'not', 'is', 'isNot'] as const;
const sortableFilterProps = ['lt', 'lte', 'gt', 'gte'] as const;
const stringFilterOps = [...filterOps, 'contains', 'startsWith', 'endsWith'] as const;
const sortableTypes = ['String', 'Int', 'Float', 'DateTime', 'BigInt'] as const;
const listOps = ['every', 'some', 'none'] as const;

export class PrismaCrudGenerator<Types extends SchemaTypes> {
  private builder;

  private refCache = new Map<string | InputType<Types>, Map<string, InputObjectRef<unknown>>>();
  private enumRefs = new Map<string, EnumRef<unknown>>();

  constructor(builder: PothosSchemaTypes.SchemaBuilder<Types>) {
    this.builder = builder;
  }

  findManyArgs<Name extends keyof Types['PrismaTypes'] & string>(modelName: Name) {
    return this.builder.args((t) => ({
      filter: t.field({
        type: this.getWhere(modelName),
        required: false,
      }),
      orderBy: t.field({
        type: this.getOrderBy(modelName),
        required: false,
      }),
    }));
  }

  getWhere<Name extends keyof Types['PrismaTypes'] & string>(modelName: Name, without?: string[]) {
    const withoutName = (without ?? []).map((name) => `Without${capitalize(name)}`).join('');
    const fullName = `${modelName}${withoutName}Filter`;

    return this.getRef(modelName, fullName, () => {
      const model = getModel(modelName, this.builder);

      return this.builder.prismaWhere(modelName, {
        name: fullName,
        fields: () => {
          const fields: Record<string, InputType<Types>> = {};
          const withoutFields = model.fields.filter((field) => without?.includes(field.name));

          model.fields
            .filter(
              (field) =>
                !withoutFields.some(
                  (f) => f.name === field.name || f.relationFromFields?.includes(field.name),
                ),
            )
            .forEach((field) => {
              let type;
              switch (field.kind) {
                case 'scalar':
                  type = this.mapScalarType(field.type) as InputType<Types>;
                  break;
                case 'enum':
                  type = this.getEnum(field.type);
                  break;
                case 'object':
                  type = this.getWhere(field.type as Name);
                  break;
                case 'unsupported':
                  break;
                default:
                  throw new Error(`Unknown field kind ${field.kind}`);
              }

              if (!type) {
                return;
              }

              const filter = field.kind === 'object' ? type : this.getFilter(type);

              if (field.isList) {
                fields[field.name] = this.getListFilter(filter);
              } else {
                fields[field.name] = filter;
              }
            });

          return fields as {};
        },
      }) as InputObjectRef<(Types['PrismaTypes'][Name] & PrismaModelTypes)['Where']>;
    });
  }

  getWhereUnique<Name extends keyof Types['PrismaTypes'] & string>(modelName: Name) {
    const name = `${modelName}UniqueFilter`;

    return this.getRef(modelName, name, () => {
      const model = getModel(modelName, this.builder);

      return this.builder.prismaWhereUnique(modelName, {
        name,
        fields: () => {
          const fields: Record<string, InputType<Types>> = {};

          model.fields
            .filter(
              (field) =>
                field.isUnique ||
                field.isId ||
                model.uniqueIndexes.some((index) => index.fields.includes(field.name)) ||
                model.primaryKey?.fields.includes(field.name),
            )
            .forEach((field) => {
              let type;
              switch (field.kind) {
                case 'scalar':
                  type = this.mapScalarType(field.type) as InputType<Types>;
                  break;
                case 'enum':
                  type = this.getEnum(field.type);
                  break;
                case 'object':
                  type = this.getWhere(field.type as Name);
                  break;
                case 'unsupported':
                  break;
                default:
                  throw new Error(`Unknown field kind ${field.kind}`);
              }

              if (!type) {
                return;
              }

              fields[field.name] = type;
            });

          return fields as {};
        },
      }) as InputObjectRef<(Types['PrismaTypes'][Name] & PrismaModelTypes)['WhereUnique']>;
    });
  }

  getOrderBy<Name extends keyof Types['PrismaTypes'] & string>(modelName: Name) {
    const name = `${modelName}OrderBy`;
    return this.getRef(modelName, name, () => {
      const model = getModel(modelName, this.builder);

      return this.builder.prismaOrderBy(modelName, {
        name,
        fields: () => {
          const fields: Record<string, InputType<Types> | boolean> = {};

          model.fields.forEach((field) => {
            let type;
            switch (field.kind) {
              case 'scalar':
              case 'enum':
                type = true;
                break;
              case 'object':
                type = this.getOrderBy(field.type as Name);
                break;
              case 'unsupported':
                break;
              default:
                throw new Error(`Unknown field kind ${field.kind}`);
            }

            if (type) {
              fields[field.name] = type;
            }
          });

          return fields as {};
        },
      });
    });
  }

  getCreateInput<Name extends keyof Types['PrismaTypes'] & string>(
    modelName: Name,
    without?: string[],
  ) {
    const withoutName = (without ?? []).map((name) => `Without${capitalize(name)}`).join('');
    const fullName = `${modelName}Create${withoutName}Input`;

    return this.getRef(modelName, fullName, () => {
      const model = getModel(modelName, this.builder);
      return this.builder.prismaCreate(modelName, {
        name: fullName,
        fields: (t) => {
          const fields: Record<string, InputTypeParam<Types>> = {};
          const withoutFields = model.fields.filter((field) => without?.includes(field.name));
          const relationIds = model.fields.flatMap((field) => field.relationFromFields ?? []);

          model.fields
            .filter(
              (field) =>
                !withoutFields.some(
                  (f) => f.name === field.name || f.relationFromFields?.includes(field.name),
                ) && !relationIds.includes(field.name),
            )
            .forEach((field) => {
              let type;
              switch (field.kind) {
                case 'scalar':
                  type = this.mapScalarType(field.type) as InputType<Types>;
                  break;
                case 'enum':
                  type = this.getEnum(field.type);
                  break;
                case 'object':
                  type = this.getCreateRelationInput(modelName, field.name);
                  break;
                case 'unsupported':
                  break;
                default:
                  throw new Error(`Unknown field kind ${field.kind}`);
              }

              if (type) {
                fields[field.name] = type;
              }
            });

          return fields as {};
        },
      }) as InputObjectRef<(Types['PrismaTypes'][Name] & PrismaModelTypes)['Create']>;
    });
  }

  getCreateRelationInput<
    Name extends keyof Types['PrismaTypes'] & string,
    Relation extends Model['RelationName'],
    Model extends PrismaModelTypes = Types['PrismaTypes'][Name] extends PrismaModelTypes
      ? Types['PrismaTypes'][Name]
      : never,
  >(modelName: Name, relation: Relation) {
    return this.getRef(`${modelName}${capitalize(relation)}`, 'CreateRelationInput', () => {
      const model = getModel(modelName, this.builder);
      return this.builder.prismaCreateRelation(modelName, relation, {
        fields: () => {
          const relationField = model.fields.find((field) => field.name === relation)!;
          const relatedModel = getModel(relationField.type, this.builder);
          const relatedFieldName = relatedModel.fields.find(
            (field) => field.relationName === relationField.relationName,
          )!;

          return {
            create: this.getCreateInput(relatedModel.name as Name, [relatedFieldName.name]),
            connect: this.getWhereUnique(relatedModel.name as Name),
          };
        },
      } as never) as InputObjectRef<NonNullable<Model['Create'][Relation & keyof Model['Update']]>>;
    });
  }

  getUpdateInput<Name extends keyof Types['PrismaTypes'] & string>(
    modelName: Name,
    without?: string[],
  ) {
    const withoutName = (without ?? []).map((name) => `Without${capitalize(name)}`).join('');
    const fullName = `${modelName}Update${withoutName}Input`;

    return this.getRef(modelName, fullName, () => {
      const model = getModel(modelName, this.builder);
      return this.builder.prismaUpdate(modelName, {
        name: fullName,
        fields: () => {
          const fields: Record<string, InputTypeParam<Types>> = {};
          const withoutFields = model.fields.filter((field) => without?.includes(field.name));
          const relationIds = model.fields.flatMap((field) => field.relationFromFields ?? []);

          model.fields
            .filter(
              (field) =>
                !withoutFields.some(
                  (f) => f.name === field.name || f.relationFromFields?.includes(field.name),
                ) && !relationIds.includes(field.name),
            )
            .forEach((field) => {
              let type;
              switch (field.kind) {
                case 'scalar':
                  type = this.mapScalarType(field.type) as InputType<Types>;
                  break;
                case 'enum':
                  type = this.getEnum(field.type);
                  break;
                case 'object':
                  type = this.getUpdateRelationInput(modelName, field.name);
                  break;
                case 'unsupported':
                  break;
                default:
                  throw new Error(`Unknown field kind ${field.kind}`);
              }

              if (type) {
                fields[field.name] = type;
              }
            });

          return fields as {};
        },
      }) as InputObjectRef<(Types['PrismaTypes'][Name] & PrismaModelTypes)['Update']>;
    });
  }

  getUpdateRelationInput<
    Name extends keyof Types['PrismaTypes'] & string,
    Relation extends Model['RelationName'],
    Model extends PrismaModelTypes = Types['PrismaTypes'][Name] extends PrismaModelTypes
      ? Types['PrismaTypes'][Name]
      : never,
  >(modelName: Name, relation: Relation) {
    return this.getRef(`${modelName}${capitalize(relation)}`, 'UpdateRelationInput', () => {
      const model = getModel(modelName, this.builder);
      return this.builder.prismaUpdateRelation(modelName, relation, {
        fields: () => {
          const relationField = model.fields.find((field) => field.name === relation)!;
          const relatedModel = getModel(relationField.type, this.builder);
          const relatedFieldName = relatedModel.fields.find(
            (field) => field.relationName === relationField.relationName,
          )!.name;

          if (relationField.isList) {
            return {
              create: this.getCreateInput(relationField.type as Name, [relatedFieldName]),
              set: this.getWhereUnique(relationField.type as Name),
              disconnect: this.getWhereUnique(relationField.type as Name),
              delete: this.getWhereUnique(relationField.type as Name),
              connect: this.getWhereUnique(relationField.type as Name),
              update: {
                where: this.getWhereUnique(relationField.type as Name),
                data: this.getUpdateInput(relationField.type as Name, [relatedFieldName]),
              },
              updateMany: {
                where: this.getWhere(relationField.type as Name, [relatedFieldName]),
                data: this.getUpdateInput(relationField.type as Name, [relatedFieldName]),
              },
              deleteMany: this.getWhere(relationField.type as Name, [relatedFieldName]),
            };
          }

          return {
            create: this.getCreateInput(relationField.type as Name, [relatedFieldName]),
            update: this.getUpdateInput(relationField.type as Name, [relatedFieldName]),
            connect: this.getWhereUnique(relationField.type as Name),
            disconnect: relationField.isRequired ? undefined : 'Boolean',
            delete: relationField.isRequired ? undefined : 'Boolean',
          };
        },
      } as never) as InputObjectRef<NonNullable<Model['Update'][Relation & keyof Model['Update']]>>;
    });
  }

  private getFilter(type: InputType<Types>) {
    return this.getRef(type, `${String(type)}Filter`, () => {
      const ops: FilterOps[] = [...filterOps];

      if (type === 'String') {
        ops.push(...stringFilterOps);
      }
      if (sortableTypes.includes(type as never)) {
        ops.push(...sortableFilterProps);
      }

      return this.builder.prismaFilter(type, {
        ops,
      });
    });
  }

  private getListFilter(type: InputType<Types>) {
    return this.getRef(type, `${String(type)}Filter`, () =>
      this.builder.prismaListFilter(type, {
        ops: listOps,
      }),
    );
  }

  private getEnum(name: string) {
    if (!this.enumRefs.has(name)) {
      const enumRef = this.builder.enumType((Prisma as unknown as Record<string, BaseEnum>)[name], {
        name,
      });

      this.enumRefs.set(name, enumRef);
    }

    return this.enumRefs.get(name)!;
  }

  private mapScalarType(type: string) {
    switch (type) {
      case 'String':
      case 'Boolean':
      case 'Int':
      case 'Float':
      case 'DateTime':
        return type;
      default:
        return null;
    }
  }

  private getRef<T extends InputObjectRef<unknown>>(
    key: string | InputType<Types>,
    name: string,
    create: () => T,
  ): T {
    if (!this.refCache.has(key)) {
      this.refCache.set(key, new Map());
    }
    const cache = this.refCache.get(key)!;

    if (cache.has(name)) {
      return cache.get(name)! as T;
    }

    const ref = new InputObjectRef(name);

    cache.set(name, ref);

    this.builder.configStore.associateRefWithName(ref, create().name);

    return ref as T;
  }
}

function capitalize(str: string) {
  return str[0].toUpperCase() + str.slice(1);
}

Generator ussage

import builder, { prisma } from '../builder';
import { PrismaCrudGenerator } from '../generator';

const generator = new PrismaCrudGenerator(builder);

builder.scalarType('DateTime', {
  serialize: (value) => value.toISOString(),
  parseValue: (value) => (typeof value === 'number' ? new Date(value) : new Date(String(value))),
});

builder.queryType({
  fields: (t) => ({
    posts: t.prismaField({
      type: ['Post'],
      args: generator.findManyArgs('Post'),
      resolve: (query, _, args) =>
        prisma.post.findMany({
          ...query,
          where: args.filter ?? undefined,
          orderBy: args.orderBy ?? undefined,
          take: 3,
        }),
    }),
  }),
});

builder.mutationType({
  fields: (t) => ({
    createUser: t.prismaField({
      type: 'User',
      args: { input: t.arg({ type: generator.getCreateInput('User'), required: true }) },
      resolve: (query, _, args) =>
        prisma.user.create({
          ...query,
          data: {
            ...args.input,
          },
        }),
    }),
    updateUser: t.prismaField({
      type: 'User',
      args: {
        where: t.arg({ type: generator.getWhereUnique('User'), required: true }),
        data: t.arg({ type: generator.getUpdateInput('User'), required: true }),
      },
      resolve: (query, _, args) =>
        prisma.user.update({
          ...query,
          where: {
            ...args.where,
          },
          data: {
            ...args.data,
          },
        }),
    }),
  }),
});

builder.prismaObject('Post', {
  fields: (t) => ({
    id: t.exposeID('id'),
    author: t.relation('author'),
    comments: t.relation('comments', {
      args: generator.findManyArgs('Comment'),
      query: (args) => ({
        where: args.filter ?? undefined,
        orderBy: args.orderBy ?? undefined,
        take: 2,
      }),
    }),
  }),
});

builder.prismaObject('Comment', {
  fields: (t) => ({
    id: t.exposeID('id'),
    content: t.exposeString('content'),
    author: t.relation('author'),
    post: t.relation('post'),
  }),
});

builder.prismaObject('User', {
  fields: (t) => ({
    id: t.exposeID('id'),
    name: t.exposeString('name', { nullable: true }),
    email: t.exposeString('email'),
    comments: t.relation('comments'),
    posts: t.relation('posts', {
      args: generator.findManyArgs('Post'),
      query: (args) => ({
        where: args.filter ?? undefined,
        orderBy: args.orderBy ?? undefined,
        take: 2,
      }),
    }),
  }),
});

export default builder.toSchema();

@vercel
Copy link

vercel bot commented Dec 10, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated
pothos ✅ Ready (Inspect) Visit Preview 💬 Add your feedback Mar 20, 2023 at 6:13AM (UTC)

@changeset-bot
Copy link

changeset-bot bot commented Dec 10, 2022

🦋 Changeset detected

Latest commit: 132b6dd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 8 packages
Name Type
@pothos-examples/complex-app Minor
@pothos/plugin-prisma Minor
@pothos/plugin-prisma-utils Minor
@pothos-examples/prisma-federation Patch
@pothos-examples/prisma-relay Patch
@pothos-examples/prisma-smart-subscriptions-apollo Patch
@pothos-examples/prisma-subscriptions Patch
@pothos-examples/prisma Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@hayes hayes marked this pull request as ready for review December 11, 2022 03:14
@hayes hayes changed the title wip - prototype create and update input types for prisma prototype create and update input types for prisma Dec 11, 2022
@LawJolla
Copy link

LawJolla commented Jan 4, 2023

Thank you @hayes this has been so helpful.

I have found one issue that I'm not bright enough to fix. Happy to make a repo if needed.

for getUpdateInput("Post"), the nested field should return an object instead of an array and nested updates aren't returning where and data fields. E.g. a post with nested comments returns...

 post: { 
   ...
   comments: [
       connect: [...],
       create: [...],
       delete: [...],
       deleteMany: [...],
       disconnect: [...],
       set: [...],
       update: [
            id: ID!
            ...other comment fields
        ] // CommentUpdateWithoutCommentInput,
       updateMany: [...],
   ]
}

But for Prisma to update we need...

 post: { 
   ...
   comments: { // object, not array
       connect: [...],
       create: [...],
       delete: [...],
       deleteMany: [...],
       disconnect: [...],
       set: [...],
       update: [
            { where:  CommentWhereUniqueInput, data: CommentUpdateWithoutCommentInput}
        ] 
       updateMany: [...],
   }
}

Did that make any sense?

@hayes
Copy link
Owner Author

hayes commented Jan 6, 2023

@LawJolla yup! Great catch, makes total sense. This is definitely an oversight on my part. There are so many different combinations of options for mutating relations. This should be pretty straightforward to fix, I'll try to look into it this weekend.

@LawJolla
Copy link

LawJolla commented Jan 6, 2023

@LawJolla yup! Great catch, makes total sense. This is definitely an oversight on my part. There are so many different combinations of options for mutating relations. This should be pretty straightforward to fix, I'll try to look into it this weekend.

Terrific thank you!

I did find one other. For Enum lists, Prisma Client adds push/set methods, e.g.

model User {
   ...
   roles: RoleEnum[]
}
...
prisma.user.update({
   where: { id: "1"}
   data: { roles: { set: [RoleEnum.Admin, RoleEnum.User] } }
})

The generator.getUpdateInput("User") is generating...

type UserUpdateInput {
   ...
   roles: RolesEnum
}

vs

type UserUpdateInput {
   ...
   roles: Prisma.UserUpdaterolesInput | Prisma.Enumerable<RolesEnum> | undefined
}

Happy to test any of it if you get a moment! Thanks as always.

@hayes
Copy link
Owner Author

hayes commented Jan 6, 2023

Cool, was just opening branch again to check this out

@hayes
Copy link
Owner Author

hayes commented Jan 7, 2023

@LawJolla just published new snapshots (PR description has been updated) and also updated the example generator code.

For update and updateMany on list relations, the fields now take an array of update objects that have where and data.

For non-relation list fields, the builder now takes an array of values. prisma can update enum lists either using { set: [a,b,c] } or by just passing the list directly. I opted for passing the list directly in the generator for now because it's a lot easier to implement. This does mean push as an update option is not supported right now. I did also notice that I haven't added filter options for scalar lists yet

@hayes
Copy link
Owner Author

hayes commented Jan 7, 2023

unfortunately sqlite doesn't support enums or scalar lists, so those are features I haven't really tested. I probably need to set up a way to test against postgres or something as well

@thuperthecret2
Copy link

thuperthecret2 commented Jan 7, 2023

I use railway.app to set up a free postgres test server and it seems to work great, and I can connect to it fine using PGAdmin.

In schema.prisma:

datasource db {
  provider = "postgresql"
  url      = "postgresql://postgres:thepassword@containers-us-west-blah.railway.app:1234/railway"
}

@thuperthecret2
Copy link

For generated input types that are ending up in the graphql schema I think a well-known convention is to suffix them with "Input" for example "UserCreateInput" instead of "UserCreate". Seems I'm just getting "UserCreate" from I believe this line of code:
const ref = this.inputRef<Model['Create']>(name ?? ${nameFromType(type, this)}Create);

@LawJolla
Copy link

LawJolla commented Jan 7, 2023

@LawJolla just published new snapshots (PR description has been updated) and also updated the example generator code.

For update and updateMany on list relations, the fields now take an array of update objects that have where and data.

For non-relation list fields, the builder now takes an array of values. prisma can update enum lists either using { set: [a,b,c] } or by just passing the list directly. I opted for passing the list directly in the generator for now because it's a lot easier to implement. This does mean push as an update option is not supported right now. I did also notice that I haven't added filter options for scalar lists yet

Awesome work! Can confirm it's working on my big mono repo.

The only issue remaining is nested relation methods are objects instead of arrays. E.g. doesn't work as an array
Explorer Sandbox Studio 2023-01-07 at 3 26 48 PM

Maybe better illustrated in Prisma Client. lineItems delete as an object vs users array
wk-mono-repo – updateDeal ts 2023-01-07 at 3 27 51 PM

@hayes
Copy link
Owner Author

hayes commented Jan 7, 2023

@LawJolla just published a new version and posted an updated generator that fixes a bunch more issues.

@thuperthecret2 updated some more of the input types to end with Input. All the input types should now end with Input, Filter, or OrderBy

@LawJolla
Copy link

Thanks @hayes ! Almost there. I've only found a few more minor issues and am happy to make a repo if needed.

On the Create and Updates, booleans are not available. E.g.

model User {
 id: ID!
 ...
  isAdmin: boolean
}

Using the generator getUpdateInput("User") and getCreateInput("User") will not expose isAdmin under data.

Otherwise I have everything working and it's awesome! Thank you again.

@hayes
Copy link
Owner Author

hayes commented Jan 29, 2023

Cool! Will look at getting that fixed tomorrow or Monday. On my end I have a couple more things to finish up, but should be able to release this soon. Working on a codegen version of the generator that statically generates the Pothos definitions rather than doing it at run time, and need to add a flag to the Prisma generator to avoid generating the extra types when only using the main plugin (including the types for updates in the generated types adds a lot of new types into the Prisma types that can slow down type checking on large schemas)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants