首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Postgraphil -仅当输入不为空且不为空时,如何筛选查询

Postgraphil -仅当输入不为空且不为空时,如何筛选查询
EN

Stack Overflow用户
提问于 2022-05-15 09:42:58
回答 1查看 282关注 0票数 0

我正在使用postgraphile,我有一个查询:

代码语言:javascript
运行
复制
query Products($categories: [String]){
  products(
    filter: {
       category: { in: $categories } 
    }) {
    id
    name
    category
  }
}

如果$categories数组为空,是否有一种不使用筛选器的方法?

如果数组未设置或为空,我希望得到所有结果。

我看到了将过滤器作为参数传递的选项,但我想知道是否还有其他的支持。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-07 22:20:37

在不使过滤器成为客户端的通用参数的情况下,在postgraphile-plugin-connection-filter (v2.3.0)插件中有两个用于filter操作符自定义的服务器端选项。两者都要求您创建一个额外的插件来注册构建钩子

选项1:使用addConnectionFilterOperator

addConnectionFilterOperatorConnectionFilterPlugin添加的构建扩展函数,它允许您为自定义功能添加新的运算符。

选项2:直接修改连接筛选器操作符

还可以通过修改每个OperatorSpec的GraphQLType值来直接更改给定操作符的SQL输出。这些规范可以在字段对象的以下Build中找到:

代码语言:javascript
运行
复制
connectionFilterArrayOperators,
connectionFilterEnumOperators,
connectionFilterRangeOperators,
connectionFilterScalarOperators

下面是选项1和2的组合插件实现的一个示例,在操作符的参数值数组为空时省略SQL生成--有效地使操作符无效,并导致完整的数据返回。该实现允许在直接修改in运算符和向每个连接过滤器的标量字段中添加新的expansiveIn运算符之间进行轻松切换。

代码语言:javascript
运行
复制
import type { Build } from "postgraphile";
import type { Plugin, Options } from "graphile-build";
import type { AddConnectionFilterOperator } from "postgraphile-plugin-connection-filter/dist/PgConnectionArgFilterPlugin";
import type { PgType, SQL } from "graphile-build-pg";
import type { GraphQLInputType } from "graphql";
import type { OperatorSpec } from "postgraphile-plugin-connection-filter/dist/PgConnectionArgFilterOperatorsPlugin";

export interface InOperatorEmptyArrayCustomizationPluginBuildOpts {
  inOperatorEmptyArrayCustomizationPlugin?: {
    /**
     * Add new "expansiveIn" operators with custom empty array instead of
     * modifying existing "in" operators
     */
    addNewOperator?: boolean;
  };
}

/**
 * Implements custom empty array handling either by registering a new "expansiveIn"
 * operator for each connection filter or by modifying the existing "operators".
 * This plugin must be appended AFTER postgraphile-plugin-connection-filter
 * as it depends on its build extensions.
 */
const InOperatorEmptyArrayCustomizationPlugin: Plugin = (builder, options) => {
  const { inOperatorEmptyArrayCustomizationPlugin } = options as Options &
    InOperatorEmptyArrayCustomizationPluginBuildOpts;

  const addNewOperator =
    inOperatorEmptyArrayCustomizationPlugin?.addNewOperator === true;

  // create a build hook to access ConnectionFilterPlugin build extensions.
  builder.hook("build", (build) => {
    const {
      pgSql: sql,
      graphql: { GraphQLList, GraphQLNonNull },

      // this function is added as a build extension by the ConnectionFilterPlugin
      // and allows for the addition of custom filter operators.
      addConnectionFilterOperator,
      gql2pg,

      // this contains all existing ConnectionFilterPlugin scalar operators
      // by GraphQL type
      connectionFilterScalarOperators,
    } = build as Build & {
      addConnectionFilterOperator: AddConnectionFilterOperator;
      connectionFilterScalarOperators: Record<
        string,
        Record<string, OperatorSpec>
      >;
    };

    // Generate "in" SQL fragment from argument input values if values are
    // present in the array. Otherwise, return null.
    const resolveListSqlValue = (
      input: unknown,
      pgType: PgType,
      pgTypeModifier: number | null,
      resolveListItemSqlValue: (
        elem: unknown,
        pgType: PgType,
        pgTypeModifier: number | null
      ) => unknown
    ) =>
      (input as unknown[]).length === 0
        ? null
        : sql.query`(${sql.join(
            (input as unknown[]).map((i) =>
              resolveListItemSqlValue
                ? resolveListItemSqlValue(i, pgType, pgTypeModifier)
                : gql2pg(i, pgType, pgTypeModifier)
            ),
            ","
          )})`;

    // checks whether value is present before adding the sql filter fragment.
    const resolve = (i: SQL, v: SQL) =>
      v != null ? sql.fragment`${i} IN ${v}` : null;

    // Find all the scalar GraphQLTypes that have an "in" operator.
    const typesWithScalarInOperators = Object.entries(
      connectionFilterScalarOperators
    )
      .filter(([, operations]) => operations.in)
      .map(([typeName]) => typeName);

    // modify existing "in" operators for every scalar type.
    if (!addNewOperator) {
      // The graphile build engine will emit a warning if you create
      // a new build object using the standard javascript mechanisms.
      // It will also throw an error if the existing
      // connectionFilterScalarOperations field is replaced in the extension
      // object...
      const extendedBuild = build.extend(build, {});

      // ...so we merge in the new operators in a separate step.
      typesWithScalarInOperators.forEach((typeName) => {
        extendedBuild.connectionFilterScalarOperators[typeName].in = {
          // see https://github.com/graphile-contrib/postgraphile-plugin-connection-filter/blob/v2.3.0/src/PgConnectionArgFilterOperatorsPlugin.ts#L80-L85
          // for existing "in" operator configuration
          ...extendedBuild.connectionFilterScalarOperators[typeName].in,
          resolveSqlValue: resolveListSqlValue,
          resolve,
        };
      });

      return extendedBuild;
    }

    // Otherwise add a new operator called "inExpansive" that implements the custom
    // empty array argument handling.
    // see https://github.com/graphile-contrib/postgraphile-plugin-connection-filter/blob/v2.3.0/__tests__/customOperatorsPlugin.ts
    // for `addConnectionFilterOperator` usage examples.
    addConnectionFilterOperator(
      // add the new operator to any type that has an "in" operator.
      typesWithScalarInOperators,
      "inExpansive",
      "Included in the specified list -unless list is empty in which case this operator is not applied.",
      // list of non-null element type
      (fieldInputType: GraphQLInputType) =>
        new GraphQLList(new GraphQLNonNull(fieldInputType)),
      resolve,
      {
        resolveSqlValue: resolveListSqlValue,
      }
    );

    return build;
  });
};

export default InOperatorEmptyArrayCustomizationPlugin;

在Postgraphile中间件选项中,在ConnectionFilterPlugin之后追加插件:

代码语言:javascript
运行
复制
// ...
appendPlugins: [
  // ..
  ConnectionFilterPlugin,
  AddInExpansiveFilterOperatorPlugin
],
// ...

要启用expansiveIn操作符(选项1),在Postgraphile中间件选项中将相关配置添加到“`graphileBuildOptions”中:

代码语言:javascript
运行
复制
graphileBuildOptions: {
  inOperatorEmptyArrayCustomizationPlugin: {
   addNewOperator: true
  },
  // other plugin options
}

您可以使用inExpansive运算符与in运算符相同的方式:

代码语言:javascript
运行
复制
query Products($categories: [String]){
  products(
    filter: {
       category: { inExpansive: $categories } 
    }) {
    id
    name
    category
  }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72247125

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档