我正在使用postgraphile,我有一个查询:
query Products($categories: [String]){
products(
filter: {
category: { in: $categories }
}) {
id
name
category
}
}
如果$categories数组为空,是否有一种不使用筛选器的方法?
如果数组未设置或为空,我希望得到所有结果。
我看到了将过滤器作为参数传递的选项,但我想知道是否还有其他的支持。
发布于 2022-06-07 22:20:37
在不使过滤器成为客户端的通用参数的情况下,在postgraphile-plugin-connection-filter
(v2.3.0)插件中有两个用于filter操作符自定义的服务器端选项。两者都要求您创建一个额外的插件来注册构建钩子。
选项1:使用addConnectionFilterOperator
addConnectionFilterOperator
是ConnectionFilterPlugin
添加的构建扩展函数,它允许您为自定义功能添加新的运算符。
选项2:直接修改连接筛选器操作符
还可以通过修改每个OperatorSpec
的GraphQLType值来直接更改给定操作符的SQL输出。这些规范可以在字段对象的以下Build
中找到:
connectionFilterArrayOperators,
connectionFilterEnumOperators,
connectionFilterRangeOperators,
connectionFilterScalarOperators
下面是选项1和2的组合插件实现的一个示例,在操作符的参数值数组为空时省略SQL生成--有效地使操作符无效,并导致完整的数据返回。该实现允许在直接修改in
运算符和向每个连接过滤器的标量字段中添加新的expansiveIn
运算符之间进行轻松切换。
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
之后追加插件:
// ...
appendPlugins: [
// ..
ConnectionFilterPlugin,
AddInExpansiveFilterOperatorPlugin
],
// ...
要启用expansiveIn
操作符(选项1),在Postgraphile中间件选项中将相关配置添加到“`graphileBuildOptions”中:
graphileBuildOptions: {
inOperatorEmptyArrayCustomizationPlugin: {
addNewOperator: true
},
// other plugin options
}
您可以使用inExpansive
运算符与in
运算符相同的方式:
query Products($categories: [String]){
products(
filter: {
category: { inExpansive: $categories }
}) {
id
name
category
}
}
https://stackoverflow.com/questions/72247125
复制相似问题