0

我正在使用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

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

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

4

1 回答 1

0

请参阅此 github 问题进行深入讨论

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

  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;
    },
  });
}
于 2020-06-07T05:46:09.267 回答