跳至主要内容

多态性

GraphQL 目前有两种类型的输出多态性:接口和联合。接口定义了一个字段列表;所有实现该接口的对象都必须实现与这些字段兼容的字段。联合是可能的类型对象的简单列表。

Grafast 支持这两种形式的 GraphQL 多态性,既通过解析器,也通过计划。解析器的工作方式与 GraphQL.js 中的工作方式相同(基本上),因此我们不会在这里深入探讨它们,但让我们看看 Grafast 如何通过计划支持多态性。

多态位置

让我们定义“多态位置”这个术语,以便更容易地讨论规划我们的多态 GraphQL 查询。想象一下,你有一个 GraphQL 架构,例如

interface Animal {
name: String!
}
type Cat extends Animal {
name: String!
numberOfLives: Int!
}
type Dog extends Animal {
name: String!
wagsTail: Boolean!
}
type Query {
bestAnimal: Animal
randomAnimals: [Animal]
}

对这个架构的一个查询可能是

{
bestAnimal {
name
... on Cat {
numberOfLives
}
... on Dog {
wagsTail
}
}
}

这里 bestAnimal 字段的返回类型是一个多态类型(Animal,它是一个接口),所以 bestAnimal 的返回类型在这个查询中是一个多态位置。

另一个查询可能是

{
randomAnimals {
name
... on Cat {
numberOfLives
}
... on Dog {
wagsTail
}
}
}

这里 randomAnimals 的返回类型是一个列表([Animal])。列表本身不是多态的,但是列表中的类型是一个多态类型(再次是 Animal),所以这个查询中的多态位置是在 randomAnimals 返回的列表中。

操作可能具有任意数量(0 个或更多个)的多态位置。

支持多态的步骤

当操作中的多态位置正在被规划时,Grafast 将像往常一样调用字段的计划解析器函数(或对于列表内部的多态位置,调用结果步骤的 itemPlan 方法)来获取表示这个多态位置的步骤。Grafast 要求该步骤必须是支持多态的步骤,即其类实现了 planForType 方法的步骤,否则将引发规划错误。

  planForType(objectType: GraphQLObjectType): ExecutableStep;

确定了表示这个多态位置的支持多态的步骤后,Grafast 将创建一个多态 LayerPlan 并遍历该位置所有可能的具体对象类型。对于每个具体对象类型,Grafast 将将类型传递给支持多态的步骤的 planForType 方法,结果步骤将表示该具体对象类型。多个具体对象类型可能由同一个步骤表示。

然后,规划将继续遍历每个可能的具体对象类型和对应步骤的子选择集。

在运行时,当支持多态的步骤执行时,execute() 结果列表中的每个条目必须是 null、错误,或者调用 GrafastpolymorphicWrap 函数的结果,将具体对象类型的名称作为第一个参数传递,可选地将任何关联数据作为第二个参数传递。这允许 Grafast 确定哪个“多态分支”已被采用,这将控制哪些未来的步骤将针对此数据执行。

export function polymorphicWrap<TType extends string>(
type: TType,
data?: unknown,
): PolymorphicData<TType>;

注意事项

高度多态的操作可能会导致非常显著的规划时间,这是我们正在努力优化的,但目前我们建议您使用持久化操作(也称为持久化查询)来确保只有您的开发人员操作被允许。或者,使用我们的插件来验证操作不包含过多多态性(TODO:插件尚未可用)。

信息

目前,Grafast 使用了一种简单的策略,在规划阶段计划 GraphQL 操作中每个点的所有可能的多分态类型。这是一种简单的方法,但它可能会增加规划操作所花费的时间,尤其是在多分态操作高度复杂的情况下,组合问题会成为一个重大问题。

在某个时间点,Grafast 将添加对按需多分态规划的支持。使用这种策略,计划的每个“多分态分支”只会在运行时第一次遇到该类型的对象时才进行规划。这种按需多分态规划策略应该可以显著减少高度多分态操作的初始规划时间,并且可能导致许多路径根本不需要进行规划!