使用Prisma Schema在Apollo Server 4中查询相关数据的问题

问题描述 投票:0回答:1

我正在使用 Apollo Server 4 和 Prisma 5 构建一个简单的 ecomm 项目。目前,我正在尝试设置我的解析器,以便能够双向查询用户及其评论...并且还将评论作为顶层查询并返回其关联的用户。在数据库中,

Comment
表与
user_id
表具有关联的
User
FK 关系。
User
表没有评论 ID,因此是一 -> 多和多 -> 一关系。

当我尝试查询用户时,注释是

null
,除非我为其编写单独的解析器,然后使用 Prisma orm 来
include
关系。我不想遵循这一点,因为在使用 gql 时它似乎是一种反模式。我想要完成的是在我的 SDL 的顶级
userByEmail()
中有一个
Query{}
解析器...然后在我的解析器中有一个
Comment: {}
第二级对象,然后让相应的
User
成为
 parent
参数传入解析器...这比 db 更依赖于 gql。

相关 Prisma 型号:

model User {
  id          String        @id @default(uuid())
  username    String        @unique
  email       String        @unique
  password    String
  first_name  String
  last_name   String?
  created_at  DateTime      @default(now())
  updated_at  DateTime      @updatedAt
  deleted     Boolean       @default(false)
  comments    Comment[]
  ratings     Rating[]
  orders      Order[]
  UserAddress UserAddress[]
}


model Comment {
  id         String        @id @default(uuid())
  user       User     @relation(fields: [user_id], references: [id])
  user_id    String   // Change type to String
  product    Product  @relation(fields: [product_id], references: [id])
  product_id String
  content    String
  created_at DateTime @default(now())
  updated_at DateTime @updatedAt
  deleted    Boolean  @default(false)
}

相关 schema.graphql 类型:

type Query {
  "Get a user by their email"
  userByEmail(email: String): User!
}

"This type represents a user in the system"
type User {
  "Unique identifier for the user"
  id: ID!

  "Username for login"
  username: String!

  "User's email address"
  email: String!

  "User's first name"
  first_name: String!

  "User's last name (optional)"
  last_name: String!

  "List of comments authored by the user (optional)"
  comments: [Comment]

  "List of ratings created by the user (optional)"
  ratings: [Rating]

  "List of orders placed by the user (optional)"
  orders: [Order]

  "List of user's addresses"
  addresses: [Address]
}

type Comment {
  "Unique identifier for the comment"
  id: ID!

  "Content of the comment"
  content: String!

  "User who authored the comment"
  user: User

  "Product this comment is associated with"
  product: Product
}

解析器.ts

import { getUserByEmail, getCommentsByUserId } from '../../dataAccessLayer/orm/user';
import { User } from '../../generated/types';

// Use intersection type to combine Resolvers and Query
export const resolvers = {
  Query: {
    userByEmail: async (_parent: unknown, { email }: { email: string }) => {
      console.log('parent', email);
      const user = await getUserByEmail(email); // Already includes comments
      return user;
    },
  },
  Comment: {
    userComments: (parent: User) => {
      console.log('parent', parent);
      const userId = parent.id;
      return getCommentsByUserId(userId);
    },
  },
};

ORM 数据库查询

import prisma from '../prismaClient';

export async function getUserByEmail(email: string) {
  return await prisma.user.findUnique({
    where: {
      email,
    },
  });
}

export async function getCommentsByUserId(id: string) {
  return await prisma.comment.findMany({
    where: {
      user_id: id,
    },
    include: {
      user: true, // Include user relation
    },
  });
}

当我运行我的项目时,我收到此错误:

 Error: Comment.userComments defined in resolvers, but not in schema
[0]     at addResolversToSchema

如何使用 Apollo 推荐方法正确查询子字段,即使用

(parent, args, context, info)
参数,其中
parent
应该是尝试获取评论时最初查询的相关用户?这样我就不会在 orm 级别将数据库查询拼接在一起。

谢谢!

graphql prisma apollo-server
1个回答
0
投票

查看 apollo 服务器文档中的示例,了解 如何实现解析器

在架构中,您已经将

comments
属性包含到
User
类型

type User {
  id: ID!
  username: String!

  "List of comments authored by the user (optional)"
  comments: [Comment]

  # ... other fields
}

您还定义了

userByEmail
来获取顶级类型中的用户
Query

type Query {
  userByEmail(email: String): User!
}

接下来,您需要为此架构实现解析器。对于类型

Query
,您需要为方法
userByEmail
实现解析器。你已经完成了这部分

import { getUserByEmail } from '../../dataAccessLayer/orm/user';
import { User } from '../../generated/types';

// Use intersection type to combine Resolvers and Query
export const resolvers = {
  Query: {
    userByEmail: async (_, { email }: { email: string }) => {
      console.log('parent', email);
      const user = await getUserByEmail(email); // Already includes comments
      return user;
    },
  },
};

您需要做的下一件事是为 comments 属性定义 resovler,这将是您想要的:用户评论。

import { getUserByEmail, getCommentsByUserId } from '../../dataAccessLayer/orm/user';
import { User } from '../../generated/types';

// Use intersection type to combine Resolvers and Query
export const resolvers = {
  Query: {
    userByEmail: async (_, { email }: { email: string }) => {
      const user = await getUserByEmail(email); // Already includes comments
      return user;
    },
  },
  // User. not Comment. 
  User: {
    // The parent entity for comments field is user
    comments: async (parent: User, _: any) {
      if (parent.comments !== undefined) {
         // you mentioned that user fetched with userByEmail already 
         // includes comments, so you might not even need to refetch it
         return parent.comments 
      } 
      const comments = await getCommentsByUserId(user.id)
      return comments;
    },
  }
};

这是与我们的架构兼容的查询示例

query userWithComments($email: String!) {
  userByEmail(email: $email) {
    id
    username
    # some other fields
    comments {
      id
      content   
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.