PJPalJS

Prisma GraphQL Generator

Generate GraphQL fragments, queries, and mutations for Prisma models based on the schema. This generator creates complete GraphQL operations for CRUD operations on Prisma models.

View Template on GitHub

Overview

The Prisma GraphQL Generator creates client-side GraphQL operations that work seamlessly with Prisma-based GraphQL APIs. It generates:

  • GraphQL fragments for reusable field selections
  • Complete CRUD queries (findUnique, findMany, findCount)
  • Complete CRUD mutations (create, update, delete, updateMany, deleteMany)
  • Properly formatted .graphql files ready for use with GraphQL code generators

Configuration Options

The generator accepts these configuration options:

typescript
interface GraphQLGeneratorOptions {
  prismaName?: string; // Name of the Prisma client instance (default: "prisma")
  excludeFields?: string[]; // Array of field names to exclude from all models
  excludeModels?: Array<{
    // Array of model configurations with selective exclusions
    name: string;
    queries?: boolean;
    mutations?: boolean;
  }>;
  excludeFieldsByModel?: Record<string, string[]>; // Model-specific field exclusions
  excludeQueriesAndMutations?: string[]; // Global operation exclusions
  excludeQueriesAndMutationsByModel?: Record<string, string[]>; // Model-specific operation exclusions
  disableQueries?: boolean; // Boolean to disable all query generation
  disableMutations?: boolean; // Boolean to disable all mutation generation
}

Generation Pattern

For each Prisma model, the generator creates the following structure:

1. Field Fragment

graphql
fragment {ModelName}Fields on {ModelName} {
  {list all scalar fields, excluding configured excluded fields}
}

2. Complete Fragment with Relations

graphql
fragment {ModelName} on {ModelName} {
  ...{ModelName}Fields
  {for each object relation field (not list), include:}
  {relationFieldName} {
    ...{RelatedModelName}Fields
  }
}

3. Query Operations

Find Unique Query

graphql
query findUnique{ModelName}($where: {ModelName}WhereUniqueInput!) {
  findUnique{ModelName}(where: $where) {
    ...{ModelName}
  }
}

Find Many Query

graphql
query findMany{ModelName}(
  $where: {ModelName}WhereInput
  $orderBy: [{ModelName}OrderByWithRelationInput!]
  $cursor: {ModelName}WhereUniqueInput
  $skip: Int
  $take: Int
) {
  findMany{ModelName}(
    where: $where
    orderBy: $orderBy
    cursor: $cursor
    skip: $skip
    take: $take
  ) {
    ...{ModelName}
  }
}

Count Query

graphql
query findMany{ModelName}Count(
  $where: {ModelName}WhereInput
  $orderBy: [{ModelName}OrderByWithRelationInput!]
  $cursor: {ModelName}WhereUniqueInput
  $skip: Int
  $take: Int
) {
  findMany{ModelName}Count(
    where: $where
    orderBy: $orderBy
    cursor: $cursor
    skip: $skip
    take: $take
  )
}

4. Mutation Operations

Create Mutation

graphql
mutation createOne{ModelName}($data: {ModelName}CreateInput!) {
  createOne{ModelName}(data: $data) {
    ...{ModelName}
  }
}

Update Mutation

graphql
mutation updateOne{ModelName}($where: {ModelName}WhereUniqueInput!, $data: {ModelName}UpdateInput!) {
  updateOne{ModelName}(where: $where, data: $data) {
    ...{ModelName}
  }
}

Delete Mutation

graphql
mutation deleteOne{ModelName}($where: {ModelName}WhereUniqueInput!) {
  deleteOne{ModelName}(where: $where) {
    ...{ModelName}
  }
}

Delete Many Mutation

graphql
mutation deleteMany{ModelName}($where: {ModelName}WhereInput) {
  deleteMany{ModelName}(where: $where) {
    count
  }
}

Update Many Mutation

graphql
mutation updateMany{ModelName}($where: {ModelName}WhereInput, $data: {ModelName}UpdateManyMutationInput!) {
  updateMany{ModelName}(where: $where, data: $data) {
    count
  }
}

Real-World Example

Let's generate GraphQL operations for a blog application with the following Prisma schema:

Sample Prisma Schema

prisma
// schema.prisma
generator client {
  provider = "prisma-client-js"
}
 
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}
 
/// User model for blog authors and commenters
model User {
  id        String   @id @default(uuid())
  email     String   @unique
  name      String?
  /// Profile image URL
  avatar    String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
 
  // Relations
  posts    Post[]
  comments Comment[]
 
  @@map("users")
}
 
