@strapi/plugin-graphql 4.0.0-next.9 → 4.0.3
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/README.md +1 -1
- package/admin/src/index.js +0 -8
- package/package.json +44 -36
- package/server/bootstrap.js +148 -0
- package/server/config/default-config.js +13 -0
- package/server/config/index.js +7 -0
- package/server/format-graphql-error.js +50 -0
- package/server/services/builders/dynamic-zones.js +97 -0
- package/server/services/builders/entity-meta.js +7 -0
- package/server/services/builders/entity.js +43 -0
- package/server/services/builders/enums.js +24 -0
- package/server/services/builders/filters/content-type.js +93 -0
- package/server/services/builders/filters/index.js +7 -0
- package/server/services/builders/filters/operators/and.js +15 -0
- package/server/services/builders/filters/operators/between.js +15 -0
- package/server/services/builders/filters/operators/contains.js +13 -0
- package/server/services/builders/filters/operators/containsi.js +13 -0
- package/server/services/builders/filters/operators/ends-with.js +13 -0
- package/server/services/builders/filters/operators/eq.js +23 -0
- package/server/services/builders/filters/operators/gt.js +13 -0
- package/server/services/builders/filters/operators/gte.js +13 -0
- package/server/services/builders/filters/operators/in.js +15 -0
- package/server/services/builders/filters/operators/index.js +38 -0
- package/server/services/builders/filters/operators/lt.js +13 -0
- package/server/services/builders/filters/operators/lte.js +13 -0
- package/server/services/builders/filters/operators/ne.js +13 -0
- package/server/services/builders/filters/operators/not-contains.js +13 -0
- package/server/services/builders/filters/operators/not-containsi.js +13 -0
- package/server/services/builders/filters/operators/not-in.js +15 -0
- package/server/services/builders/filters/operators/not-null.js +13 -0
- package/server/services/builders/filters/operators/not.js +19 -0
- package/server/services/builders/filters/operators/null.js +13 -0
- package/server/services/builders/filters/operators/or.js +15 -0
- package/server/services/builders/filters/operators/starts-with.js +13 -0
- package/server/services/builders/generic-morph.js +41 -0
- package/server/services/builders/index.js +92 -0
- package/server/services/builders/input.js +121 -0
- package/server/services/builders/mutations/collection-type.js +191 -0
- package/server/services/builders/mutations/index.js +9 -0
- package/server/services/builders/mutations/single-type.js +141 -0
- package/server/services/builders/queries/collection-type.js +120 -0
- package/server/services/builders/queries/index.js +9 -0
- package/server/services/builders/queries/single-type.js +70 -0
- package/server/services/builders/relation-response-collection.js +35 -0
- package/server/services/builders/resolvers/association.js +85 -0
- package/server/services/builders/resolvers/component.js +18 -0
- package/server/services/builders/resolvers/dynamic-zone.js +9 -0
- package/server/services/builders/resolvers/index.js +18 -0
- package/server/services/builders/resolvers/mutation.js +33 -0
- package/server/services/builders/resolvers/query.js +19 -0
- package/server/services/builders/response-collection.js +43 -0
- package/server/services/builders/response.js +32 -0
- package/server/services/builders/type.js +364 -0
- package/server/services/builders/utils.js +134 -0
- package/server/services/constants.js +149 -0
- package/server/services/content-api/index.js +179 -0
- package/server/services/content-api/policy.js +60 -0
- package/server/services/content-api/register-functions/collection-type.js +72 -0
- package/server/services/content-api/register-functions/component.js +15 -0
- package/server/services/content-api/register-functions/content-type/dynamic-zones.js +36 -0
- package/server/services/content-api/register-functions/content-type/enums.js +33 -0
- package/server/services/content-api/register-functions/content-type/filters.js +15 -0
- package/server/services/content-api/register-functions/content-type/index.js +13 -0
- package/server/services/content-api/register-functions/content-type/inputs.js +21 -0
- package/server/services/content-api/register-functions/index.js +22 -0
- package/server/services/content-api/register-functions/internals.js +13 -0
- package/server/services/content-api/register-functions/polymorphic.js +69 -0
- package/server/services/content-api/register-functions/scalars.js +14 -0
- package/server/services/content-api/register-functions/single-type.js +72 -0
- package/server/services/content-api/wrap-resolvers.js +144 -0
- package/server/services/extension/extension.js +95 -0
- package/server/services/extension/index.js +5 -0
- package/server/services/extension/shadow-crud-manager.js +159 -0
- package/server/services/format/index.js +7 -0
- package/server/services/format/return-types.js +27 -0
- package/server/services/index.js +21 -0
- package/server/services/internals/args/index.js +11 -0
- package/server/services/internals/args/pagination.js +19 -0
- package/server/services/internals/args/publication-state.js +12 -0
- package/server/services/internals/args/sort.js +10 -0
- package/server/services/internals/helpers/get-enabled-scalars.js +15 -0
- package/server/services/internals/helpers/index.js +7 -0
- package/server/services/internals/index.js +13 -0
- package/server/services/internals/scalars/index.js +18 -0
- package/server/services/internals/scalars/time.js +36 -0
- package/server/services/internals/types/error.js +34 -0
- package/server/services/internals/types/filters.js +39 -0
- package/server/services/internals/types/index.js +29 -0
- package/server/services/internals/types/pagination.js +24 -0
- package/server/services/internals/types/publication-state.js +24 -0
- package/server/services/internals/types/response-collection-meta.js +39 -0
- package/server/services/type-registry.js +104 -0
- package/server/services/utils/attributes.js +84 -0
- package/server/services/utils/index.js +11 -0
- package/server/services/utils/mappers/entity-to-response-entity.js +12 -0
- package/server/services/utils/mappers/graphql-filters-to-strapi-query.js +109 -0
- package/server/services/utils/mappers/graphql-scalar-to-operators.js +17 -0
- package/server/services/utils/mappers/index.js +13 -0
- package/server/services/utils/mappers/strapi-scalar-to-graphql-scalar.js +25 -0
- package/server/services/utils/naming.js +287 -0
- package/strapi-admin.js +3 -0
- package/strapi-server.js +7 -9
- package/admin/src/assets/images/logo.svg +0 -38
- package/config/routes.json +0 -3
- package/config/schema.graphql +0 -1
- package/config/settings.json +0 -12
- package/controllers/GraphQL.js +0 -9
- package/hooks/graphql/defaults.json +0 -5
- package/hooks/graphql/index.js +0 -174
- package/hooks/graphql/load-config.js +0 -42
- package/services/build-aggregation.js +0 -565
- package/services/data-loaders.js +0 -55
- package/services/naming.js +0 -15
- package/services/resolvers-builder.js +0 -204
- package/services/schema-definitions.js +0 -131
- package/services/schema-generator.js +0 -178
- package/services/shadow-crud.js +0 -612
- package/services/type-builder.js +0 -311
- package/services/utils.js +0 -200
- package/types/dynamiczoneScalar.js +0 -40
- package/types/publication-state.js +0 -16
- package/types/time.js +0 -26
package/services/shadow-crud.js
DELETED
|
@@ -1,612 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const _ = require('lodash');
|
|
4
|
-
const { contentTypes } = require('@strapi/utils');
|
|
5
|
-
|
|
6
|
-
const {
|
|
7
|
-
hasDraftAndPublish,
|
|
8
|
-
constants: { DP_PUB_STATE_LIVE },
|
|
9
|
-
} = contentTypes;
|
|
10
|
-
|
|
11
|
-
const DynamicZoneScalar = require('../types/dynamiczoneScalar');
|
|
12
|
-
|
|
13
|
-
const { formatModelConnectionsGQL } = require('./build-aggregation');
|
|
14
|
-
const types = require('./type-builder');
|
|
15
|
-
const {
|
|
16
|
-
actionExists,
|
|
17
|
-
mergeSchemas,
|
|
18
|
-
convertToParams,
|
|
19
|
-
convertToQuery,
|
|
20
|
-
amountLimiting,
|
|
21
|
-
createDefaultSchema,
|
|
22
|
-
} = require('./utils');
|
|
23
|
-
const { toSDL, getTypeDescription } = require('./schema-definitions');
|
|
24
|
-
const { toSingular, toPlural } = require('./naming');
|
|
25
|
-
const { buildQuery, buildMutation } = require('./resolvers-builder');
|
|
26
|
-
|
|
27
|
-
const OPTIONS = Symbol();
|
|
28
|
-
|
|
29
|
-
const FIND_QUERY_ARGUMENTS = {
|
|
30
|
-
sort: 'String',
|
|
31
|
-
limit: 'Int',
|
|
32
|
-
start: 'Int',
|
|
33
|
-
where: 'JSON',
|
|
34
|
-
publicationState: 'PublicationState',
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const FIND_ONE_QUERY_ARGUMENTS = {
|
|
38
|
-
id: 'ID!',
|
|
39
|
-
publicationState: 'PublicationState',
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Builds a graphql schema from all the contentTypes & components loaded
|
|
44
|
-
* @param {{ schema: object }} ctx
|
|
45
|
-
* @returns {object}
|
|
46
|
-
*/
|
|
47
|
-
const buildShadowCrud = ctx => {
|
|
48
|
-
const models = Object.values(strapi.contentTypes).filter(model => model.plugin !== 'admin');
|
|
49
|
-
const components = Object.values(strapi.components);
|
|
50
|
-
|
|
51
|
-
const allSchemas = buildModels([...models, ...components], ctx);
|
|
52
|
-
|
|
53
|
-
return mergeSchemas(createDefaultSchema(), ...allSchemas);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const assignOptions = (element, parent) => {
|
|
57
|
-
if (Array.isArray(element)) {
|
|
58
|
-
return element.map(el => assignOptions(el, parent));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return _.set(element, OPTIONS, _.get(parent, OPTIONS, {}));
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const isQueryEnabled = (schema, name) => {
|
|
65
|
-
return _.get(schema, `resolver.Query.${name}`) !== false;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const getQueryInfo = (schema, name) => {
|
|
69
|
-
return _.get(schema, `resolver.Query.${name}`, {});
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const isMutationEnabled = (schema, name) => {
|
|
73
|
-
return _.get(schema, `resolver.Mutation.${name}`) !== false;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const getMutationInfo = (schema, name) => {
|
|
77
|
-
return _.get(schema, `resolver.Mutation.${name}`, {});
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const isTypeAttributeEnabled = (model, attr) =>
|
|
81
|
-
_.get(strapi.plugins.graphql, `config._schema.graphql.type.${model.globalId}.${attr}`) !== false;
|
|
82
|
-
const isNotPrivate = _.curry((model, attributeName) => {
|
|
83
|
-
return !contentTypes.isPrivateAttribute(model, attributeName);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
const wrapPublicationStateResolver = query => async (parent, args, ctx, ast) => {
|
|
87
|
-
const results = await query(parent, args, ctx, ast);
|
|
88
|
-
|
|
89
|
-
const queryOptions = _.pick(args, 'publicationState');
|
|
90
|
-
return assignOptions(results, { [OPTIONS]: queryOptions });
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const buildTypeDefObj = model => {
|
|
94
|
-
const { associations = [], attributes, primaryKey, globalId } = model;
|
|
95
|
-
|
|
96
|
-
const typeDef = {
|
|
97
|
-
id: 'ID!',
|
|
98
|
-
[primaryKey]: 'ID!',
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// Add timestamps attributes.
|
|
102
|
-
if (_.isArray(_.get(model, 'options.timestamps'))) {
|
|
103
|
-
const [createdAtKey, updatedAtKey] = model.options.timestamps;
|
|
104
|
-
typeDef[createdAtKey] = 'DateTime!';
|
|
105
|
-
typeDef[updatedAtKey] = 'DateTime!';
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
Object.keys(attributes)
|
|
109
|
-
.filter(isNotPrivate(model))
|
|
110
|
-
.filter(attributeName => isTypeAttributeEnabled(model, attributeName))
|
|
111
|
-
.forEach(attributeName => {
|
|
112
|
-
const attribute = attributes[attributeName];
|
|
113
|
-
// Convert our type to the GraphQL type.
|
|
114
|
-
typeDef[attributeName] = types.convertType({
|
|
115
|
-
attribute,
|
|
116
|
-
modelName: globalId,
|
|
117
|
-
attributeName,
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
// Change field definition for collection relations
|
|
122
|
-
associations
|
|
123
|
-
.filter(association => association.type === 'collection')
|
|
124
|
-
.filter(association => isNotPrivate(model, association.alias))
|
|
125
|
-
.filter(attributeName => isTypeAttributeEnabled(model, attributeName))
|
|
126
|
-
.forEach(association => {
|
|
127
|
-
typeDef[`${association.alias}(sort: String, limit: Int, start: Int, where: JSON)`] =
|
|
128
|
-
typeDef[association.alias];
|
|
129
|
-
|
|
130
|
-
delete typeDef[association.alias];
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
return typeDef;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
const generateEnumDefinitions = (model, globalId) => {
|
|
137
|
-
const { attributes } = model;
|
|
138
|
-
return Object.keys(attributes)
|
|
139
|
-
.filter(attribute => attributes[attribute].type === 'enumeration')
|
|
140
|
-
.filter(attribute => isTypeAttributeEnabled(model, attribute))
|
|
141
|
-
.map(attribute => {
|
|
142
|
-
const definition = attributes[attribute];
|
|
143
|
-
|
|
144
|
-
const name = types.convertEnumType(definition, globalId, attribute);
|
|
145
|
-
const values = definition.enum.map(v => `\t${v}`).join('\n');
|
|
146
|
-
return `enum ${name} {\n${values}\n}\n`;
|
|
147
|
-
})
|
|
148
|
-
.join('');
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const generateDynamicZoneDefinitions = (attributes, globalId, schema) => {
|
|
152
|
-
Object.keys(attributes)
|
|
153
|
-
.filter(attribute => attributes[attribute].type === 'dynamiczone')
|
|
154
|
-
.forEach(attribute => {
|
|
155
|
-
const { components } = attributes[attribute];
|
|
156
|
-
|
|
157
|
-
const typeName = `${globalId}${_.upperFirst(_.camelCase(attribute))}DynamicZone`;
|
|
158
|
-
|
|
159
|
-
if (components.length === 0) {
|
|
160
|
-
// Create dummy type because graphql doesn't support empty ones
|
|
161
|
-
schema.definition += `type ${typeName} { _:Boolean}`;
|
|
162
|
-
} else {
|
|
163
|
-
const componentsTypeNames = components.map(componentUID => {
|
|
164
|
-
const compo = strapi.components[componentUID];
|
|
165
|
-
if (!compo) {
|
|
166
|
-
throw new Error(
|
|
167
|
-
`Trying to creating dynamiczone type with unkown component ${componentUID}`
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return compo.globalId;
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
const unionType = `union ${typeName} = ${componentsTypeNames.join(' | ')}`;
|
|
175
|
-
|
|
176
|
-
schema.definition += `\n${unionType}\n`;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const inputTypeName = `${typeName}Input`;
|
|
180
|
-
schema.definition += `\nscalar ${inputTypeName}\n`;
|
|
181
|
-
|
|
182
|
-
schema.resolvers[typeName] = {
|
|
183
|
-
__resolveType(obj) {
|
|
184
|
-
return strapi.components[obj.__component].globalId;
|
|
185
|
-
},
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
schema.resolvers[inputTypeName] = new DynamicZoneScalar({
|
|
189
|
-
name: inputTypeName,
|
|
190
|
-
attribute,
|
|
191
|
-
globalId,
|
|
192
|
-
components,
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
const initQueryOptions = (targetModel, parent) => {
|
|
198
|
-
if (hasDraftAndPublish(targetModel)) {
|
|
199
|
-
return {
|
|
200
|
-
_publicationState: _.get(parent, [OPTIONS, 'publicationState'], DP_PUB_STATE_LIVE),
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return {};
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
const buildAssocResolvers = model => {
|
|
208
|
-
const { primaryKey, associations = [] } = model;
|
|
209
|
-
|
|
210
|
-
return associations
|
|
211
|
-
.filter(association => isNotPrivate(model, association.alias))
|
|
212
|
-
.filter(association => isTypeAttributeEnabled(model, association.alias))
|
|
213
|
-
.reduce((resolver, association) => {
|
|
214
|
-
const target = association.model || association.collection;
|
|
215
|
-
const targetModel = strapi.getModel(target, association.plugin);
|
|
216
|
-
|
|
217
|
-
const { nature, alias } = association;
|
|
218
|
-
|
|
219
|
-
switch (nature) {
|
|
220
|
-
case 'oneToManyMorph':
|
|
221
|
-
case 'manyMorphToOne':
|
|
222
|
-
case 'manyMorphToMany':
|
|
223
|
-
case 'manyToManyMorph': {
|
|
224
|
-
resolver[alias] = async obj => {
|
|
225
|
-
if (obj[alias]) {
|
|
226
|
-
return assignOptions(obj[alias], obj);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const params = {
|
|
230
|
-
...initQueryOptions(targetModel, obj),
|
|
231
|
-
id: obj[primaryKey],
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
const entry = await strapi.query(model.uid).findOne(params, [alias]);
|
|
235
|
-
|
|
236
|
-
return assignOptions(entry[alias], obj);
|
|
237
|
-
};
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
240
|
-
default: {
|
|
241
|
-
resolver[alias] = async (obj, options) => {
|
|
242
|
-
// force component relations to be refetched
|
|
243
|
-
if (model.modelType === 'component') {
|
|
244
|
-
obj[alias] = _.get(obj[alias], targetModel.primaryKey, obj[alias]);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const loader = strapi.plugins.graphql.services['data-loaders'].loaders[targetModel.uid];
|
|
248
|
-
|
|
249
|
-
const localId = obj[model.primaryKey];
|
|
250
|
-
const targetPK = targetModel.primaryKey;
|
|
251
|
-
const foreignId = _.get(obj[alias], targetModel.primaryKey, obj[alias]);
|
|
252
|
-
|
|
253
|
-
const params = {
|
|
254
|
-
...initQueryOptions(targetModel, obj),
|
|
255
|
-
...convertToParams(_.omit(amountLimiting(options), 'where')),
|
|
256
|
-
...convertToQuery(options.where),
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
if (['oneToOne', 'oneWay', 'manyToOne'].includes(nature)) {
|
|
260
|
-
if (!_.has(obj, alias) || _.isNil(foreignId)) {
|
|
261
|
-
return null;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// check this is an entity and not a mongo ID
|
|
265
|
-
if (_.has(obj[alias], targetPK)) {
|
|
266
|
-
return assignOptions(obj[alias], obj);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
const query = {
|
|
270
|
-
single: true,
|
|
271
|
-
filters: {
|
|
272
|
-
...params,
|
|
273
|
-
[targetPK]: foreignId,
|
|
274
|
-
},
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
return loader.load(query).then(r => assignOptions(r, obj));
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (
|
|
281
|
-
nature === 'oneToMany' ||
|
|
282
|
-
(nature === 'manyToMany' && association.dominant !== true)
|
|
283
|
-
) {
|
|
284
|
-
const { via } = association;
|
|
285
|
-
|
|
286
|
-
const filters = {
|
|
287
|
-
...params,
|
|
288
|
-
[via]: localId,
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
return loader.load({ filters }).then(r => assignOptions(r, obj));
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (
|
|
295
|
-
nature === 'manyWay' ||
|
|
296
|
-
(nature === 'manyToMany' && association.dominant === true)
|
|
297
|
-
) {
|
|
298
|
-
let targetIds = [];
|
|
299
|
-
|
|
300
|
-
// find the related ids to query them and apply the filters
|
|
301
|
-
if (Array.isArray(obj[alias])) {
|
|
302
|
-
targetIds = obj[alias].map(value => value[targetPK] || value);
|
|
303
|
-
} else {
|
|
304
|
-
const entry = await strapi
|
|
305
|
-
.query(model.uid)
|
|
306
|
-
.findOne({ [primaryKey]: obj[primaryKey] }, [alias]);
|
|
307
|
-
|
|
308
|
-
if (_.isEmpty(entry[alias])) {
|
|
309
|
-
return [];
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
targetIds = entry[alias].map(el => el[targetPK]);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const filters = {
|
|
316
|
-
...params,
|
|
317
|
-
[`${targetPK}_in`]: targetIds.map(_.toString),
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
return loader.load({ filters }).then(r => assignOptions(r, obj));
|
|
321
|
-
}
|
|
322
|
-
};
|
|
323
|
-
break;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return resolver;
|
|
328
|
-
}, {});
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Construct the GraphQL query & definition and apply the right resolvers.
|
|
333
|
-
*
|
|
334
|
-
* @return Object
|
|
335
|
-
*/
|
|
336
|
-
const buildModels = (models, ctx) => {
|
|
337
|
-
return models.map(model => {
|
|
338
|
-
const { kind, modelType } = model;
|
|
339
|
-
|
|
340
|
-
if (modelType === 'component') {
|
|
341
|
-
return buildComponent(model);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
switch (kind) {
|
|
345
|
-
case 'singleType':
|
|
346
|
-
return buildSingleType(model, ctx);
|
|
347
|
-
default:
|
|
348
|
-
return buildCollectionType(model, ctx);
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
const buildModelDefinition = (model, globalType = {}) => {
|
|
354
|
-
const { globalId, primaryKey } = model;
|
|
355
|
-
|
|
356
|
-
const typeDefObj = buildTypeDefObj(model);
|
|
357
|
-
|
|
358
|
-
const schema = {
|
|
359
|
-
definition: '',
|
|
360
|
-
query: {},
|
|
361
|
-
mutation: {},
|
|
362
|
-
resolvers: {
|
|
363
|
-
Query: {},
|
|
364
|
-
Mutation: {},
|
|
365
|
-
[globalId]: {
|
|
366
|
-
id: parent => parent[primaryKey] || parent.id,
|
|
367
|
-
...buildAssocResolvers(model),
|
|
368
|
-
},
|
|
369
|
-
},
|
|
370
|
-
typeDefObj,
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
schema.definition += generateEnumDefinitions(model, globalId);
|
|
374
|
-
generateDynamicZoneDefinitions(model.attributes, globalId, schema);
|
|
375
|
-
|
|
376
|
-
const description = getTypeDescription(globalType, model);
|
|
377
|
-
const fields = toSDL(typeDefObj, globalType, model);
|
|
378
|
-
const typeDef = `${description}type ${globalId} {${fields}}\n`;
|
|
379
|
-
|
|
380
|
-
schema.definition += typeDef;
|
|
381
|
-
return schema;
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
const buildComponent = component => {
|
|
385
|
-
const { globalId } = component;
|
|
386
|
-
const schema = buildModelDefinition(component);
|
|
387
|
-
|
|
388
|
-
schema.definition += types.generateInputModel(component, globalId, {
|
|
389
|
-
allowIds: true,
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
return schema;
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
const buildSingleType = (model, ctx) => {
|
|
396
|
-
const { uid, modelName } = model;
|
|
397
|
-
|
|
398
|
-
const singularName = toSingular(modelName);
|
|
399
|
-
|
|
400
|
-
const globalType = _.get(ctx.schema, `type.${model.globalId}`, {});
|
|
401
|
-
|
|
402
|
-
const localSchema = buildModelDefinition(model, globalType);
|
|
403
|
-
|
|
404
|
-
// Add definition to the schema but this type won't be "queriable" or "mutable".
|
|
405
|
-
if (globalType === false) {
|
|
406
|
-
return localSchema;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
if (isQueryEnabled(ctx.schema, singularName)) {
|
|
410
|
-
const resolverOpts = {
|
|
411
|
-
resolver: `${uid}.find`,
|
|
412
|
-
...getQueryInfo(ctx.schema, singularName),
|
|
413
|
-
};
|
|
414
|
-
|
|
415
|
-
const resolver = buildQuery(singularName, resolverOpts);
|
|
416
|
-
|
|
417
|
-
const query = {
|
|
418
|
-
query: {
|
|
419
|
-
[singularName]: {
|
|
420
|
-
args: {
|
|
421
|
-
publicationState: 'PublicationState',
|
|
422
|
-
...(resolverOpts.args || {}),
|
|
423
|
-
},
|
|
424
|
-
type: model.globalId,
|
|
425
|
-
},
|
|
426
|
-
},
|
|
427
|
-
resolvers: {
|
|
428
|
-
Query: {
|
|
429
|
-
[singularName]: wrapPublicationStateResolver(resolver),
|
|
430
|
-
},
|
|
431
|
-
},
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
_.merge(localSchema, query);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// Add model Input definition.
|
|
438
|
-
localSchema.definition += types.generateInputModel(model, modelName);
|
|
439
|
-
|
|
440
|
-
// build every mutation
|
|
441
|
-
['update', 'delete'].forEach(action => {
|
|
442
|
-
const mutationSchema = buildMutationTypeDef({ model, action }, ctx);
|
|
443
|
-
|
|
444
|
-
mergeSchemas(localSchema, mutationSchema);
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
return localSchema;
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
const buildCollectionType = (model, ctx) => {
|
|
451
|
-
const { plugin, modelName, uid } = model;
|
|
452
|
-
|
|
453
|
-
const singularName = toSingular(modelName);
|
|
454
|
-
const pluralName = toPlural(modelName);
|
|
455
|
-
|
|
456
|
-
const globalType = _.get(ctx.schema, `type.${model.globalId}`, {});
|
|
457
|
-
|
|
458
|
-
const localSchema = buildModelDefinition(model, globalType);
|
|
459
|
-
const { typeDefObj } = localSchema;
|
|
460
|
-
|
|
461
|
-
// Add definition to the schema but this type won't be "queriable" or "mutable".
|
|
462
|
-
if (globalType === false) {
|
|
463
|
-
return localSchema;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
if (isQueryEnabled(ctx.schema, singularName)) {
|
|
467
|
-
const resolverOpts = {
|
|
468
|
-
resolver: `${uid}.findOne`,
|
|
469
|
-
...getQueryInfo(ctx.schema, singularName),
|
|
470
|
-
};
|
|
471
|
-
|
|
472
|
-
if (actionExists(resolverOpts)) {
|
|
473
|
-
const resolver = buildQuery(singularName, resolverOpts);
|
|
474
|
-
|
|
475
|
-
const query = {
|
|
476
|
-
query: {
|
|
477
|
-
[singularName]: {
|
|
478
|
-
args: {
|
|
479
|
-
...FIND_ONE_QUERY_ARGUMENTS,
|
|
480
|
-
...(resolverOpts.args || {}),
|
|
481
|
-
},
|
|
482
|
-
type: model.globalId,
|
|
483
|
-
},
|
|
484
|
-
},
|
|
485
|
-
resolvers: {
|
|
486
|
-
Query: {
|
|
487
|
-
[singularName]: wrapPublicationStateResolver(resolver),
|
|
488
|
-
},
|
|
489
|
-
},
|
|
490
|
-
};
|
|
491
|
-
|
|
492
|
-
_.merge(localSchema, query);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
if (isQueryEnabled(ctx.schema, pluralName)) {
|
|
497
|
-
const resolverOpts = {
|
|
498
|
-
resolver: `${uid}.find`,
|
|
499
|
-
...getQueryInfo(ctx.schema, pluralName),
|
|
500
|
-
};
|
|
501
|
-
|
|
502
|
-
if (actionExists(resolverOpts)) {
|
|
503
|
-
const resolver = buildQuery(pluralName, resolverOpts);
|
|
504
|
-
|
|
505
|
-
const query = {
|
|
506
|
-
query: {
|
|
507
|
-
[pluralName]: {
|
|
508
|
-
args: {
|
|
509
|
-
...FIND_QUERY_ARGUMENTS,
|
|
510
|
-
...(resolverOpts.args || {}),
|
|
511
|
-
},
|
|
512
|
-
type: `[${model.globalId}]`,
|
|
513
|
-
},
|
|
514
|
-
},
|
|
515
|
-
resolvers: {
|
|
516
|
-
Query: {
|
|
517
|
-
[pluralName]: wrapPublicationStateResolver(resolver),
|
|
518
|
-
},
|
|
519
|
-
},
|
|
520
|
-
};
|
|
521
|
-
|
|
522
|
-
_.merge(localSchema, query);
|
|
523
|
-
|
|
524
|
-
if (isQueryEnabled(ctx.schema, `${pluralName}Connection`)) {
|
|
525
|
-
// Generate the aggregation for the given model
|
|
526
|
-
const aggregationSchema = formatModelConnectionsGQL({
|
|
527
|
-
fields: typeDefObj,
|
|
528
|
-
model,
|
|
529
|
-
name: modelName,
|
|
530
|
-
resolver: resolverOpts,
|
|
531
|
-
plugin,
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
mergeSchemas(localSchema, aggregationSchema);
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
// Add model Input definition.
|
|
540
|
-
localSchema.definition += types.generateInputModel(model, modelName);
|
|
541
|
-
|
|
542
|
-
// build every mutation
|
|
543
|
-
['create', 'update', 'delete'].forEach(action => {
|
|
544
|
-
const mutationSchema = buildMutationTypeDef({ model, action }, ctx);
|
|
545
|
-
mergeSchemas(localSchema, mutationSchema);
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
return localSchema;
|
|
549
|
-
};
|
|
550
|
-
|
|
551
|
-
// TODO:
|
|
552
|
-
// - Implement batch methods (need to update the content-manager as well).
|
|
553
|
-
// - Implement nested transactional methods (create/update).
|
|
554
|
-
const buildMutationTypeDef = ({ model, action }, ctx) => {
|
|
555
|
-
const capitalizedName = _.upperFirst(toSingular(model.modelName));
|
|
556
|
-
const mutationName = `${action}${capitalizedName}`;
|
|
557
|
-
|
|
558
|
-
const resolverOpts = {
|
|
559
|
-
resolver: `${model.uid}.${action}`,
|
|
560
|
-
transformOutput: result => ({ [toSingular(model.modelName)]: result }),
|
|
561
|
-
...getMutationInfo(ctx.schema, mutationName),
|
|
562
|
-
isShadowCrud: true,
|
|
563
|
-
};
|
|
564
|
-
|
|
565
|
-
if (!actionExists(resolverOpts)) {
|
|
566
|
-
return {};
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
const definition = types.generateInputPayloadArguments({
|
|
570
|
-
model,
|
|
571
|
-
name: model.modelName,
|
|
572
|
-
mutationName,
|
|
573
|
-
action,
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
// ignore if disabled
|
|
577
|
-
if (!isMutationEnabled(ctx.schema, mutationName)) {
|
|
578
|
-
return {
|
|
579
|
-
definition,
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
const { kind } = model;
|
|
584
|
-
|
|
585
|
-
const args = {};
|
|
586
|
-
|
|
587
|
-
if (kind !== 'singleType' || action !== 'delete') {
|
|
588
|
-
Object.assign(args, {
|
|
589
|
-
input: `${mutationName}Input`,
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
return {
|
|
594
|
-
definition,
|
|
595
|
-
mutation: {
|
|
596
|
-
[mutationName]: {
|
|
597
|
-
args: {
|
|
598
|
-
...args,
|
|
599
|
-
...(resolverOpts.args || {}),
|
|
600
|
-
},
|
|
601
|
-
type: `${mutationName}Payload`,
|
|
602
|
-
},
|
|
603
|
-
},
|
|
604
|
-
resolvers: {
|
|
605
|
-
Mutation: {
|
|
606
|
-
[mutationName]: buildMutation(mutationName, resolverOpts),
|
|
607
|
-
},
|
|
608
|
-
},
|
|
609
|
-
};
|
|
610
|
-
};
|
|
611
|
-
|
|
612
|
-
module.exports = buildShadowCrud;
|