GraphQL并集和序列化

时间:2019-12-18 15:07:22

标签: javascript node.js graphql sequelize.js

我无法理解如何从GraphQL Union检索信息。我有这样的地方:

const Profile = StudentProfile | TeacherProfile

然后在我的解析器中有

  Profile: {
    __resolveType(obj, context, info) {
      if (obj.studentId) {
        return 'StudentProfile'
      } else if (obj.salaryGrade) {
        return 'TeacherProfile'
      }
    },
  },

这不会引发任何错误,但是当我运行这样的查询时:

query {
  listUsers {
    id
    firstName
    lastName
    email
    password
    profile {
      __typename
      ... on StudentProfile {
        studentId
      }
      ... on TeacherProfile {
         salaryGrade
     }
    }
  }
}

这将返回所有内容,但配置文件仅返回null。我正在使用Sequelize来处理数据库工作,但是我对Union的理解是,它只需查找要查询的ID的相关类型并在查询中返回适当的详细信息即可。

如果我弄错了,如何使该查询起作用?

编辑:

我的列表用户解析器:

const listUsers = async (root, { filter }, { models }) => {
  const Op = Sequelize.Op
  return models.User.findAll(
    filter
      ? {
          where: {
            [Op.or]: [
              {
                email: filter,
              },
              {
                firstName: filter,
              },
              {
                lastName: filter,
              },
            ],
          },
        }
      : {},
  )
}

用户模型关系(非常简单,与配置文件没有关系)

User.associate = function(models) {
    User.belongsTo(models.UserType)
    User.belongsTo(models.UserRole)
  }

和我的一般用户解析器:

User: {
    async type(type) {
      return type.getUserType()
    },

    async role(role) {
      return role.getUserRole()
    },
  },

1 个答案:

答案 0 :(得分:1)

最简单的方法是利用单个表(即single table inheritance)。

  • 创建一个包含所有类型的列的表。例如,它将包含student_idsalary_grade列,即使这些列将作为架构中单独类型的字段公开。
  • 添加一个“类型”列,以标识每一行的实际类型。实际上,将这一列命名为__typename(稍后会详细介绍)会很有帮助。
  • 为表创建一个Sequelize模型。同样,此模型将包括所有属性,即使它们不适用于特定类型。
  • 定义您的GraphQL类型和您的接口/联合类型。您可以提供一种__resolveType方法,该方法根据您添加的“类型”字段返回适当的类型名称。但是,如果您将此字段命名为__typename,并使用要公开的GraphQL类型的名称填充它,则实际上可以跳过此步骤!
  • 您可以像平常一样使用模型,利用find方法查询表或与其建立关联。例如,您可以添加诸如User.belongsTo(Profile)之类的关系,然后延迟加载它:User.findAll({ include: [Profile] })

此方法的最大缺点是您丢失了数据库级和模型级验证。也许salary_grade对于TeacherProfile永远不能为null,但是您不能通过约束来强制执行此操作,也不能将属性的allowNull属性设置为false。充其量,您只能依靠GraphQL的类型系统来执行验证,但这并不理想。

可以更进一步,并为每个单独的“类型”创建其他Sequelize模型。这些模型仍将指向同一张表,但仅包含特定于您要为每种类型公开的字段的属性。这样,您至少可以在模型级别强制实施“必需”属性。然后,例如,您使用Profile模型来查询所有个人资料,但是在插入或更新教师个人资料时使用TeacherProfile。这样效果很好,请注意,在构造这样的模型时不能使用sync方法-您需要手动处理迁移。无论如何,您都不应该在生产中使用sync,因此这不是一笔很大的交易,但绝对是要注意的事情。