Search code examples
graphqlapollo-clientprisma2

Prisma2: How to solve n +1 Problem with Paljs


thx for any help.

Im using at the frontend the apollo-client and at the backend graphql-nexus,prisma2 and graphql-yoga server.

I want to solve the n + 1 problem with @paljs/plugins.

At the frontend I have a query posts like:

query posts{
    posts {
        id
        favoritedBy(where: { id: { equals: $currentUserId } }) {
            id
        }
        author {
            id
            avatar {
                id
            }
        }
        link {
            id
        }
        games {
            id
        }
        tags {
            id
        }
        likes(where: { user: { id: { equals: $currentUserId } } }) {
            id
        }
    }
}

Posts resolver:

import { PrismaSelect } from '@paljs/plugins'
export const posts = queryField('posts', {
  type: 'Post',
  list: true,
  args: {
    ...
  },
  resolve: async (_parent, args, { prisma, request }, info) => {
    const select = new PrismaSelect(info).value
    let opArgs: FindManyPostArgs = {
      take: 10,
      orderBy: {
        [args.orderBy]: 'desc',
      },
      ...select
    }

    const post = await prisma.post.findMany(opArgs)
    
    //The result I want to return with the "sub-models" like likes, author tags...
    console.log(JSON.stringify(post, undefined, 2))

    return post
  },
})

I logging the queries

const prisma = new PrismaClient({
  log: ['query'],
})

My Problem: With PrismaSelect, I have 5 queries more than without and If I check the request-time at the frontend I need 300-400ms longer with PrismaSelect. So what I'm doing wrong? I saw in the @paljs/plugins doc the select in the context. Maybe that is my mistake. How can I use the select in the context?

Here ist my Context:

import { PrismaClient, PrismaClientOptions } from '@prisma/client'
import { PubSub } from 'graphql-yoga'
import { PrismaDelete, onDeleteArgs } from '@paljs/plugins'

class Prisma extends PrismaClient {
  constructor(options?: PrismaClientOptions) {
    super(options)
  }

  async onDelete(args: onDeleteArgs) {
    const prismaDelete = new PrismaDelete(this)
    await prismaDelete.onDelete(args)
  }
}

export const prisma = new PrismaClient({
  log: ['query'],
})
export const pubsub = new PubSub()

export interface Context {
  prisma: PrismaClient
  request: any
  pubsub: PubSub
}

export function createContext(request: any): Context {
  return { prisma, request, pubsub }
}

Solution

  • You need to know that to use my PrismaSelect plugin you need to remove the nexus-prisma-plugin package and use my Pal.js CLI to create your CRUD and ObjectType for nexus and using @paljs/nexus plugin to add in mackSchema function

    import { makeSchema } from '@nexus/schema';
    import * as types from './graphql';
    import { paljs } from '@paljs/nexus'; // import our plugin
    
    export const schema = makeSchema({
      types,
      plugins: [paljs()],// here our plugin don't use nexus-prisma-plugin
      outputs: {
        schema: __dirname + '/generated/schema.graphql',
        typegen: __dirname + '/generated/nexus.ts',
      },
      typegenAutoConfig: {
        sources: [
          {
            source: require.resolve('./context'),
            alias: 'Context',
          },
        ],
        contextType: 'Context.Context',
      },
    });
    

    Now add this type to your Context

    export interface Context {
      prisma: PrismaClient
      request: any
      pubsub: PubSub
      select: any // here our select type
    }
    export function createContext(request: any): Context {
    // our paljs plugin will add select object before resolver
      return { prisma, request, pubsub, select: {} }
    }
    

    after you add our plugin your query will log like this

    
    extendType({
      type: 'Query',
      definition(t) {
        t.field('findOneUser', {
          type: 'User',
          nullable: true,
          args: {
            where: arg({
              type: 'UserWhereUniqueInput',
              nullable: false,
            }),
          },
          resolve(_, { where }, { prisma, select }) {
    // our plugin add select object into context for you
            return prisma.user.findOne({
              where,
              ...select,
            });
          },
        });
      },
    });
    

    Can you please try to use my pal c command to start an example from my list and try your schema and make tests with it