我应该如何在没有 `include` 的情况下使用 graphql-sequelize 急切地加载关联?
How am I supposed to eagerly load an association using graphql-sequelize without `include`?
我正在使用 graphql-sequelize 来实现 GraphQL 端点。我刚刚创建了一个新的辅助实体并将其与我的一个主要实体相关联,现在正尝试在获取主要实体时包括相关的辅助实体。当我尝试实现该提取时出现以下错误:
AssertionError ERR_ASSERTION Include support has been removed in favor of dataloader batching
我的基于解析器的旧 gql 端点如下所示:
driver: {
type: MyGQLTypes.Driver,
resolve: resolver(Driver)
}
我从代码库中其他地方的实验得知这通常有效:
const driver = Driver.getById(`${uuid}`, {
include: { model: Helmet }
})
// yields:
// {
// id: '<uuid>',
// name: 'Tom',
// helmetNumber: '470',
// Helmet: {
// number: '470',
// type: 'cool',
// color: 'red'
// }
// }
因此,在检查 source code of graphql-sequelize's resolver
并确定第二个参数传递给 sqlz 访问器后,我将相同的 include
添加到我的 GQL 解析器,如下所示:
driver: {
type: MyGQLTypes.Driver,
resolve: resolver(Driver, {
include: { model: Helmet }
})
}
那是我遇到致命错误的时候。研究表明 graphql-sequelize 人员现在不允许 include
用于 performance reasons,支持 sequelize 的数据加载器,我目前没有使用也没有计划使用它。
但即使我是,也没有回答他们希望我们如何在 resolver
中获取关联行的问题。我发现 a cryptic comment 表明有一个名为 join
的替代方案,但我无法找到它的文档,并且从臀部射击失败:
driver: {
type: MyGQLTypes.Driver,
resolve: resolver(Driver, {
include: { model: Helmet } // fatal error: disallowed
join: { model: Helmet } // no effect, no error
join: Helmet // no effect, no error
})
}
我能想到的就是添加一个 after
例程来手动获取关联的模型,然后将该结果附加到主模型的相同位置,如果它已被获取标准方式(即使用 include
),像这样:
driver: {
type: MyGQLTypes.Driver,
resolve: resolver(Driver, {
// can't do this:
include: { model: Helmet }
// so I try to emulate it this way:
after: async (driver) => {
driver.Helmet = await driver.getHelmet()
return driver
}
})
}
当该代码执行并找到我期望的模型时,它无法将找到的模型附加到同一个地方。
Sqlz 实例不是普通哈希:它们有一个 dataValues
属性,其中包含来自数据库的原始列值,当您引用 myModel.colName
时,一个隐藏的 getter 从 myModel.dataValues[ colName ]
中获取值。实验表明,通过 include
进行预加载会导致关联模型出现在 dataValues
结构中,可能连同所需的任何隐藏访问器一起出现,如下所示:
{
dataValues: {
id: '<uuid>',
name: 'Tom',
helmetNumber: '470',
Helmet: {
dataValues: {
number: '470,
type: 'cool',
color: 'red'
}
}
}
}
我很确定我可以将获取的模型附加到那里:
driver.dataValues.Helmet = await driver.getHelmet()
但我认为我们应该避免摆弄 dataValues
,这看起来很笨拙。
我正在使用 apollo-server-express
,它(正确地)根据 GQL 模式验证解析器 return 值,因此,我对 Driver
的 GQL 类型定义在技术上是 这个解析函数的下游。我已经开始构建一堆糖来组成 GQL 类型(特别是当涉及到将次级实体嵌入初级时),并且这种观点鼓励我认为基于 resolver
的端点应该具有统一形状 returns。 IE。如果某些实体的解析器发出损坏的 sqlz 模型实例,而其他实体 return 发出健康的解析器,那将很糟糕。
我们应该如何在没有 include
的情况下在 graphql-sequelize 的 resolver
中实现预加载?
包版本:
apollo-server-express@1.3.2
graphql-sequelize@5.6.1
sequelize@4.35.1
dataloader-sequelize@1.6.3
我尝试了两件事:
driver: {
type: MyGQLTypes.Driver,
resolve: resolver(Driver, {
after: driver => {
return Driver.findById(driver.id, {
include: [ Helmet ]
})
}
})
}
有效,但它击中了主要 table 两次,非常恶心。
所以,我决定直接扔掉graphql-sequelize的"helper"resolver
,直接编程到apollo-server-express的API:
driver: {
type: MyGQLTypes.Driver,
resolve: (parent, args, context, info) => {
return Driver.findById(args.id, {
include: [ Helmet ]
})
})
}
像冠军一样工作。可能有一个我还没有看到的缺点。我想时间会证明一切。
将此问题暂时搁置,以防其他人(包括我自己)有更好的答案。
我正在使用 graphql-sequelize 来实现 GraphQL 端点。我刚刚创建了一个新的辅助实体并将其与我的一个主要实体相关联,现在正尝试在获取主要实体时包括相关的辅助实体。当我尝试实现该提取时出现以下错误:
AssertionError ERR_ASSERTION Include support has been removed in favor of dataloader batching
我的基于解析器的旧 gql 端点如下所示:
driver: {
type: MyGQLTypes.Driver,
resolve: resolver(Driver)
}
我从代码库中其他地方的实验得知这通常有效:
const driver = Driver.getById(`${uuid}`, {
include: { model: Helmet }
})
// yields:
// {
// id: '<uuid>',
// name: 'Tom',
// helmetNumber: '470',
// Helmet: {
// number: '470',
// type: 'cool',
// color: 'red'
// }
// }
因此,在检查 source code of graphql-sequelize's resolver
并确定第二个参数传递给 sqlz 访问器后,我将相同的 include
添加到我的 GQL 解析器,如下所示:
driver: {
type: MyGQLTypes.Driver,
resolve: resolver(Driver, {
include: { model: Helmet }
})
}
那是我遇到致命错误的时候。研究表明 graphql-sequelize 人员现在不允许 include
用于 performance reasons,支持 sequelize 的数据加载器,我目前没有使用也没有计划使用它。
但即使我是,也没有回答他们希望我们如何在 resolver
中获取关联行的问题。我发现 a cryptic comment 表明有一个名为 join
的替代方案,但我无法找到它的文档,并且从臀部射击失败:
driver: {
type: MyGQLTypes.Driver,
resolve: resolver(Driver, {
include: { model: Helmet } // fatal error: disallowed
join: { model: Helmet } // no effect, no error
join: Helmet // no effect, no error
})
}
我能想到的就是添加一个 after
例程来手动获取关联的模型,然后将该结果附加到主模型的相同位置,如果它已被获取标准方式(即使用 include
),像这样:
driver: {
type: MyGQLTypes.Driver,
resolve: resolver(Driver, {
// can't do this:
include: { model: Helmet }
// so I try to emulate it this way:
after: async (driver) => {
driver.Helmet = await driver.getHelmet()
return driver
}
})
}
当该代码执行并找到我期望的模型时,它无法将找到的模型附加到同一个地方。
Sqlz 实例不是普通哈希:它们有一个 dataValues
属性,其中包含来自数据库的原始列值,当您引用 myModel.colName
时,一个隐藏的 getter 从 myModel.dataValues[ colName ]
中获取值。实验表明,通过 include
进行预加载会导致关联模型出现在 dataValues
结构中,可能连同所需的任何隐藏访问器一起出现,如下所示:
{
dataValues: {
id: '<uuid>',
name: 'Tom',
helmetNumber: '470',
Helmet: {
dataValues: {
number: '470,
type: 'cool',
color: 'red'
}
}
}
}
我很确定我可以将获取的模型附加到那里:
driver.dataValues.Helmet = await driver.getHelmet()
但我认为我们应该避免摆弄 dataValues
,这看起来很笨拙。
我正在使用 apollo-server-express
,它(正确地)根据 GQL 模式验证解析器 return 值,因此,我对 Driver
的 GQL 类型定义在技术上是 这个解析函数的下游。我已经开始构建一堆糖来组成 GQL 类型(特别是当涉及到将次级实体嵌入初级时),并且这种观点鼓励我认为基于 resolver
的端点应该具有统一形状 returns。 IE。如果某些实体的解析器发出损坏的 sqlz 模型实例,而其他实体 return 发出健康的解析器,那将很糟糕。
我们应该如何在没有 include
的情况下在 graphql-sequelize 的 resolver
中实现预加载?
包版本:
apollo-server-express@1.3.2
graphql-sequelize@5.6.1
sequelize@4.35.1
dataloader-sequelize@1.6.3
我尝试了两件事:
driver: {
type: MyGQLTypes.Driver,
resolve: resolver(Driver, {
after: driver => {
return Driver.findById(driver.id, {
include: [ Helmet ]
})
}
})
}
有效,但它击中了主要 table 两次,非常恶心。
所以,我决定直接扔掉graphql-sequelize的"helper"resolver
,直接编程到apollo-server-express的API:
driver: {
type: MyGQLTypes.Driver,
resolve: (parent, args, context, info) => {
return Driver.findById(args.id, {
include: [ Helmet ]
})
})
}
像冠军一样工作。可能有一个我还没有看到的缺点。我想时间会证明一切。
将此问题暂时搁置,以防其他人(包括我自己)有更好的答案。