GraphQL 数据建模 - 扩展类型 (Prisma)

GraphQL data modelling - extended types (Prisma)

在我的 Prisma 数据模型中,我从这样的基本用户类型开始:

type User {
  name: String!
  email: String! @unique
  password: String!
}

现在一个用户可以有两个角色:作为候选人或作为与雇主相关联的用户。如果是候选人,用户还应该有一组应用程序和一组资格,如果与雇主相关联,它应该有一个访问级别和对雇主的引用。

首先,有什么方法可以扩展 GraphQL 数据建模中的基本类型吗?如果是这样,我将如何去做?

如果没有,我可以看到使用了三种不同的方法,我很好奇每种方法的优缺点是什么:

  1. 有两个不同的类型 CandidateUserEmployerUser,每个类型都有字段 nameemailpassword。我发现这种方法有两个问题: email 上的 @unique 标签不可靠,我必须编写自定义验证以确保该字段在两种类型中都是唯一的;并且拥有一个接收电子邮件并获取用户相应数据的登录功能不再是微不足道的:它需要在两个表中进行查找。

像这样:

    type CandidateUser {
      name: String!
      email: String! @unique
      password: String!
      applications: [Application!]!
      qualifications: [Qualification!]!
    }
    type EmployerUser{
      name: String!
      email: String! @unique
      password: String!
      employer: Employer!
      accessRight: AccessRight!
    }
  1. 同样是两种不同的类型,但是 RootUser 包含 nameemailpassword,以及 CandidateUserEmployerUser 每个都有对 RootUser 的一对一引用。这将在电子邮件字段上强制执行 @unique 标记,但查找仍然很重要。

    type RootUser{
      name: String!
      email: String! @unique
      password: String!
    }
    type CandidateUser {
      rootUser: RootUser!
      applications: [Application!]!
      qualifications: [Qualification!]!
    }
    type EmployerUser{
      rootUser: RootUser!
      employer: Employer!
      accessRight: AccessRight!
    }
    
  2. 扩展 User 以将 EmployerUser 和 CandidateUser 中的字段作为可选参数。这是一种非常简单的方法,但我需要自定义处理来强制执行必填字段(例如,我无法将雇主标记为必填,因为候选人不存在该字段)。

    type User{
      name: String!
      email: String! @unique
      password: String!
      applications: [Application!]!
      qualifications: [Qualification!]!
      employer: Employer
      accessRight: AccessRight
    }
    

我很想问问有没有更好的方法解决这个问题。我对 GraphQL 还是很陌生,并不是最好的数据建模师,但我非常感谢任何朝着正确方向的推动:)

如果除了我列出的三个之外别无选择,那一个最有意义?

您要做的是实施 interface type:

An Interface is an abstract type that includes a certain set of fields that a type must include to implement the interface.

interface User {
  name: String!
  email: String! @unique
  password: String!
}

这意味着任何实现 User 的类型都需要具有这些确切的字段、这些参数和 return 类型。所以现在你的 Candidate 类型可以实现 User:

type Candidate implements User {
  name: String!
  email: String! @unique
  password: String!
  applications: [Application!]!
  qualifications: [Qualification!]!
}

当您想要 return 一个对象或一组对象时,接口很有用,但它们可能有几种不同的类型。查看 interface abstract type documentation 了解更多信息。


更新:

由于这是一个 Prisma GraphQL 问题,您应该知道 Prisma 目前还不支持接口或联合类型Issue #83 and issue #165 将两者分别作为功能请求进行讨论。

但是,有一篇很棒的文章讨论了这种方法的解决方法:

GraphQL Interfaces (and Union Types) with Prisma and Yoga

归结为 2 个选项:

  1. Storing all data with optional type-specific fields under one type (the interface) in Prisma, and then splitting the data back between the primitive types in the app server.
  2. Storing the data in each primitive type on Prisma, and stitching things for queries on the app server.