/// Blog post model
model Post {
  id        String   @id @default(uuid())
  title     String
  content   String?
  /// Whether the post is published
  published Boolean  @default(false)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
 
  // Relations
  authorId String
  author   User      @relation(fields: [authorId], references: [id])
  comments Comment[]
 
  @@map("posts")
}
 
/// Comment on blog posts
model Comment {
  id        String   @id @default(uuid())
  content   String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
 
  // Relations
  postId   String
  post     Post   @relation(fields: [postId], references: [id])
  authorId String
  author   User   @relation(fields: [authorId], references: [id])
 
  @@map("comments")
}

AI Prompt

code
I need to generate GraphQL fragments, queries, and mutations for my blog application using the PalJS patterns.

Please follow the Prisma GraphQL Generator template with this configuration:
- Output directory: src/graphql/operations
- Exclude fields: ["createdAt", "updatedAt"]
- Models to generate: ["User", "Post", "Comment"]
- Exclude mutations: ["deleteMany", "updateMany"] for all models

[Include the complete Prisma GraphQL Generator template from GitHub]

Here's my Prisma schema:
[Include the schema above]

Generate the .graphql files following the template patterns.

Generated Output

File Structure:

code
src/graphql/operations/
├── User.graphql
├── Post.graphql
└── Comment.graphql

User.graphql:

graphql
fragment UserFields on User {
  id
  email
  name
  avatar
}
 
fragment User on User {
  ...UserFields
}
 
query findUniqueUser($where: UserWhereUniqueInput!) {
  findUniqueUser(where: $where) {
    ...User
  }
}
 
query findManyUser(
  $where: UserWhereInput
  $orderBy: [UserOrderByWithRelationInput!]
  $cursor: UserWhereUniqueInput
  $skip: Int
  $take: Int
) {
  findManyUser(
    where: $where
    orderBy: $orderBy
    cursor: $cursor
    skip: $skip
    take: $take
  ) {
    ...User
  }
}
 
query findManyUserCount(
  $where: UserWhereInput
  $orderBy: [UserOrderByWithRelationInput!]
  $cursor: UserWhereUniqueInput
  $skip: Int
  $take: Int
) {
  findManyUserCount(
    where: $where
    orderBy: $orderBy
    cursor: $cursor
    skip: $skip
    take: $take
  )
}
 
mutation createOneUser($data: UserCreateInput!) {
  createOneUser(data: $data) {
    ...User
  }
}
 
mutation updateOneUser($where: UserWhereUniqueInput!, $data: UserUpdateInput!) {
  updateOneUser(where: $where, data: $data) {
    ...User
  }
}
 
mutation deleteOneUser($where: UserWhereUniqueInput!) {
  deleteOneUser(where: $where) {
    ...User
  }
}

Post.graphql:

graphql
fragment PostFields on Post {
  id
  title
  content
  published
  authorId
}
 
fragment Post on Post {
  ...PostFields
  author {
    ...UserFields
  }
}
 
query findUniquePost($where: PostWhereUniqueInput!) {
  findUniquePost(where: $where) {
    ...Post
  }
}
 
query findManyPost(
  $where: PostWhereInput
  $orderBy: [PostOrderByWithRelationInput!]
  $cursor: PostWhereUniqueInput
  $skip: Int
  $take: Int
) {
  findManyPost(
    where: $where
    orderBy: $orderBy
    cursor: $cursor
    skip: $skip
    take: $take
  ) {
    ...Post
  }
}
 
query findManyPostCount(
  $where: PostWhereInput
  $orderBy: [PostOrderByWithRelationInput!]
  $cursor: PostWhereUniqueInput
  $skip: Int
  $take: Int
) {
  findManyPostCount(
    where: $where
    orderBy: $orderBy
    cursor: $cursor
    skip: $skip
    take: $take
  )
}
 
mutation createOnePost($data: PostCreateInput!) {
  createOnePost(data: $data) {
    ...Post
  }
}
 
mutation updateOnePost($where: PostWhereUniqueInput!, $data: PostUpdateInput!) {
  updateOnePost(where: $where, data: $data) {
    ...Post
  }
}
 
mutation deleteOnePost($where: PostWhereUniqueInput!) {
  deleteOnePost(where: $where) {
    ...Post
  }
}

Usage in Frontend Applications

