graphile-pg-aggregates 1.1.0
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/AddAggregateTypesPlugin.d.ts +38 -0
- package/AddAggregateTypesPlugin.js +268 -0
- package/AddConnectionAggregatesPlugin.d.ts +2 -0
- package/AddConnectionAggregatesPlugin.js +56 -0
- package/AddConnectionGroupedAggregatesPlugin.d.ts +10 -0
- package/AddConnectionGroupedAggregatesPlugin.js +118 -0
- package/AddGroupByAggregateEnumValuesForAttributesPlugin.d.ts +10 -0
- package/AddGroupByAggregateEnumValuesForAttributesPlugin.js +116 -0
- package/AddGroupByAggregateEnumsPlugin.d.ts +2 -0
- package/AddGroupByAggregateEnumsPlugin.js +51 -0
- package/AddHavingAggregateTypesPlugin.d.ts +22 -0
- package/AddHavingAggregateTypesPlugin.js +449 -0
- package/AggregateSpecsPlugin.d.ts +1 -0
- package/AggregateSpecsPlugin.js +206 -0
- package/AggregatesSmartTagsPlugin.d.ts +8 -0
- package/AggregatesSmartTagsPlugin.js +65 -0
- package/EXPORTABLE.d.ts +1 -0
- package/EXPORTABLE.js +15 -0
- package/FilterRelationalAggregatesPlugin.d.ts +74 -0
- package/FilterRelationalAggregatesPlugin.js +443 -0
- package/InflectionPlugin.d.ts +67 -0
- package/InflectionPlugin.js +71 -0
- package/LICENSE +23 -0
- package/OrderByAggregatesPlugin.d.ts +31 -0
- package/OrderByAggregatesPlugin.js +205 -0
- package/README.md +128 -0
- package/esm/AddAggregateTypesPlugin.d.ts +38 -0
- package/esm/AddAggregateTypesPlugin.js +265 -0
- package/esm/AddConnectionAggregatesPlugin.d.ts +2 -0
- package/esm/AddConnectionAggregatesPlugin.js +53 -0
- package/esm/AddConnectionGroupedAggregatesPlugin.d.ts +10 -0
- package/esm/AddConnectionGroupedAggregatesPlugin.js +115 -0
- package/esm/AddGroupByAggregateEnumValuesForAttributesPlugin.d.ts +10 -0
- package/esm/AddGroupByAggregateEnumValuesForAttributesPlugin.js +113 -0
- package/esm/AddGroupByAggregateEnumsPlugin.d.ts +2 -0
- package/esm/AddGroupByAggregateEnumsPlugin.js +48 -0
- package/esm/AddHavingAggregateTypesPlugin.d.ts +22 -0
- package/esm/AddHavingAggregateTypesPlugin.js +446 -0
- package/esm/AggregateSpecsPlugin.d.ts +1 -0
- package/esm/AggregateSpecsPlugin.js +203 -0
- package/esm/AggregatesSmartTagsPlugin.d.ts +8 -0
- package/esm/AggregatesSmartTagsPlugin.js +62 -0
- package/esm/EXPORTABLE.d.ts +1 -0
- package/esm/EXPORTABLE.js +12 -0
- package/esm/FilterRelationalAggregatesPlugin.d.ts +74 -0
- package/esm/FilterRelationalAggregatesPlugin.js +440 -0
- package/esm/InflectionPlugin.d.ts +67 -0
- package/esm/InflectionPlugin.js +68 -0
- package/esm/OrderByAggregatesPlugin.d.ts +31 -0
- package/esm/OrderByAggregatesPlugin.js +202 -0
- package/esm/index.d.ts +42 -0
- package/esm/index.js +37 -0
- package/esm/interfaces.d.ts +145 -0
- package/esm/interfaces.js +44 -0
- package/esm/utils.d.ts +23 -0
- package/esm/utils.js +22 -0
- package/index.d.ts +42 -0
- package/index.js +40 -0
- package/interfaces.d.ts +145 -0
- package/interfaces.js +47 -0
- package/package.json +61 -0
- package/utils.d.ts +23 -0
- package/utils.js +25 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PgAggregatesAddGroupByAggregateEnumsPlugin = void 0;
|
|
4
|
+
const version = '1.0.0';
|
|
5
|
+
const Plugin = {
|
|
6
|
+
name: 'PgAggregatesAddGroupByAggregateEnumsPlugin',
|
|
7
|
+
description: 'Creates the enum types used for grouping in groupedAggregates.',
|
|
8
|
+
version,
|
|
9
|
+
provides: ['aggregates'],
|
|
10
|
+
schema: {
|
|
11
|
+
entityBehavior: {
|
|
12
|
+
pgResource: ['select', 'order', 'groupedAggregates']
|
|
13
|
+
},
|
|
14
|
+
hooks: {
|
|
15
|
+
// Create the group by enums for each table
|
|
16
|
+
init(_, build) {
|
|
17
|
+
const { inflection } = build;
|
|
18
|
+
for (const resource of Object.values(build.input.pgRegistry.pgResources)) {
|
|
19
|
+
if (resource.parameters ||
|
|
20
|
+
!resource.codec.attributes ||
|
|
21
|
+
resource.isUnique) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (!build.behavior.pgResourceMatches(resource, 'select')) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (!build.behavior.pgResourceMatches(resource, 'order')) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (!build.behavior.pgResourceMatches(resource, 'resource:groupedAggregates')) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const tableTypeName = inflection.tableType(resource.codec);
|
|
34
|
+
/* const TableGroupByType = */
|
|
35
|
+
build.registerEnumType(inflection.aggregateGroupByType({ resource }), {
|
|
36
|
+
pgTypeResource: resource,
|
|
37
|
+
isPgAggregateGroupEnum: true
|
|
38
|
+
}, () => ({
|
|
39
|
+
name: inflection.aggregateGroupByType({ resource }),
|
|
40
|
+
description: build.wrapDescription(`Grouping methods for \`${tableTypeName}\` for usage during aggregation.`, 'type'),
|
|
41
|
+
values: {
|
|
42
|
+
/* no default values, these will be added via hooks */
|
|
43
|
+
}
|
|
44
|
+
}), `Adding connection "groupBy" enum type for ${resource.name}.`);
|
|
45
|
+
}
|
|
46
|
+
return _;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
exports.PgAggregatesAddGroupByAggregateEnumsPlugin = Plugin;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
namespace GraphileBuild {
|
|
3
|
+
interface BehaviorStrings {
|
|
4
|
+
'resource:groupedAggregates:having': true;
|
|
5
|
+
having: true;
|
|
6
|
+
'resource:havingBy': true;
|
|
7
|
+
'attribute:havingBy': true;
|
|
8
|
+
havingBy: true;
|
|
9
|
+
'sum:resource:groupedAggregates:having': true;
|
|
10
|
+
'distinctCount:resource:groupedAggregates:having': true;
|
|
11
|
+
'min:resource:groupedAggregates:having': true;
|
|
12
|
+
'max:resource:groupedAggregates:having': true;
|
|
13
|
+
'average:resource:groupedAggregates:having': true;
|
|
14
|
+
'stddevSample:resource:groupedAggregates:having': true;
|
|
15
|
+
'stddevPopulation:resource:groupedAggregates:having': true;
|
|
16
|
+
'varianceSample:resource:groupedAggregates:having': true;
|
|
17
|
+
'variancePopulation:resource:groupedAggregates:having': true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
declare const Plugin: GraphileConfig.Plugin;
|
|
22
|
+
export { Plugin as PgAggregatesAddHavingAggregateTypesPlugin };
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PgAggregatesAddHavingAggregateTypesPlugin = void 0;
|
|
4
|
+
const EXPORTABLE_1 = require("./EXPORTABLE");
|
|
5
|
+
const interfaces_1 = require("./interfaces");
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
const version = '1.0.0';
|
|
8
|
+
const pgAggregatesApplyAnd = (0, EXPORTABLE_1.EXPORTABLE)(() => function apply($where) {
|
|
9
|
+
return $where;
|
|
10
|
+
}, [], 'pgAggregatesApplyAnd');
|
|
11
|
+
const pgAggregatesApplyHaving = (0, EXPORTABLE_1.EXPORTABLE)(() => function apply($filter) {
|
|
12
|
+
return $filter;
|
|
13
|
+
}, [], 'pgAggregatesApplyHaving');
|
|
14
|
+
const pgAggregatesApplyAttributeFilter = (0, EXPORTABLE_1.EXPORTABLE)(() => (PgBooleanFilter, aggregateSpec, attribute, attributeName, sql, $having) => {
|
|
15
|
+
const attributeExpression = sql.fragment `${$having.alias}.${sql.identifier(attributeName)}`;
|
|
16
|
+
const aggregateExpression = aggregateSpec.sqlAggregateWrap(attributeExpression, attribute.codec);
|
|
17
|
+
return new PgBooleanFilter($having, aggregateExpression);
|
|
18
|
+
}, [], 'pgAggregatesApplyAttributeFilter');
|
|
19
|
+
const pgAggregatesApplyComputedColumnFilter = (0, EXPORTABLE_1.EXPORTABLE)(() => (PgBooleanFilter, aggregateSpec, computedAttributeResource, from, getNullableType, isInputObjectType, makeArgsRuntime, parameterAnalysis, parameters, pgFromExpressionRuntime, $having, input, { field, schema }) => {
|
|
20
|
+
if (input == null) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const fieldType = getNullableType(field.type);
|
|
24
|
+
if (!isInputObjectType(fieldType)) {
|
|
25
|
+
throw new Error(`Expected an input object type (${field.type})`);
|
|
26
|
+
}
|
|
27
|
+
const argsField = fieldType.getFields().args;
|
|
28
|
+
const firstArg = {
|
|
29
|
+
placeholder: $having.alias,
|
|
30
|
+
position: 0
|
|
31
|
+
};
|
|
32
|
+
let src;
|
|
33
|
+
if (argsField && input.args != null) {
|
|
34
|
+
const argsType = getNullableType(fieldType.getFields().args.type);
|
|
35
|
+
if (!isInputObjectType(argsType)) {
|
|
36
|
+
throw new Error(`Expected an input object type (${argsType})`);
|
|
37
|
+
}
|
|
38
|
+
const fields = argsType.getFields();
|
|
39
|
+
// Because we require that the computed attribute is
|
|
40
|
+
// evaluated inline, we have to convert it to an
|
|
41
|
+
// expression here; this is only needed because of the
|
|
42
|
+
// aggregation.
|
|
43
|
+
src = pgFromExpressionRuntime(from, parameters, [firstArg, ...makeArgsRuntime(schema, fields, input.args)], parameterAnalysis);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
src = pgFromExpressionRuntime(from, parameters, [firstArg], parameterAnalysis);
|
|
47
|
+
}
|
|
48
|
+
const aggregateExpression = aggregateSpec.sqlAggregateWrap(src, computedAttributeResource.codec);
|
|
49
|
+
const $filter = new PgBooleanFilter($having, aggregateExpression);
|
|
50
|
+
// fieldArgs.apply($filter, "filter");
|
|
51
|
+
return $filter;
|
|
52
|
+
}, [], 'pgAggregatesApplyComputedColumnFilter');
|
|
53
|
+
const pgAggregatesPlanAggregatesField = (0, EXPORTABLE_1.EXPORTABLE)(() => function apply($having) {
|
|
54
|
+
return $having;
|
|
55
|
+
}, [], 'pgAggregatesPlanAggregatesField');
|
|
56
|
+
const pgAggregatesApplyHavingBinaryOperation = (0, EXPORTABLE_1.EXPORTABLE)(() => (codec, infix, sql, sqlValueWithCodec, $booleanFilter, input) => {
|
|
57
|
+
if (input == null)
|
|
58
|
+
return;
|
|
59
|
+
$booleanFilter.having(sql `(${sql.parens($booleanFilter.expression)} ${infix()} ${sqlValueWithCodec(input, codec)})`);
|
|
60
|
+
}, [], 'pgAggregatesApplyHavingBinaryOperation');
|
|
61
|
+
const Plugin = {
|
|
62
|
+
name: 'PgAggregatesAddHavingAggregateTypesPlugin',
|
|
63
|
+
description: `\
|
|
64
|
+
Creates the types for the 'having' clause in groupedAggregates, the fields \
|
|
65
|
+
below that for each aggregate spec, and adds fields for attributes and computed \
|
|
66
|
+
columns.`,
|
|
67
|
+
version,
|
|
68
|
+
provides: ['aggregates'],
|
|
69
|
+
after: ['PgBasicsPlugin'],
|
|
70
|
+
schema: {
|
|
71
|
+
behaviorRegistry: {
|
|
72
|
+
add: {
|
|
73
|
+
having: {
|
|
74
|
+
description: "Should we add a 'having' option to aggregates on this resource?",
|
|
75
|
+
entities: ['pgResource']
|
|
76
|
+
},
|
|
77
|
+
havingBy: {
|
|
78
|
+
description: "Should this function-like resource, or attribute, be usable in the 'having' clause when aggregating?",
|
|
79
|
+
entities: ['pgResource', 'pgCodecAttribute']
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
entityBehavior: {
|
|
84
|
+
// having - for connections' groupedAggregates field
|
|
85
|
+
// havingBy - for computed column functions acting like attributes
|
|
86
|
+
pgResource: ['order', 'having', 'havingBy'],
|
|
87
|
+
pgCodecAttribute: ['havingBy']
|
|
88
|
+
},
|
|
89
|
+
hooks: {
|
|
90
|
+
build(build) {
|
|
91
|
+
if (!build.dataplanPg) {
|
|
92
|
+
throw new Error(`PgBasicsPlugin must be loaded first`);
|
|
93
|
+
}
|
|
94
|
+
const { dataplanPg: { TYPES } } = build;
|
|
95
|
+
return build.extend(build, {
|
|
96
|
+
pgHavingFilterTypeNameForCodec(codec) {
|
|
97
|
+
switch (codec) {
|
|
98
|
+
case TYPES.int2:
|
|
99
|
+
case TYPES.int: {
|
|
100
|
+
return build.inflection.aggregateHavingFilterInputType('int');
|
|
101
|
+
}
|
|
102
|
+
case TYPES.bigint: {
|
|
103
|
+
return build.inflection.aggregateHavingFilterInputType('bigint');
|
|
104
|
+
}
|
|
105
|
+
case TYPES.float4:
|
|
106
|
+
case TYPES.float: {
|
|
107
|
+
return build.inflection.aggregateHavingFilterInputType('float');
|
|
108
|
+
}
|
|
109
|
+
case TYPES.money:
|
|
110
|
+
case TYPES.numeric: {
|
|
111
|
+
return build.inflection.aggregateHavingFilterInputType('bigfloat');
|
|
112
|
+
}
|
|
113
|
+
case TYPES.date:
|
|
114
|
+
case TYPES.timestamp:
|
|
115
|
+
case TYPES.timestamptz: {
|
|
116
|
+
return build.inflection.aggregateHavingFilterInputType('datetime');
|
|
117
|
+
}
|
|
118
|
+
case TYPES.char:
|
|
119
|
+
case TYPES.text:
|
|
120
|
+
case TYPES.varchar: {
|
|
121
|
+
return build.inflection.aggregateHavingFilterInputType('string');
|
|
122
|
+
}
|
|
123
|
+
default: {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}, 'adding pgHavingFilterTypeForTypeAndModifier');
|
|
129
|
+
},
|
|
130
|
+
init(_, build, _context) {
|
|
131
|
+
const { graphql: { GraphQLList, GraphQLNonNull, getNullableType, isInputObjectType }, inflection, sql, dataplanPg: { PgOrFilter, PgBooleanFilter, pgFromExpressionRuntime, generatePgParameterAnalysis }, EXPORTABLE } = build;
|
|
132
|
+
for (const spec of interfaces_1.CORE_HAVING_FILTER_SPECS) {
|
|
133
|
+
const name = build.inflection.aggregateHavingFilterInputType(spec);
|
|
134
|
+
build.registerInputObjectType(name, {
|
|
135
|
+
isPgHavingFilterInputType: true,
|
|
136
|
+
pgHavingFilterSpec: spec
|
|
137
|
+
}, () => ({
|
|
138
|
+
name,
|
|
139
|
+
fields: Object.create(null)
|
|
140
|
+
}), '');
|
|
141
|
+
}
|
|
142
|
+
for (const resource of Object.values(build.input.pgRegistry.pgResources)) {
|
|
143
|
+
if (resource.parameters ||
|
|
144
|
+
!resource.codec.attributes ||
|
|
145
|
+
resource.isUnique) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (!build.behavior.pgResourceMatches(resource, 'order')) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (!build.behavior.pgResourceMatches(resource, 'resource:groupedAggregates:having')) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const tableTypeName = inflection.tableType(resource.codec);
|
|
155
|
+
const tableHavingInputTypeName = inflection.aggregateHavingInputType({
|
|
156
|
+
resource: resource
|
|
157
|
+
});
|
|
158
|
+
build.registerInputObjectType(tableHavingInputTypeName, {
|
|
159
|
+
pgTypeResource: resource,
|
|
160
|
+
isPgAggregateHavingInputType: true
|
|
161
|
+
}, () => ({
|
|
162
|
+
description: build.wrapDescription(`Conditions for \`${tableTypeName}\` aggregates.`, 'type'),
|
|
163
|
+
fields: () => {
|
|
164
|
+
return {
|
|
165
|
+
AND: {
|
|
166
|
+
type: new GraphQLList(new GraphQLNonNull(build.getInputTypeByName(tableHavingInputTypeName))),
|
|
167
|
+
apply: pgAggregatesApplyAnd
|
|
168
|
+
// No need to auto-apply, the having field calls `fieldArgs.apply(...)`
|
|
169
|
+
},
|
|
170
|
+
OR: {
|
|
171
|
+
type: new GraphQLList(new GraphQLNonNull(build.getInputTypeByName(tableHavingInputTypeName))),
|
|
172
|
+
apply: EXPORTABLE((PgOrFilter) => ($where) => new PgOrFilter($where), [PgOrFilter])
|
|
173
|
+
// No need to auto-apply, the having field calls `fieldArgs.apply(...)`
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}), `Adding connection "groupBy" having input type for ${resource.name}.`);
|
|
178
|
+
const computedAttributeResources = (0, utils_1.getComputedAttributeResources)(build, resource);
|
|
179
|
+
for (const aggregateSpec of build.pgAggregateSpecs) {
|
|
180
|
+
for (const computedAttributeResource of computedAttributeResources) {
|
|
181
|
+
const argsTypeName = inflection.aggregateHavingAggregateComputedAttributeArgsInputType({
|
|
182
|
+
resource: resource,
|
|
183
|
+
aggregateSpec,
|
|
184
|
+
computedAttributeResource: computedAttributeResource
|
|
185
|
+
});
|
|
186
|
+
build.registerInputObjectType(argsTypeName, {}, () => {
|
|
187
|
+
return {
|
|
188
|
+
fields: () => {
|
|
189
|
+
const { argDetails } = build.pgGetArgDetailsFromParameters(computedAttributeResource, computedAttributeResource.parameters, 1);
|
|
190
|
+
return argDetails.reduce((memo, { inputType, graphqlArgName }) => {
|
|
191
|
+
memo[graphqlArgName] = {
|
|
192
|
+
type: inputType
|
|
193
|
+
// NO PLAN NEEDED!
|
|
194
|
+
};
|
|
195
|
+
return memo;
|
|
196
|
+
}, Object.create(null));
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}, '');
|
|
200
|
+
const computedHavingInputName = inflection.aggregateHavingAggregateComputedAttributeInputType({
|
|
201
|
+
resource: resource,
|
|
202
|
+
aggregateSpec,
|
|
203
|
+
computedAttributeResource: computedAttributeResource
|
|
204
|
+
});
|
|
205
|
+
/*const ComputedHavingInput =*/
|
|
206
|
+
build.registerInputObjectType(computedHavingInputName, {}, () => {
|
|
207
|
+
return {
|
|
208
|
+
fields: () => {
|
|
209
|
+
const havingFilterTypeName = build.pgHavingFilterTypeNameForCodec(computedAttributeResource.codec);
|
|
210
|
+
const HavingFilterType = havingFilterTypeName
|
|
211
|
+
? build.getTypeByName(havingFilterTypeName)
|
|
212
|
+
: undefined;
|
|
213
|
+
const ArgsType = build.getTypeByName(argsTypeName);
|
|
214
|
+
if (!HavingFilterType || !ArgsType) {
|
|
215
|
+
return { fields: Object.create(null) };
|
|
216
|
+
}
|
|
217
|
+
const requiresAtLeastOneArg = computedAttributeResource.parameters
|
|
218
|
+
.slice(1)
|
|
219
|
+
.some((p) => !p.optional);
|
|
220
|
+
return {
|
|
221
|
+
...(ArgsType
|
|
222
|
+
? {
|
|
223
|
+
args: {
|
|
224
|
+
type: build.nullableIf(!requiresAtLeastOneArg, ArgsType)
|
|
225
|
+
// NO PLAN NEEDED
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
: null),
|
|
229
|
+
filter: {
|
|
230
|
+
type: new GraphQLNonNull(HavingFilterType),
|
|
231
|
+
apply: pgAggregatesApplyHaving
|
|
232
|
+
// No need to auto-apply, parent calls `fieldArgs.apply($filter, "filter")` below
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
}, '');
|
|
238
|
+
}
|
|
239
|
+
const typeName = inflection.aggregateHavingAggregateInputType({
|
|
240
|
+
resource: resource,
|
|
241
|
+
aggregateSpec
|
|
242
|
+
});
|
|
243
|
+
build.registerInputObjectType(typeName, {}, () => ({
|
|
244
|
+
name: typeName,
|
|
245
|
+
fields: ({ fieldWithHooks }) => {
|
|
246
|
+
let fields = Object.create(null);
|
|
247
|
+
fields = build.extend(fields, Object.entries(resource.codec.attributes).reduce((newFields, [attributeName, attribute]) => {
|
|
248
|
+
if (!build.behavior.pgCodecAttributeMatches([resource.codec, attributeName], 'attribute:havingBy')) {
|
|
249
|
+
return newFields;
|
|
250
|
+
}
|
|
251
|
+
const fieldName = inflection.attribute({
|
|
252
|
+
codec: resource.codec,
|
|
253
|
+
attributeName: attributeName
|
|
254
|
+
});
|
|
255
|
+
const havingFilterTypeName = build.pgHavingFilterTypeNameForCodec(attribute.codec);
|
|
256
|
+
const HavingFilterType = havingFilterTypeName
|
|
257
|
+
? build.getTypeByName(havingFilterTypeName)
|
|
258
|
+
: undefined;
|
|
259
|
+
if (!HavingFilterType) {
|
|
260
|
+
return newFields;
|
|
261
|
+
}
|
|
262
|
+
const newField = fieldWithHooks({ fieldName }, () => ({
|
|
263
|
+
type: HavingFilterType,
|
|
264
|
+
apply: EXPORTABLE((PgBooleanFilter, aggregateSpec, attribute, attributeName, pgAggregatesApplyAttributeFilter, sql) => ($having) => {
|
|
265
|
+
return pgAggregatesApplyAttributeFilter(PgBooleanFilter, aggregateSpec, attribute, attributeName, sql, $having);
|
|
266
|
+
}, [
|
|
267
|
+
PgBooleanFilter,
|
|
268
|
+
aggregateSpec,
|
|
269
|
+
attribute,
|
|
270
|
+
attributeName,
|
|
271
|
+
pgAggregatesApplyAttributeFilter,
|
|
272
|
+
sql
|
|
273
|
+
])
|
|
274
|
+
}));
|
|
275
|
+
return build.extend(newFields, { [fieldName]: newField }, `Adding attribute '${attributeName}' to having filter type for '${resource.name}'`);
|
|
276
|
+
}, Object.create(null)), '');
|
|
277
|
+
fields = build.extend(fields, computedAttributeResources.reduce((memo, computedAttributeResource) => {
|
|
278
|
+
if (!build.behavior.pgResourceMatches(computedAttributeResource, 'resource:havingBy')) {
|
|
279
|
+
return memo;
|
|
280
|
+
}
|
|
281
|
+
const codec = computedAttributeResource.codec;
|
|
282
|
+
if ((aggregateSpec.shouldApplyToEntity &&
|
|
283
|
+
!aggregateSpec.shouldApplyToEntity({
|
|
284
|
+
type: 'computedAttribute',
|
|
285
|
+
resource: computedAttributeResource
|
|
286
|
+
})) ||
|
|
287
|
+
!aggregateSpec.isSuitableType(codec)) {
|
|
288
|
+
return memo;
|
|
289
|
+
}
|
|
290
|
+
const argsTypeName = inflection.aggregateHavingAggregateComputedAttributeArgsInputType({
|
|
291
|
+
resource: resource,
|
|
292
|
+
aggregateSpec,
|
|
293
|
+
computedAttributeResource: computedAttributeResource
|
|
294
|
+
});
|
|
295
|
+
const havingFilterTypeName = build.pgHavingFilterTypeNameForCodec(computedAttributeResource.codec);
|
|
296
|
+
const HavingFilterType = havingFilterTypeName
|
|
297
|
+
? build.getTypeByName(havingFilterTypeName)
|
|
298
|
+
: undefined;
|
|
299
|
+
const ArgsType = build.getTypeByName(argsTypeName);
|
|
300
|
+
const computedHavingInputName = inflection.aggregateHavingAggregateComputedAttributeInputType({
|
|
301
|
+
resource: resource,
|
|
302
|
+
aggregateSpec,
|
|
303
|
+
computedAttributeResource: computedAttributeResource
|
|
304
|
+
});
|
|
305
|
+
const ComputedHavingInput = build.getTypeByName(computedHavingInputName);
|
|
306
|
+
if (!HavingFilterType ||
|
|
307
|
+
!ArgsType ||
|
|
308
|
+
!ComputedHavingInput) {
|
|
309
|
+
return memo;
|
|
310
|
+
}
|
|
311
|
+
const fieldName = inflection.computedAttributeField({
|
|
312
|
+
resource: computedAttributeResource
|
|
313
|
+
});
|
|
314
|
+
const { from: rawFrom, parameters } = computedAttributeResource;
|
|
315
|
+
const { makeArgsRuntime } = build.pgGetArgDetailsFromParameters(computedAttributeResource, parameters, 1);
|
|
316
|
+
const parameterAnalysis = EXPORTABLE((generatePgParameterAnalysis, parameters) => generatePgParameterAnalysis(parameters), [generatePgParameterAnalysis, parameters], `${computedAttributeResource.name}ParameterAnalysis`);
|
|
317
|
+
const from = typeof rawFrom === 'function'
|
|
318
|
+
? rawFrom
|
|
319
|
+
: () => rawFrom;
|
|
320
|
+
const newField = fieldWithHooks({ fieldName }, {
|
|
321
|
+
type: ComputedHavingInput,
|
|
322
|
+
apply: EXPORTABLE((PgBooleanFilter, aggregateSpec, computedAttributeResource, from, getNullableType, isInputObjectType, makeArgsRuntime, parameterAnalysis, parameters, pgAggregatesApplyComputedColumnFilter, pgFromExpressionRuntime) => ($having, input, info) => {
|
|
323
|
+
return pgAggregatesApplyComputedColumnFilter(PgBooleanFilter, aggregateSpec, computedAttributeResource, from, getNullableType, isInputObjectType, makeArgsRuntime, parameterAnalysis, parameters, pgFromExpressionRuntime, $having, input, info);
|
|
324
|
+
}, [
|
|
325
|
+
PgBooleanFilter,
|
|
326
|
+
aggregateSpec,
|
|
327
|
+
computedAttributeResource,
|
|
328
|
+
from,
|
|
329
|
+
getNullableType,
|
|
330
|
+
isInputObjectType,
|
|
331
|
+
makeArgsRuntime,
|
|
332
|
+
parameterAnalysis,
|
|
333
|
+
parameters,
|
|
334
|
+
pgAggregatesApplyComputedColumnFilter,
|
|
335
|
+
pgFromExpressionRuntime
|
|
336
|
+
])
|
|
337
|
+
// No need to auto-apply, parent does `return $having;`
|
|
338
|
+
});
|
|
339
|
+
return build.extend(memo, { [fieldName]: newField }, `Adding computed attribute function '${computedAttributeResource.name}' to having filter type for '${resource.name}'`);
|
|
340
|
+
}, Object.create(null)), '');
|
|
341
|
+
return fields;
|
|
342
|
+
}
|
|
343
|
+
}), '');
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return _;
|
|
347
|
+
},
|
|
348
|
+
GraphQLInputObjectType_fields(inFields, build, context) {
|
|
349
|
+
const { sql, inflection, dataplanPg: { TYPES, sqlValueWithCodec }, EXPORTABLE } = build;
|
|
350
|
+
const { scope: { isPgHavingFilterInputType, pgHavingFilterSpec, isPgAggregateHavingInputType, pgTypeResource: table }, fieldWithHooks } = context;
|
|
351
|
+
let fields = inFields;
|
|
352
|
+
fields = (() => {
|
|
353
|
+
if (!isPgAggregateHavingInputType ||
|
|
354
|
+
!table ||
|
|
355
|
+
table.parameters ||
|
|
356
|
+
!table.codec.attributes) {
|
|
357
|
+
return fields;
|
|
358
|
+
}
|
|
359
|
+
return build.extend(fields, build.pgAggregateSpecs.reduce((aggregateFields, aggregateSpec) => {
|
|
360
|
+
if (!build.behavior.pgResourceMatches(table, `${aggregateSpec.id}:resource:groupedAggregates:having`)) {
|
|
361
|
+
return aggregateFields;
|
|
362
|
+
}
|
|
363
|
+
const typeName = inflection.aggregateHavingAggregateInputType({
|
|
364
|
+
resource: table,
|
|
365
|
+
aggregateSpec
|
|
366
|
+
});
|
|
367
|
+
const SpecInput = build.getTypeByName(typeName);
|
|
368
|
+
if (!SpecInput) {
|
|
369
|
+
return aggregateFields;
|
|
370
|
+
}
|
|
371
|
+
const fieldName = inflection.aggregatesField({ aggregateSpec });
|
|
372
|
+
return build.extend(aggregateFields, {
|
|
373
|
+
[fieldName]: fieldWithHooks({ fieldName }, // e.g. 'average' or 'stddevPopulation'
|
|
374
|
+
{
|
|
375
|
+
type: SpecInput,
|
|
376
|
+
apply: pgAggregatesPlanAggregatesField
|
|
377
|
+
// No need to auto-apply, `filter` field does `return new PgBooleanFilter($having, aggregateExpression)`
|
|
378
|
+
})
|
|
379
|
+
}, '');
|
|
380
|
+
}, Object.create(null)), `Adding attributes to having filter for '${table.name}'`);
|
|
381
|
+
})();
|
|
382
|
+
fields = (() => {
|
|
383
|
+
if (!isPgHavingFilterInputType) {
|
|
384
|
+
return fields;
|
|
385
|
+
}
|
|
386
|
+
const rawCodec = (() => {
|
|
387
|
+
switch (pgHavingFilterSpec) {
|
|
388
|
+
case 'int':
|
|
389
|
+
return TYPES.int;
|
|
390
|
+
case 'bigint':
|
|
391
|
+
return TYPES.bigint;
|
|
392
|
+
case 'float':
|
|
393
|
+
return TYPES.float;
|
|
394
|
+
case 'bigfloat':
|
|
395
|
+
return TYPES.numeric;
|
|
396
|
+
case 'datetime':
|
|
397
|
+
return TYPES.timestamptz;
|
|
398
|
+
default: {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
})();
|
|
403
|
+
if (rawCodec === null) {
|
|
404
|
+
return fields;
|
|
405
|
+
}
|
|
406
|
+
const codec = rawCodec;
|
|
407
|
+
const FieldType = build.getGraphQLTypeByPgCodec(codec, 'input');
|
|
408
|
+
if (FieldType == null) {
|
|
409
|
+
return fields;
|
|
410
|
+
}
|
|
411
|
+
function addBinaryOp(fieldName, infix) {
|
|
412
|
+
fields = build.extend(fields, {
|
|
413
|
+
[fieldName]: fieldWithHooks({ fieldName }, {
|
|
414
|
+
type: FieldType,
|
|
415
|
+
apply: EXPORTABLE((codec, infix, pgAggregatesApplyHavingBinaryOperation, sql, sqlValueWithCodec) => ($booleanFilter, input) => {
|
|
416
|
+
return pgAggregatesApplyHavingBinaryOperation(codec, infix, sql, sqlValueWithCodec, $booleanFilter, input);
|
|
417
|
+
}, [
|
|
418
|
+
codec,
|
|
419
|
+
infix,
|
|
420
|
+
pgAggregatesApplyHavingBinaryOperation,
|
|
421
|
+
sql,
|
|
422
|
+
sqlValueWithCodec
|
|
423
|
+
])
|
|
424
|
+
// No need to auto-apply
|
|
425
|
+
})
|
|
426
|
+
}, '');
|
|
427
|
+
}
|
|
428
|
+
switch (pgHavingFilterSpec) {
|
|
429
|
+
case 'int':
|
|
430
|
+
case 'bigint':
|
|
431
|
+
case 'float':
|
|
432
|
+
case 'bigfloat':
|
|
433
|
+
case 'datetime': {
|
|
434
|
+
addBinaryOp('equalTo', EXPORTABLE((sql) => () => sql.fragment `=`, [sql]));
|
|
435
|
+
addBinaryOp('notEqualTo', EXPORTABLE((sql) => () => sql.fragment `<>`, [sql]));
|
|
436
|
+
addBinaryOp('greaterThan', EXPORTABLE((sql) => () => sql.fragment `>`, [sql]));
|
|
437
|
+
addBinaryOp('greaterThanOrEqualTo', EXPORTABLE((sql) => () => sql.fragment `>=`, [sql]));
|
|
438
|
+
addBinaryOp('lessThan', EXPORTABLE((sql) => () => sql.fragment `<`, [sql]));
|
|
439
|
+
addBinaryOp('lessThanOrEqualTo', EXPORTABLE((sql) => () => sql.fragment `<=`, [sql]));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return fields;
|
|
443
|
+
})();
|
|
444
|
+
return fields;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
exports.PgAggregatesAddHavingAggregateTypesPlugin = Plugin;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const PgAggregatesSpecsPlugin: GraphileConfig.Plugin;
|