graphile-plugin-connection-filter 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/ConnectionArgFilterPlugin.d.ts +3 -0
  2. package/ConnectionArgFilterPlugin.js +18 -0
  3. package/LICENSE +23 -0
  4. package/PgConnectionArgFilterBackwardRelationsPlugin.d.ts +12 -0
  5. package/PgConnectionArgFilterBackwardRelationsPlugin.js +244 -0
  6. package/PgConnectionArgFilterColumnsPlugin.d.ts +3 -0
  7. package/PgConnectionArgFilterColumnsPlugin.js +51 -0
  8. package/PgConnectionArgFilterCompositeTypeColumnsPlugin.d.ts +3 -0
  9. package/PgConnectionArgFilterCompositeTypeColumnsPlugin.js +67 -0
  10. package/PgConnectionArgFilterComputedColumnsPlugin.d.ts +3 -0
  11. package/PgConnectionArgFilterComputedColumnsPlugin.js +114 -0
  12. package/PgConnectionArgFilterForwardRelationsPlugin.d.ts +11 -0
  13. package/PgConnectionArgFilterForwardRelationsPlugin.js +130 -0
  14. package/PgConnectionArgFilterLogicalOperatorsPlugin.d.ts +3 -0
  15. package/PgConnectionArgFilterLogicalOperatorsPlugin.js +67 -0
  16. package/PgConnectionArgFilterOperatorsPlugin.d.ts +15 -0
  17. package/PgConnectionArgFilterOperatorsPlugin.js +551 -0
  18. package/PgConnectionArgFilterPlugin.d.ts +27 -0
  19. package/PgConnectionArgFilterPlugin.js +305 -0
  20. package/PgConnectionArgFilterRecordFunctionsPlugin.d.ts +3 -0
  21. package/PgConnectionArgFilterRecordFunctionsPlugin.js +75 -0
  22. package/README.md +364 -0
  23. package/esm/ConnectionArgFilterPlugin.js +16 -0
  24. package/esm/PgConnectionArgFilterBackwardRelationsPlugin.js +242 -0
  25. package/esm/PgConnectionArgFilterColumnsPlugin.js +49 -0
  26. package/esm/PgConnectionArgFilterCompositeTypeColumnsPlugin.js +65 -0
  27. package/esm/PgConnectionArgFilterComputedColumnsPlugin.js +112 -0
  28. package/esm/PgConnectionArgFilterForwardRelationsPlugin.js +128 -0
  29. package/esm/PgConnectionArgFilterLogicalOperatorsPlugin.js +65 -0
  30. package/esm/PgConnectionArgFilterOperatorsPlugin.js +549 -0
  31. package/esm/PgConnectionArgFilterPlugin.js +303 -0
  32. package/esm/PgConnectionArgFilterRecordFunctionsPlugin.js +73 -0
  33. package/esm/index.js +58 -0
  34. package/esm/types.js +1 -0
  35. package/index.d.ts +6 -0
  36. package/index.js +64 -0
  37. package/package.json +58 -0
  38. package/types.d.ts +25 -0
  39. package/types.js +2 -0