With GraphQL Code Generator

  1. Install dependencies:

    bash
    npm install @graphql-codegen/cli @graphql-codegen/typescript
    npm install @graphql-codegen/typescript-operations
    npm install @graphql-codegen/typescript-react-apollo
  2. Configure codegen.yml:

    yaml
    overwrite: true
    schema: "http://localhost:4000/graphql"
    documents: "src/graphql/operations/**/*.graphql"
    generates:
      src/generated/graphql.tsx:
        plugins:
          - "typescript"
          - "typescript-operations"
          - "typescript-react-apollo"
        config:
          withHooks: true
          withComponent: false
          withHOC: false
  3. Use generated hooks in React:

    tsx
    import {
      useFindManyUserQuery,
      useCreateOneUserMutation,
    } from "../generated/graphql";
     
    function UserList() {
      const { data, loading, error } = useFindManyUserQuery({
        variables: {
          where: { name: { contains: "john" } },
          take: 10,
        },
      });
     
      const [createUser] = useCreateOneUserMutation();
     
      const handleCreateUser = async () => {
        await createUser({
          variables: {
            data: {
              email: "john@example.com",
              name: "John Doe",
            },
          },
        });
      };
     
      if (loading) return <div>Loading...</div>;
      if (error) return <div>Error: {error.message}</div>;
     
      return (
        <div>
          {data?.findManyUser.map((user) => (
            <div key={user.id}>
              {user.name} - {user.email}
            </div>
          ))}
          <button onClick={handleCreateUser}>Create User</button>
        </div>
      );
    }

With Apollo Client

tsx
import { gql } from "@apollo/client";
 
// Import the generated fragments and operations
export const FIND_MANY_USER = gql`
  query findManyUser(
    $where: UserWhereInput
    $orderBy: [UserOrderByWithRelationInput!]
    $cursor: UserWhereUniqueInput
    $skip: Int
    $take: Int
  ) {
    findManyUser(
      where: $where
      orderBy: $orderBy
      cursor: $cursor
      skip: $skip
      take: $take
    ) {
      ...User
    }
  }
 
  fragment UserFields on User {
    id
    email
    name
    avatar
  }
 
  fragment User on User {
    ...UserFields
  }
`;

Field Exclusion Logic

The generator follows this logic for excluding fields:

  1. Check global excludeFields array - Fields listed here are excluded from all models
  2. Check model-specific excludeFieldsByModel[modelName] array - Fields specific to a model
  3. Exclude object fields from the Fields fragment - Relations go in the main fragment
  4. Include only scalar fields in the Fields fragment - Boolean, String, Int, DateTime, etc.

Operation Exclusion Logic

For excluding specific operations:

  1. Check global excludeQueriesAndMutations array - Operations excluded across all models
  2. Check model-specific excludeQueriesAndMutationsByModel[modelName] array - Model-specific exclusions
  3. Check if queries/mutations are globally disabled - Using disableQueries or disableMutations
  4. Check excludeModels configuration - For selective query/mutation disabling per model

Best Practices

Field Selection Strategy

  • Use fragments consistently - Always use the generated fragments for consistency
  • Exclude sensitive fields globally - Add fields like password, hash to global exclusions
  • Exclude audit fields - Fields like createdAt, updatedAt are often not needed in fragments
  • Include relation fields selectively - Only include relations that are commonly queried together

Performance Considerations

  • Use pagination variables - Always provide take and skip for large datasets
  • Implement cursor-based pagination - Use cursor for efficient pagination
  • Add proper WHERE filters - Use the where parameter to filter data at the database level
  • Order results consistently - Use orderBy to ensure predictable results

Error Handling

  • Handle loading states - Show loading indicators during queries
  • Display error messages - Provide user-friendly error messages
  • Implement retry logic - Handle network failures gracefully
  • Validate inputs - Use TypeScript types for compile-time safety

Common Use Cases

1. User Management System

graphql
# Get user profile with posts
query getUserProfile($userId: String!) {
  findUniqueUser(where: { id: $userId }) {
    ...UserFields
    posts {
      ...PostFields
    }
  }
}

2. Blog Post Listing

graphql
# Get published posts with authors
query getPublishedPosts($skip: Int, $take: Int) {
  findManyPost(
    where: { published: true }
    orderBy: [{ createdAt: desc }]
    skip: $skip
    take: $take
  ) {
    ...PostFields
    author {
      ...UserFields
    }
  }
}

3. Comment Thread

graphql
# Get comments for a post
query getPostComments($postId: String!) {
  findManyComment(where: { postId: $postId }, orderBy: [{ createdAt: asc }]) {
    ...CommentFields
    author {
      ...UserFields
    }
  }
}

Next Steps

Command Palette

Search for a command to run...