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