Prisma и ApolloClient: предотвращение перезаписи условий включения в серверной части интерфейсом для отношений.

У меня проблема, спасибо за любую помощь.

С помощью prisma мы можем использовать условия include with where для моделей с отношением. Если я сделаю условия включения, я получу правильный результат. Если я верну его во внешний интерфейс, он будет перезаписан. Я хочу вернуть свой результат из бэкэнда.

У меня на интерфейсе есть запрос (ApolloClient, gql) вроде. Он вернет массив комментариев для каждого сообщения, я просто хочу иметь первый комментарий для каждого сообщения.

const POSTS = gql`
    query posts {
        posts(postId: $postId) {
            id
            comments{ // at the backend I have conditions for the comments
              id
            }
        }
    }
`;

Бэкэнд: Primsa и graphql nexus

Схема призмы

model Post {
  id            String         @id @default(cuid())
  comments      Comment[]
}

model Comment {
  id            String         @id @default(cuid())
  post          Post           @relation(fields: [postId], references: [id])
  postId        String
}

Модель Nexus

const Post = objectType({
  name: 'Post',
  definition(t) {
    t.model.id()
    t.model.comments()
})

const Comment = objectType({
  name: 'Comment',
  definition(t) {
    t.model.id()
    t.model.post()
    t.model.postId()
})

Резольвер

export const posts = queryField('posts', {
  type: 'Post',
  list: true,
  args: {
    ...
  },
  resolve: async (_parent, args: any, { prisma, request }, info) => {
    
     const posts = await prisma.post.findMany({
      include: {
        comments: {
          take: 1
        }
      }
    })

    console.log(posts) 
    //Perfect result I want to return the include condition. But at the frontend I have all 
    //comments
    return posts
  },
})

Console.log (сообщения) - это именно то, что я хочу вернуть !. У каждого сообщения есть массив ОДНОГО комментария. Я возвращаю сообщения, и на интерфейсе у каждого сообщения есть Массив ВСЕХ комментариев, чего я не хочу. Как я могу предотвратить перезапись запросом внешнего интерфейса возвращаемого значения серверного интерфейса? Поля такие же.


person Tölz    schedule 21.09.2020    source источник
comment
Было бы здорово, если бы вы могли поделиться своими моделями Nexus для Post и Comment.   -  person Ryan    schedule 22.09.2020


Ответы (3)


Я не могу добавить комментарий, поэтому добавляю это к другому ответу.

Как я уже сказал с моим PrismaSelect плагином, вы не можете использовать nexus-plugin-prisma t.model, t.crud. Вам нужно будет использовать CLI Pal.Js для автоматического создания всех CRUD и ObjectTypes для всех моделей.

const Post = objectType({
  name: 'Post',
  definition(t) {
    t.model.id()
    t.model.comments() // this field will overwritten by next one so this not needed
     t.list.field('comments', {
      type: 'Comment',
      list: true,
      resolve: (parent, args, { prisma }) => {
// here parent type include all other fields but not this field 
        return prisma.comment.findMany({ // this query is very wrong will case N+1 issue
          where: {
            postId: parent.id,
          },
          take: 1,
        })
      },
    })
})

Пример

model User {
  id        Int       @default(autoincrement()) @id
  createdAt DateTime  @default(now())
  email     String    @unique
  name      String?
  password  String
  posts     Post[]
  comments  Comment[]
}

model Post {
  id        Int       @default(autoincrement()) @id
  published Boolean   @default(false)
  title     String
  author    User?     @relation(fields: [authorId], references: [id])
  authorId  Int?
  comments  Comment[]
}

model Comment {
  id        Int      @default(autoincrement()) @id
  contain   String
  post      Post     @relation(fields: [postId], references: [id])
  postId    Int
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}

Вот мой тип, сгенерированный CLI Pal.Js для модели Post

import { objectType } from '@nexus/schema'

export const Post = objectType({
  name: 'Post',
  definition(t) {
    t.int('id', { nullable: false })
    t.boolean('published', { nullable: false })
    t.string('title', { nullable: false })
    t.field('author', {
      nullable: true,
      type: 'User',
      resolve(parent: any) {
        return parent['author']
      },
    })
    t.int('authorId', { nullable: true })
    t.field('comments', {
      nullable: false,
      list: [true],
      type: 'Comment',
      args: {
        where: 'CommentWhereInput',
        orderBy: 'CommentOrderByInput',
        cursor: 'CommentWhereUniqueInput',
        take: 'Int',
        skip: 'Int',
        distinct: 'CommentDistinctFieldEnum',
      },
      resolve(parent: any) {
        return parent['comments']
      },
    })
  },
})

когда вы используете мой CLI Pal.js, ваш запрос внешнего интерфейса будет таким

query {
  findOnePost(where: {id: 1}) {
   comments(where: {}, take: 1){
    id
   }
  }
}
``
person Ahmed Elywa    schedule 07.10.2020

Лучший способ решить эту проблему - просто запросить, какой из запросов вашего внешнего интерфейса использовать мой PrismaSelect. Prisma Select принимает объект info: GraphQLResolveInfo в общих аргументах graphql (родительский, аргументы, контекст, информация) для выбора объекта, принятого prisma client. Такой подход обеспечивает лучшую производительность, поскольку вы будете использовать только один преобразователь для получения всего вашего запроса. Таким образом, это также устраняет проблему N + 1.

Кроме того, вы можете использовать мой интерфейс командной строки для автоматического создания всех CRUD из файла schema.prisma https://paljs.com/generator/nexus

person Ahmed Elywa    schedule 04.10.2020
comment
Спасибо за ваш ответ и за ваш замечательный плагин. Это помогло мне с проблемой удаления. Я задал новый вопрос с проблемой n +1. Надеюсь, ты сможешь мне помочь. (stackoverflow.com/questions/64248004/) - person Tölz; 07.10.2020

Я имею в виду, что могу добавить в свой Post-ObjectType условие поля, например:

const Post = objectType({
  name: 'Post',
  definition(t) {
    t.model.id()
    t.model.comments()
     t.list.field('comments', {
      type: 'Comment',
      list: true,
      resolve: (parent, args, { prisma }) => {
        return prisma.comment.findMany({
          where: {
            postId: parent.id,
          },
          take: 1,
        })
      },
    })
})

Это работает. Но если я правильно понял, у меня для каждого поста есть один дополнительный запрос. Но у меня уже есть на распознавателе мутаций правильный результат. И у меня нет поля комментариев в родительском (t.list.field-resolver)

person Tölz    schedule 22.09.2020