@@ -0,0 +1,303 @@
1
+ const PgConnectionArgFilterPlugin = (builder, rawOptions) => {
2
+ const { connectionFilterAllowedFieldTypes, connectionFilterArrays, connectionFilterSetofFunctions, connectionFilterAllowNullInput, connectionFilterAllowEmptyObjectInput, } = rawOptions;
3
+ // Add `filter` input argument to connection and simple collection types
4
+ builder.hook('GraphQLObjectType:fields:field:args', (args, build, context) => {
5
+ const { extend, newWithHooks, getTypeByName, inflection, pgGetGqlTypeByTypeIdAndModifier, pgOmit: omit, connectionFilterResolve, connectionFilterType, } = build;
6
+ const { scope: { isPgFieldConnection, isPgFieldSimpleCollection, pgFieldIntrospection: source, }, addArgDataGenerator, field, Self, } = context;
7
+ const shouldAddFilter = isPgFieldConnection || isPgFieldSimpleCollection;
8
+ if (!shouldAddFilter)
9
+ return args;
10
+ if (!source)
11
+ return args;
12
+ if (omit(source, 'filter'))
13
+ return args;
14
+ if (source.kind === 'procedure') {
15
+ if (!(source.tags.filterable || connectionFilterSetofFunctions)) {
16
+ return args;
17
+ }
18
+ }
19
+ const returnTypeId = source.kind === 'class' ? source.type.id : source.returnTypeId;
20
+ const returnType = source.kind === 'class'
21
+ ? source.type
22
+ : build.pgIntrospectionResultsByKind.type.find((t) => t.id === returnTypeId);
23
+ if (!returnType) {
24
+ return args;
25
+ }
26
+ const isRecordLike = returnTypeId === '2249';
27
+ const nodeTypeName = isRecordLike
28
+ ? inflection.recordFunctionReturnType(source)
29
+ : pgGetGqlTypeByTypeIdAndModifier(returnTypeId, null).name;
30
+ const filterTypeName = inflection.filterType(nodeTypeName);
31
+ const nodeType = getTypeByName(nodeTypeName);
32
+ if (!nodeType) {
33
+ return args;
34
+ }
35
+ const nodeSource = source.kind === 'procedure' && returnType.class
36
+ ? returnType.class
37
+ : source;
38
+ const FilterType = connectionFilterType(newWithHooks, filterTypeName, nodeSource, nodeTypeName);
39
+ if (!FilterType) {
40
+ return args;
41
+ }
42
+ // Generate SQL where clause from filter argument
43
+ addArgDataGenerator(function connectionFilter(args) {
44
+ return {
45
+ pgQuery: (queryBuilder) => {
46
+ if (Object.prototype.hasOwnProperty.call(args, 'filter')) {
47
+ const sqlFragment = connectionFilterResolve(args.filter, queryBuilder.getTableAlias(), filterTypeName, queryBuilder, returnType, null);
48
+ if (sqlFragment != null) {
49
+ queryBuilder.where(sqlFragment);
50
+ }
51
+ }
52
+ },
53
+ };
54
+ });
55
+ return extend(args, {
56
+ filter: {
57
+ description: 'A filter to be used in determining which values should be returned by the collection.',
58
+ type: FilterType,
59
+ },
60
+ }, `Adding connection filter arg to field '${field.name}' of '${Self.name}'`);
61
+ });
62
+ builder.hook('build', (build) => {
63
+ const { extend, graphql: { getNamedType, GraphQLInputObjectType, GraphQLList }, inflection, pgIntrospectionResultsByKind: introspectionResultsByKind, pgGetGqlInputTypeByTypeIdAndModifier, pgGetGqlTypeByTypeIdAndModifier, pgSql: sql, } = build;
64
+ const connectionFilterResolvers = {};
65
+ const connectionFilterTypesByTypeName = {};
66
+ const handleNullInput = () => {
67
+ if (!connectionFilterAllowNullInput) {
68
+ throw new Error('Null literals are forbidden in filter argument input.');
69
+ }
70
+ return null;
71
+ };
72
+ const handleEmptyObjectInput = () => {
73
+ if (!connectionFilterAllowEmptyObjectInput) {
74
+ throw new Error('Empty objects are forbidden in filter argument input.');
75
+ }
76
+ return null;
77
+ };
78
+ const isEmptyObject = (obj) => typeof obj === 'object' &&
79
+ obj !== null &&
80
+ !Array.isArray(obj) &&
81
+ Object.keys(obj).length === 0;
82
+ const connectionFilterRegisterResolver = (typeName, fieldName, resolve) => {
83
+ const existingResolvers = connectionFilterResolvers[typeName] || {};
84
+ if (existingResolvers[fieldName]) {
85
+ return;
86
+ }
87
+ connectionFilterResolvers[typeName] = extend(existingResolvers, {
88
+ [fieldName]: resolve,
89
+ });
90
+ };
91
+ const connectionFilterResolve = (obj, sourceAlias, typeName, queryBuilder, pgType, pgTypeModifier, parentFieldName, parentFieldInfo) => {
92
+ if (obj == null)
93
+ return handleNullInput();
94
+ if (isEmptyObject(obj))
95
+ return handleEmptyObjectInput();
96
+ const sqlFragments = Object.entries(obj)
97
+ .map(([key, value]) => {
98
+ if (value == null)
99
+ return handleNullInput();
100
+ if (isEmptyObject(value))
101
+ return handleEmptyObjectInput();
102
+ const resolversByFieldName = connectionFilterResolvers[typeName];
103
+ if (resolversByFieldName && resolversByFieldName[key]) {
104
+ return resolversByFieldName[key]({
105
+ sourceAlias,
106
+ fieldName: key,
107
+ fieldValue: value,
108
+ queryBuilder,
109
+ pgType,
110
+ pgTypeModifier,
111
+ parentFieldName,
112
+ parentFieldInfo,
113
+ });
114
+ }
115
+ throw new Error(`Unable to resolve filter field '${key}'`);
116
+ })
117
+ .filter((x) => x != null);
118
+ return sqlFragments.length === 0
119
+ ? null
120
+ : sql.query `(${sql.join(sqlFragments, ') and (')})`;
121
+ };
122
+ // Get or create types like IntFilter, StringFilter, etc.
123
+ const connectionFilterOperatorsType = (newWithHooks, pgTypeId, pgTypeModifier) => {
124
+ const pgType = introspectionResultsByKind.typeById[pgTypeId];
125
+ const allowedPgTypeTypes = ['b', 'd', 'e', 'r'];
126
+ if (!allowedPgTypeTypes.includes(pgType.type)) {
127
+ // Not a base, domain, enum, or range type? Skip.
128
+ return null;
129
+ }
130
+ // Perform some checks on the simple type (after removing array/range/domain wrappers)
131
+ const pgGetNonArrayType = (pgType) => pgType.isPgArray && pgType.arrayItemType
132
+ ? pgType.arrayItemType
133
+ : pgType;
134
+ const pgGetNonRangeType = (pgType) => pgType.rangeSubTypeId
135
+ ? introspectionResultsByKind.typeById[pgType.rangeSubTypeId]
136
+ : pgType;
137
+ const pgGetNonDomainType = (pgType) => pgType.type === 'd' && pgType.domainBaseTypeId
138
+ ? introspectionResultsByKind.typeById[pgType.domainBaseTypeId]
139
+ : pgType;
140
+ const pgGetSimpleType = (pgType) => pgGetNonDomainType(pgGetNonRangeType(pgGetNonArrayType(pgType)));
141
+ const pgSimpleType = pgGetSimpleType(pgType);
142
+ if (!pgSimpleType)
143
+ return null;
144
+ if (!(pgSimpleType.type === 'e' ||
145
+ (pgSimpleType.type === 'b' && !pgSimpleType.isPgArray))) {
146
+ // Haven't found an enum type or a non-array base type? Skip.
147
+ return null;
148
+ }
149
+ if (pgSimpleType.name === 'json') {
150
+ // The PG `json` type has no valid operators.
151
+ // Skip filter type creation to allow the proper
152
+ // operators to be exposed for PG `jsonb` types.
153
+ return null;
154
+ }
155
+ // Establish field type and field input type
156
+ const fieldType = pgGetGqlTypeByTypeIdAndModifier(pgTypeId, pgTypeModifier);
157
+ if (!fieldType)
158
+ return null;
159
+ const fieldInputType = pgGetGqlInputTypeByTypeIdAndModifier(pgTypeId, pgTypeModifier);
160
+ if (!fieldInputType)
161
+ return null;
162
+ // Avoid exposing filter operators on unrecognized types that PostGraphile handles as Strings
163
+ const namedType = getNamedType(fieldType);
164
+ const namedInputType = getNamedType(fieldInputType);
165
+ const actualStringPgTypeIds = [
166
+ '1042', // bpchar
167
+ '18', // char
168
+ '19', // name
169
+ '25', // text
170
+ '1043', // varchar
171
+ ];
172
+ // Include citext as recognized String type
173
+ const citextPgType = introspectionResultsByKind.type.find((t) => t.name === 'citext');
174
+ if (citextPgType) {
175
+ actualStringPgTypeIds.push(citextPgType.id);
176
+ }
177
+ if (namedInputType &&
178
+ namedInputType.name === 'String' &&
179
+ !actualStringPgTypeIds.includes(pgSimpleType.id)) {
180
+ // Not a real string type? Skip.
181
+ return null;
182
+ }
183
+ // Respect `connectionFilterAllowedFieldTypes` config option
184
+ if (connectionFilterAllowedFieldTypes &&
185
+ !connectionFilterAllowedFieldTypes.includes(namedType.name)) {
186
+ return null;
187
+ }
188
+ const pgConnectionFilterOperatorsCategory = pgType.isPgArray
189
+ ? 'Array'
190
+ : pgType.rangeSubTypeId
191
+ ? 'Range'
192
+ : pgType.type === 'e'
193
+ ? 'Enum'
194
+ : pgType.type === 'd'
195
+ ? 'Domain'
196
+ : 'Scalar';
197
+ // Respect `connectionFilterArrays` config option
198
+ if (pgConnectionFilterOperatorsCategory === 'Array' &&
199
+ !connectionFilterArrays) {
200
+ return null;
201
+ }
202
+ const rangeElementInputType = pgType.rangeSubTypeId
203
+ ? pgGetGqlInputTypeByTypeIdAndModifier(pgType.rangeSubTypeId, pgTypeModifier)
204
+ : null;
205
+ const domainBaseType = pgType.type === 'd'
206
+ ? pgGetGqlTypeByTypeIdAndModifier(pgType.domainBaseTypeId, pgType.domainTypeModifier)
207
+ : null;
208
+ const isListType = fieldType instanceof GraphQLList;
209
+ const operatorsTypeName = isListType
210
+ ? inflection.filterFieldListType(namedType.name)
211
+ : inflection.filterFieldType(namedType.name);
212
+ const existingType = connectionFilterTypesByTypeName[operatorsTypeName];
213
+ if (existingType) {
214
+ return existingType;
215
+ }
216
+ return newWithHooks(GraphQLInputObjectType, {
217
+ name: operatorsTypeName,
218
+ description: `A filter to be used against ${namedType.name}${isListType ? ' List' : ''} fields. All fields are combined with a logical ‘and.’`,
219
+ }, {
220
+ isPgConnectionFilterOperators: true,
221
+ pgConnectionFilterOperatorsCategory,
222
+ fieldType,
223
+ fieldInputType,
224
+ rangeElementInputType,
225
+ domainBaseType,
226
+ }, true);
227
+ };
228
+ const connectionFilterType = (newWithHooks, filterTypeName, source, nodeTypeName) => {
229
+ const existingType = connectionFilterTypesByTypeName[filterTypeName];
230
+ if (existingType) {
231
+ return existingType;
232
+ }
233
+ const placeholder = new GraphQLInputObjectType({
234
+ name: filterTypeName,
235
+ fields: {},
236
+ });
237
+ connectionFilterTypesByTypeName[filterTypeName] = placeholder;
238
+ const FilterType = newWithHooks(GraphQLInputObjectType, {
239
+ description: `A filter to be used against \`${nodeTypeName}\` object types. All fields are combined with a logical ‘and.’`,
240
+ name: filterTypeName,
241
+ }, {
242
+ pgIntrospection: source,
243
+ isPgConnectionFilter: true,
244
+ }, true);
245
+ connectionFilterTypesByTypeName[filterTypeName] = FilterType;
246
+ return FilterType;
247
+ };
248
+ const escapeLikeWildcards = (input) => {
249
+ if ('string' !== typeof input) {
250
+ throw new Error('Non-string input was provided to escapeLikeWildcards');
251
+ }
252
+ else {
253
+ return input.split('%').join('\\%').split('_').join('\\_');
254
+ }
255
+ };
256
+ const addConnectionFilterOperator = (typeNames, operatorName, description, resolveType, resolve, options = {}) => {
257
+ if (!typeNames) {
258
+ const msg = `Missing first argument 'typeNames' in call to 'addConnectionFilterOperator' for operator '${operatorName}'`;
259
+ throw new Error(msg);
260
+ }
261
+ if (!operatorName) {
262
+ const msg = `Missing second argument 'operatorName' in call to 'addConnectionFilterOperator' for operator '${operatorName}'`;
263
+ throw new Error(msg);
264
+ }
265
+ if (!resolveType) {
266
+ const msg = `Missing fourth argument 'resolveType' in call to 'addConnectionFilterOperator' for operator '${operatorName}'`;
267
+ throw new Error(msg);
268
+ }
269
+ if (!resolve) {
270
+ const msg = `Missing fifth argument 'resolve' in call to 'addConnectionFilterOperator' for operator '${operatorName}'`;
271
+ throw new Error(msg);
272
+ }
273
+ const { connectionFilterScalarOperators } = build;
274
+ const gqlTypeNames = Array.isArray(typeNames) ? typeNames : [typeNames];
275
+ for (const gqlTypeName of gqlTypeNames) {
276
+ if (!connectionFilterScalarOperators[gqlTypeName]) {
277
+ connectionFilterScalarOperators[gqlTypeName] = {};
278
+ }
279
+ if (connectionFilterScalarOperators[gqlTypeName][operatorName]) {
280
+ const msg = `Operator '${operatorName}' already exists for type '${gqlTypeName}'.`;
281
+ throw new Error(msg);
282
+ }
283
+ connectionFilterScalarOperators[gqlTypeName][operatorName] = {
284
+ description,
285
+ resolveType,
286
+ resolve,
287
+ // These functions may exist on `options`: resolveSqlIdentifier, resolveSqlValue, resolveInput
288
+ ...options,
289
+ };
290
+ }
291
+ };
292
+ return extend(build, {
293
+ connectionFilterTypesByTypeName,
294
+ connectionFilterRegisterResolver,
295
+ connectionFilterResolve,
296
+ connectionFilterOperatorsType,
297
+ connectionFilterType,
298
+ escapeLikeWildcards,
299
+ addConnectionFilterOperator,
300
+ });
301
+ });
302
+ };
303
+ export default PgConnectionArgFilterPlugin;
@@ -0,0 +1,73 @@
1
+ const PgConnectionArgFilterRecordFunctionsPlugin = (builder, rawOptions) => {
2
+ const { connectionFilterSetofFunctions } = rawOptions;
3
+ builder.hook('GraphQLInputObjectType:fields', (fields, build, context) => {
4
+ const { extend, newWithHooks, pgSql: sql, pgIntrospectionResultsByKind: introspectionResultsByKind, pgGetGqlTypeByTypeIdAndModifier, inflection, describePgEntity, connectionFilterOperatorsType, connectionFilterRegisterResolver, connectionFilterResolve, connectionFilterTypesByTypeName, } = build;
5
+ const { fieldWithHooks, scope: { pgIntrospection: proc, isPgConnectionFilter }, Self, } = context;
6
+ if (!isPgConnectionFilter || proc.kind !== 'procedure')
7
+ return fields;
8
+ connectionFilterTypesByTypeName[Self.name] = Self;
9
+ // Must return a `RECORD` type
10
+ const isRecordLike = proc.returnTypeId === '2249';
11
+ if (!isRecordLike)
12
+ return fields;
13
+ // Must be marked @filterable OR enabled via plugin option
14
+ if (!(proc.tags.filterable || connectionFilterSetofFunctions))
15
+ return fields;
16
+ const argModesWithOutput = [
17
+ 'o', // OUT,
18
+ 'b', // INOUT
19
+ 't', // TABLE
20
+ ];
21
+ const outputArgNames = proc.argTypeIds.reduce((prev, _, idx) => {
22
+ if (argModesWithOutput.includes(proc.argModes[idx])) {
23
+ prev.push(proc.argNames[idx] || '');
24
+ }
25
+ return prev;
26
+ }, []);
27
+ const outputArgTypes = proc.argTypeIds.reduce((prev, typeId, idx) => {
28
+ if (argModesWithOutput.includes(proc.argModes[idx])) {
29
+ prev.push(introspectionResultsByKind.typeById[typeId]);
30
+ }
31
+ return prev;
32
+ }, []);
33
+ const outputArgByFieldName = outputArgNames.reduce((memo, outputArgName, idx) => {
34
+ const fieldName = inflection.functionOutputFieldName(proc, outputArgName, idx + 1);
35
+ if (memo[fieldName]) {
36
+ throw new Error(`Tried to register field name '${fieldName}' twice in '${describePgEntity(proc)}'; the argument names are too similar.`);
37
+ }
38
+ memo[fieldName] = {
39
+ name: outputArgName,
40
+ type: outputArgTypes[idx],
41
+ };
42
+ return memo;
43
+ }, {});
44
+ const outputArgFields = Object.entries(outputArgByFieldName).reduce((memo, [fieldName, outputArg]) => {
45
+ const OperatorsType = connectionFilterOperatorsType(newWithHooks, outputArg.type.id, null);
46
+ if (!OperatorsType) {
47
+ return memo;
48
+ }
49
+ return extend(memo, {
50
+ [fieldName]: fieldWithHooks(fieldName, {
51
+ description: `Filter by the object’s \`${fieldName}\` field.`,
52
+ type: OperatorsType,
53
+ }, {
54
+ isPgConnectionFilterField: true,
55
+ }),
56
+ });
57
+ }, {});
58
+ const resolve = ({ sourceAlias, fieldName, fieldValue, queryBuilder, }) => {
59
+ if (fieldValue == null)
60
+ return null;
61
+ const outputArg = outputArgByFieldName[fieldName];
62
+ const sqlIdentifier = sql.query `${sourceAlias}.${sql.identifier(outputArg.name)}`;
63
+ const typeName = pgGetGqlTypeByTypeIdAndModifier(outputArg.type.id, null).name;
64
+ const filterTypeName = inflection.filterType(typeName);
65
+ return connectionFilterResolve(fieldValue, sqlIdentifier, filterTypeName, queryBuilder, outputArg.type, null, fieldName);
66
+ };
67
+ for (const fieldName of Object.keys(outputArgFields)) {
68
+ connectionFilterRegisterResolver(Self.name, fieldName, resolve);
69
+ }
70
+ return extend(fields, outputArgFields);
71
+ });
72
+ };
73
+ export default PgConnectionArgFilterRecordFunctionsPlugin;
package/esm/index.js ADDED
@@ -0,0 +1,58 @@
1
+ import ConnectionArgFilterPlugin from './ConnectionArgFilterPlugin';
2
+ import PgConnectionArgFilterBackwardRelationsPlugin from './PgConnectionArgFilterBackwardRelationsPlugin';
3
+ import PgConnectionArgFilterColumnsPlugin from './PgConnectionArgFilterColumnsPlugin';
4
+ import PgConnectionArgFilterComputedColumnsPlugin from './PgConnectionArgFilterComputedColumnsPlugin';
5
+ import PgConnectionArgFilterCompositeTypeColumnsPlugin from './PgConnectionArgFilterCompositeTypeColumnsPlugin';
6
+ import PgConnectionArgFilterForwardRelationsPlugin from './PgConnectionArgFilterForwardRelationsPlugin';
7
+ import PgConnectionArgFilterLogicalOperatorsPlugin from './PgConnectionArgFilterLogicalOperatorsPlugin';
8
+ import PgConnectionArgFilterOperatorsPlugin from './PgConnectionArgFilterOperatorsPlugin';
9
+ import PgConnectionArgFilterPlugin from './PgConnectionArgFilterPlugin';
10
+ import PgConnectionArgFilterRecordFunctionsPlugin from './PgConnectionArgFilterRecordFunctionsPlugin';
11
+ import pkg from '../package.json';
12
+ const defaultOptions = {
13
+ connectionFilterArrays: true,
14
+ connectionFilterComputedColumns: true,
15
+ connectionFilterRelations: false,
16
+ connectionFilterSetofFunctions: true,
17
+ connectionFilterLogicalOperators: true,
18
+ connectionFilterAllowNullInput: false,
19
+ connectionFilterAllowEmptyObjectInput: false,
20
+ };
21
+ const PostGraphileConnectionFilterPlugin = (builder, configOptions = {}) => {
22
+ builder.hook('build', (build) => {
23
+ if (!build.versions) {
24
+ throw new Error(`Plugin ${pkg.name}@${pkg.version} requires graphile-build@^4.1.0 in order to check dependencies (current version: ${build.graphileBuildVersion})`);
25
+ }
26
+ const depends = (name, range) => {
27
+ if (!build.hasVersion(name, range)) {
28
+ throw new Error(`Plugin ${pkg.name}@${pkg.version} requires ${name}@${range} (${build.versions[name]
29
+ ? `current version: ${build.versions[name]}`
30
+ : 'not found'})`);
31
+ }
32
+ };
33
+ depends('graphile-build-pg', '^4.5.0');
34
+ build.versions = build.extend(build.versions, { [pkg.name]: pkg.version });
35
+ return build;
36
+ });
37
+ const options = {
38
+ ...defaultOptions,
39
+ ...configOptions,
40
+ };
41
+ const { connectionFilterRelations, connectionFilterLogicalOperators } = options;
42
+ ConnectionArgFilterPlugin(builder, options);
43
+ PgConnectionArgFilterPlugin(builder, options);
44
+ PgConnectionArgFilterColumnsPlugin(builder, options);
45
+ PgConnectionArgFilterComputedColumnsPlugin(builder, options);
46
+ PgConnectionArgFilterCompositeTypeColumnsPlugin(builder, options);
47
+ PgConnectionArgFilterRecordFunctionsPlugin(builder, options);
48
+ if (connectionFilterRelations) {
49
+ PgConnectionArgFilterBackwardRelationsPlugin(builder, options);
50
+ PgConnectionArgFilterForwardRelationsPlugin(builder, options);
51
+ }
52
+ if (connectionFilterLogicalOperators) {
53
+ PgConnectionArgFilterLogicalOperatorsPlugin(builder, options);
54
+ }
55
+ PgConnectionArgFilterOperatorsPlugin(builder, options);
56
+ };
57
+ export { PostGraphileConnectionFilterPlugin };
58
+ export default PostGraphileConnectionFilterPlugin;
package/esm/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { Plugin } from 'graphile-build';
2
+ import type { ConnectionFilterConfig, ConnectionFilterOptions } from './types';
3
+ declare const PostGraphileConnectionFilterPlugin: Plugin;
4
+ export type { ConnectionFilterConfig, ConnectionFilterOptions };
5
+ export { PostGraphileConnectionFilterPlugin };
6
+ export default PostGraphileConnectionFilterPlugin;
package/index.js ADDED
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PostGraphileConnectionFilterPlugin = void 0;
7
+ const ConnectionArgFilterPlugin_1 = __importDefault(require("./ConnectionArgFilterPlugin"));
8
+ const PgConnectionArgFilterBackwardRelationsPlugin_1 = __importDefault(require("./PgConnectionArgFilterBackwardRelationsPlugin"));
9
+ const PgConnectionArgFilterColumnsPlugin_1 = __importDefault(require("./PgConnectionArgFilterColumnsPlugin"));
10
+ const PgConnectionArgFilterComputedColumnsPlugin_1 = __importDefault(require("./PgConnectionArgFilterComputedColumnsPlugin"));
11
+ const PgConnectionArgFilterCompositeTypeColumnsPlugin_1 = __importDefault(require("./PgConnectionArgFilterCompositeTypeColumnsPlugin"));
12
+ const PgConnectionArgFilterForwardRelationsPlugin_1 = __importDefault(require("./PgConnectionArgFilterForwardRelationsPlugin"));
13
+ const PgConnectionArgFilterLogicalOperatorsPlugin_1 = __importDefault(require("./PgConnectionArgFilterLogicalOperatorsPlugin"));
14
+ const PgConnectionArgFilterOperatorsPlugin_1 = __importDefault(require("./PgConnectionArgFilterOperatorsPlugin"));
15
+ const PgConnectionArgFilterPlugin_1 = __importDefault(require("./PgConnectionArgFilterPlugin"));
16
+ const PgConnectionArgFilterRecordFunctionsPlugin_1 = __importDefault(require("./PgConnectionArgFilterRecordFunctionsPlugin"));
17
+ const package_json_1 = __importDefault(require("../package.json"));
18
+ const defaultOptions = {
19
+ connectionFilterArrays: true,
20
+ connectionFilterComputedColumns: true,
21
+ connectionFilterRelations: false,
22
+ connectionFilterSetofFunctions: true,
23
+ connectionFilterLogicalOperators: true,
24
+ connectionFilterAllowNullInput: false,
25
+ connectionFilterAllowEmptyObjectInput: false,
26
+ };
27
+ const PostGraphileConnectionFilterPlugin = (builder, configOptions = {}) => {
28
+ builder.hook('build', (build) => {
29
+ if (!build.versions) {
30
+ throw new Error(`Plugin ${package_json_1.default.name}@${package_json_1.default.version} requires graphile-build@^4.1.0 in order to check dependencies (current version: ${build.graphileBuildVersion})`);
31
+ }
32
+ const depends = (name, range) => {
33
+ if (!build.hasVersion(name, range)) {
34
+ throw new Error(`Plugin ${package_json_1.default.name}@${package_json_1.default.version} requires ${name}@${range} (${build.versions[name]
35
+ ? `current version: ${build.versions[name]}`
36
+ : 'not found'})`);
37
+ }
38
+ };
39
+ depends('graphile-build-pg', '^4.5.0');
40
+ build.versions = build.extend(build.versions, { [package_json_1.default.name]: package_json_1.default.version });
41
+ return build;
42
+ });
43
+ const options = {
44
+ ...defaultOptions,
45
+ ...configOptions,
46
+ };
47
+ const { connectionFilterRelations, connectionFilterLogicalOperators } = options;
48
+ (0, ConnectionArgFilterPlugin_1.default)(builder, options);
49
+ (0, PgConnectionArgFilterPlugin_1.default)(builder, options);
50
+ (0, PgConnectionArgFilterColumnsPlugin_1.default)(builder, options);
51
+ (0, PgConnectionArgFilterComputedColumnsPlugin_1.default)(builder, options);
52
+ (0, PgConnectionArgFilterCompositeTypeColumnsPlugin_1.default)(builder, options);
53
+ (0, PgConnectionArgFilterRecordFunctionsPlugin_1.default)(builder, options);
54
+ if (connectionFilterRelations) {
55
+ (0, PgConnectionArgFilterBackwardRelationsPlugin_1.default)(builder, options);
56
+ (0, PgConnectionArgFilterForwardRelationsPlugin_1.default)(builder, options);
57
+ }
58
+ if (connectionFilterLogicalOperators) {
59
+ (0, PgConnectionArgFilterLogicalOperatorsPlugin_1.default)(builder, options);
60
+ }
61
+ (0, PgConnectionArgFilterOperatorsPlugin_1.default)(builder, options);
62
+ };
63
+ exports.PostGraphileConnectionFilterPlugin = PostGraphileConnectionFilterPlugin;
64
+ exports.default = PostGraphileConnectionFilterPlugin;
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "graphile-plugin-connection-filter",
3
+ "version": "2.3.1",
4
+ "description": "Filtering on PostGraphile connections",
5
+ "author": "Matt Bretl",
6
+ "homepage": "https://github.com/launchql/launchql",
7
+ "license": "MIT",
8
+ "main": "index.js",
9
+ "module": "esm/index.js",
10
+ "types": "index.d.ts",
11
+ "scripts": {
12
+ "clean": "makage clean",
13
+ "copy": "makage assets",
14
+ "prepack": "pnpm run build",
15
+ "build": "makage build",
16
+ "build:dev": "makage build --dev",
17
+ "lint": "eslint . --fix",
18
+ "test": "jest",
19
+ "test:watch": "jest --watch"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public",
23
+ "directory": "dist"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/launchql/launchql"
28
+ },
29
+ "keywords": [
30
+ "postgraphile",
31
+ "graphile",
32
+ "plugin",
33
+ "postgres",
34
+ "graphql",
35
+ "filters",
36
+ "launchql"
37
+ ],
38
+ "bugs": {
39
+ "url": "https://github.com/launchql/launchql/issues"
40
+ },
41
+ "dependencies": {
42
+ "graphile-build": "^4.14.1",
43
+ "graphile-build-pg": "^4.14.1",
44
+ "graphql": "15.10.1"
45
+ },
46
+ "peerDependencies": {
47
+ "postgraphile": "^4.14.1"
48
+ },
49
+ "devDependencies": {
50
+ "@graphile-contrib/pg-simplify-inflector": "^6.1.0",
51
+ "@types/pg": "^8.15.6",
52
+ "graphile-test": "^2.8.9",
53
+ "makage": "^0.1.6",
54
+ "pg": "^8.16.0",
55
+ "pgsql-test": "^2.14.12"
56
+ },
57
+ "gitHead": "3812f24a480b2035b3413ec7fecfe492f294e590"
58
+ }
package/types.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ export type SimpleCollectionSetting = 'omit' | 'both' | 'only';
2
+ export interface ConnectionFilterOptions {
3
+ connectionFilterAllowedOperators?: string[];
4
+ connectionFilterAllowedFieldTypes?: string[];
5
+ connectionFilterOperatorNames?: Record<string, string>;
6
+ connectionFilterUseListInflectors?: boolean;
7
+ connectionFilterArrays?: boolean;
8
+ connectionFilterComputedColumns?: boolean;
9
+ connectionFilterRelations?: boolean;
10
+ connectionFilterSetofFunctions?: boolean;
11
+ connectionFilterLogicalOperators?: boolean;
12
+ connectionFilterAllowNullInput?: boolean;
13
+ connectionFilterAllowEmptyObjectInput?: boolean;
14
+ pgSimpleCollections?: SimpleCollectionSetting;
15
+ pgOmitListSuffix?: boolean;
16
+ }
17
+ export type ConnectionFilterConfig = ConnectionFilterOptions & {
18
+ connectionFilterArrays: boolean;
19
+ connectionFilterComputedColumns: boolean;
20
+ connectionFilterRelations: boolean;
21
+ connectionFilterSetofFunctions: boolean;
22
+ connectionFilterLogicalOperators: boolean;
23
+ connectionFilterAllowNullInput: boolean;
24
+ connectionFilterAllowEmptyObjectInput: boolean;
25
+ };
package/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });