【问题标题】:Schema Directives don't execute in LTR order specified in schema架构指令不按架构中指定的 LTR 顺序执行
【发布时间】:2020-09-25 08:28:05
【问题描述】:

我正在使用graphql-tools@v6,并且我已经实现了两个指令@map@filter。我的目标是像地图和过滤器管道一样使用它们。在某些情况下,我想在过滤之前进行映射,而在其他情况下,反之亦然。这些指令是使用Schema Directives API 实现的,当只应用一个指令时它们会按预期工作。

但是,如果我将它们一起使用,那么它们总是以一种特定的顺序执行,这与它们在架构中的声明方式不匹配。

例如

directive @map on FIELD_DEFINITION
directive @filter on FIELD_DEFINITION

# usage
type MyType {
    list1: [String!]! @map @filter
    list2: [String!]! @filter @map
}

在这种情况下,要么映射两个字段,然后过滤,反之亦然。顺序由我在schemaTransforms 属性中传递它们的方式控制。

const schema = makeExecutableSchema({
  schemaTransforms: [mapDirective, filterDirective] # vs [filterDirective, mapDirective]
});

我相信由于这些转换是作为数组传递的,所以它们的执行顺序取决于数组的顺序。我可以用directiveResolvers 替换它们,但它们的功能有限。

但让我失望的是文档中的以下声明

使用directiveResolvers 的现有代码可以考虑迁移到直接使用mapSchema

因为它们在执行顺序方面有不同的行为,所以我看不出它们是如何互换的。

有人能解释一下是否有办法保证模式指令按照它们在特定字段的模式中使用的顺序执行吗?

【问题讨论】:

    标签: graphql apollo graphql-js apollo-server graphql-tools


    【解决方案1】:

    请参阅this github issue for in depth discussion

    新 API 的工作方式与 directiveResolversschemaDirectives 不同。 schemaTransform 在下一个模式之前应用于整个模式,而其他两个模式在访问下一个字段节点之前将所有转换应用于特定字段。我认为有两种方法:

    1. 创建一个新的@pipeline 指令,它采用其他指令的名称列表,然后按照directiveResolvers 的顺序应用它们。

    2. 我采取了一条不同的路线,我创建了一个新函数 attachSchemaTransforms,就像 attachDirectiveResolvers 一样,它访问每个节点并按顺序应用所有指令。

    export function attachSchemaTransforms(
      schema: GraphQLSchema,
      schemaTransforms: Record<string, FieldDirectiveConfig>, // a custom config object which contains the transform and the directive name
    ): GraphQLSchema {
      if (typeof schemaTransforms !== 'object') {
        throw new Error(`Expected schemaTransforms to be of type object, got ${typeof schemaTransforms}`);
      }
    
      if (Array.isArray(schemaTransforms)) {
        throw new Error('Expected schemaTransforms to be of type object, got Array');
      }
    
      return mapSchema(schema, {
        [MapperKind.OBJECT_FIELD]: oldFieldConfig => {
          const fieldConfig = { ...oldFieldConfig };
    
          const directives = getDirectives(schema, fieldConfig);
    
          Object.keys(directives).forEach(directiveName => {
            const config = schemaTransforms[directiveName];
            if (config) {
              const { apply, name } = config;
              const directives = getDirectives(schema, fieldConfig);
              if (directives[name]) {
                const directiveArgs: unknown = directives[name]
                apply(fieldConfig, directiveArgs);
                return fieldConfig;
              }
            }
          });
    
          return fieldConfig;
        },
      });
    }
    

    【讨论】:

      猜你喜欢
      • 2014-08-18
      • 2017-01-07
      • 1970-01-01
      • 1970-01-01
      • 2020-01-04
      • 2020-01-04
      • 1970-01-01
      • 2013-12-30
      • 2021-07-06
      相关资源
      最近更新 更多