Prisma2:如何使用Paljs解决n +1问题

问题描述

任何帮助。

我在前端使用apollo客户端,在后端graphql-nexus使用prisma2和graphql-yoga服务器。

我想用@ paljs / plugins解决n + 1问题。

在前端,我有一个查询帖子,例如:

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
        }
    }
}

帖子解析器:

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
  },})

我记录查询

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

我的问题:使用prismaSelect时,我有5个查询,而如果不检查前端的请求时间,则需要300-400ms。所以我做错了什么? 我在@paljs/plugins文档中看到了上下文中的选择。也许那是我的错误。如何在上下文中使用选择?

这里是我的上下文:

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 }
}

解决方法

您需要知道,要使用我的PrismaSelect插件,您需要删除nexus-prisma-plugin程序包,并使用我的Pal.js CLI为nexus创建您的CRUD和ObjectType并使用@paljs/nexus插件以添加mackSchema函数

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',});

现在将此类型添加到您的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: {} }
}

添加我们的插件后,您的查询将像这样记录


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,});
      },});
  },});

能否请您尝试使用我的pal c命令从列表中启动示例,并尝试使用它进行模式测试

,

工作正常,谢谢艾哈迈德,您的插件太棒了!!!!

我从更改了后对象

const Post = objectType({
  name: 'Post',definition(t) {
    t.model.id()
    t.model.authorId()
    t.model.tags()
    t.model.games()
    t.model.link()
    t.model.report()
    t.model.notifications()
    t.model.author()
    t.model.favoritedBy({
      filtering: {
        id: true,})
    t.model.likes({
      filtering: {
        user: true,})
  }
})

const Post = objectType({
  name: 'Post',definition(t) {
    t.string('id')
    t.field('tags',{
      nullable: false,list: [true],type: 'Tag',resolve(parent: any) {
        return parent['tags']
      },})
    t.field('games',{
      list: [true],type: 'Game',resolve(parent: any) {
        return parent['games']
      },})
    t.field('link',{
      type: 'Link',resolve(parent: any) {
        return parent['link']
      },})
    t.field('notifications',type: 'Notification',resolve(parent: any) {
        return parent['notifications']
      },})
    t.field('author',type: 'User',resolve(parent: any) {
        return parent['author']
      },})
    t.field('favoritedBy',args: {
        where: 'UserWhereInput',resolve(parent: any) {
        return parent['favoritedBy']
      },})
    t.field('likes',type: 'Like',args: {
        where: 'LikeWhereInput',resolve(parent: any) {
        return parent['likes']
      },})
  },})

我还同时使用了nexus-prisma-plugin和paljs-plugin