@strapi/plugin-graphql 4.0.0-next.8 → 4.0.2
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 +43 -35
- 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
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Build queries and mutation resolvers
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
|
-
const _ = require('lodash');
|
|
8
|
-
const compose = require('koa-compose');
|
|
9
|
-
|
|
10
|
-
const { policy: policyUtils } = require('@strapi/utils');
|
|
11
|
-
const {
|
|
12
|
-
convertToParams,
|
|
13
|
-
convertToQuery,
|
|
14
|
-
amountLimiting,
|
|
15
|
-
getAction,
|
|
16
|
-
getActionDetails,
|
|
17
|
-
isResolvablePath,
|
|
18
|
-
} = require('./utils');
|
|
19
|
-
|
|
20
|
-
const buildMutation = (mutationName, config) => {
|
|
21
|
-
const { resolver, resolverOf, transformOutput = _.identity, isShadowCrud = false } = config;
|
|
22
|
-
|
|
23
|
-
if (_.isFunction(resolver) && !isResolvablePath(resolverOf)) {
|
|
24
|
-
throw new Error(
|
|
25
|
-
`Cannot create mutation "${mutationName}". Missing "resolverOf" option with custom resolver.`
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const policiesMiddleware = compose(getPolicies(config));
|
|
30
|
-
|
|
31
|
-
// custom resolvers
|
|
32
|
-
if (_.isFunction(resolver)) {
|
|
33
|
-
return async (root, options = {}, graphqlContext, info) => {
|
|
34
|
-
const ctx = buildMutationContext({ options, graphqlContext, isShadowCrud });
|
|
35
|
-
|
|
36
|
-
await policiesMiddleware(ctx);
|
|
37
|
-
graphqlContext.context = ctx;
|
|
38
|
-
|
|
39
|
-
return resolver(root, options, graphqlContext, info);
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const action = getAction(resolver);
|
|
44
|
-
|
|
45
|
-
return async (root, options = {}, graphqlContext) => {
|
|
46
|
-
const ctx = buildMutationContext({ options, graphqlContext, isShadowCrud });
|
|
47
|
-
|
|
48
|
-
await policiesMiddleware(ctx);
|
|
49
|
-
|
|
50
|
-
const values = await action(ctx);
|
|
51
|
-
const result = ctx.body !== undefined ? ctx.body : values;
|
|
52
|
-
|
|
53
|
-
if (_.isError(result)) {
|
|
54
|
-
throw result;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return transformOutput(result);
|
|
58
|
-
};
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const buildMutationContext = ({ options, graphqlContext, isShadowCrud }) => {
|
|
62
|
-
const { context } = graphqlContext;
|
|
63
|
-
|
|
64
|
-
const ctx = cloneKoaContext(context);
|
|
65
|
-
|
|
66
|
-
if (options.input && options.input.where) {
|
|
67
|
-
ctx.params = convertToParams(options.input.where || {});
|
|
68
|
-
} else {
|
|
69
|
-
ctx.params = {};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (options.input && options.input.data) {
|
|
73
|
-
ctx.request.body = options.input.data || {};
|
|
74
|
-
} else {
|
|
75
|
-
ctx.request.body = options;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (isShadowCrud) {
|
|
79
|
-
ctx.query = convertToParams(_.omit(options, 'input'));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return ctx;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const buildQuery = (queryName, config) => {
|
|
86
|
-
const { resolver } = config;
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
validateResolverOption(config);
|
|
90
|
-
} catch (error) {
|
|
91
|
-
throw new Error(`Cannot create query "${queryName}": ${error.message}`);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const policiesMiddleware = compose(getPolicies(config));
|
|
95
|
-
|
|
96
|
-
// custom resolvers
|
|
97
|
-
if (_.isFunction(resolver)) {
|
|
98
|
-
return async (root, options = {}, graphqlContext, info) => {
|
|
99
|
-
const { ctx, opts } = buildQueryContext({ options, graphqlContext });
|
|
100
|
-
|
|
101
|
-
await policiesMiddleware(ctx);
|
|
102
|
-
graphqlContext.context = ctx;
|
|
103
|
-
|
|
104
|
-
return resolver(root, opts, graphqlContext, info);
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const action = getAction(resolver);
|
|
109
|
-
|
|
110
|
-
return async (root, options = {}, graphqlContext) => {
|
|
111
|
-
const { ctx } = buildQueryContext({ options, graphqlContext });
|
|
112
|
-
|
|
113
|
-
// duplicate context
|
|
114
|
-
await policiesMiddleware(ctx);
|
|
115
|
-
|
|
116
|
-
const values = await action(ctx);
|
|
117
|
-
const result = ctx.body !== undefined ? ctx.body : values;
|
|
118
|
-
|
|
119
|
-
if (_.isError(result)) {
|
|
120
|
-
throw result;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return result;
|
|
124
|
-
};
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const validateResolverOption = config => {
|
|
128
|
-
const { resolver, resolverOf, policies } = config;
|
|
129
|
-
|
|
130
|
-
if (_.isFunction(resolver) && !isResolvablePath(resolverOf)) {
|
|
131
|
-
throw new Error(`Missing "resolverOf" option with custom resolver.`);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (!_.isUndefined(policies) && (!Array.isArray(policies) || !_.every(policies, _.isString))) {
|
|
135
|
-
throw new Error('Policies option must be an array of string.');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return true;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const cloneKoaContext = ctx => {
|
|
142
|
-
return Object.assign(ctx.app.createContext(_.clone(ctx.req), _.clone(ctx.res)), {
|
|
143
|
-
state: {
|
|
144
|
-
...ctx.state,
|
|
145
|
-
},
|
|
146
|
-
});
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const buildQueryContext = ({ options, graphqlContext }) => {
|
|
150
|
-
const { context } = graphqlContext;
|
|
151
|
-
const _options = _.cloneDeep(options);
|
|
152
|
-
|
|
153
|
-
const ctx = cloneKoaContext(context);
|
|
154
|
-
|
|
155
|
-
const opts = amountLimiting(_options);
|
|
156
|
-
|
|
157
|
-
ctx.query = {
|
|
158
|
-
...convertToParams(_.omit(opts, 'where')),
|
|
159
|
-
...convertToQuery(opts.where),
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
ctx.params = convertToParams(opts);
|
|
163
|
-
|
|
164
|
-
return { ctx, opts };
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Checks if a resolverPath (resolver or resovlerOf) might be resolved
|
|
169
|
-
*/
|
|
170
|
-
const getPolicies = config => {
|
|
171
|
-
const { resolver, policies = [], resolverOf } = config;
|
|
172
|
-
|
|
173
|
-
const { api, plugin } = config['_metadatas'] || {};
|
|
174
|
-
|
|
175
|
-
const policyFns = [];
|
|
176
|
-
|
|
177
|
-
const { controller, action, plugin: pathPlugin } = isResolvablePath(resolverOf)
|
|
178
|
-
? getActionDetails(resolverOf)
|
|
179
|
-
: getActionDetails(resolver);
|
|
180
|
-
|
|
181
|
-
const globalPolicy = policyUtils.globalPolicy({
|
|
182
|
-
controller,
|
|
183
|
-
action,
|
|
184
|
-
plugin: pathPlugin,
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
policyFns.push(globalPolicy);
|
|
188
|
-
|
|
189
|
-
if (strapi.plugins['users-permissions']) {
|
|
190
|
-
policies.unshift('plugin::users-permissions.permissions');
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
policies.forEach(policy => {
|
|
194
|
-
const policyFn = policyUtils.get(policy, plugin, api);
|
|
195
|
-
policyFns.push(policyFn);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
return policyFns;
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
module.exports = {
|
|
202
|
-
buildQuery,
|
|
203
|
-
buildMutation,
|
|
204
|
-
};
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema definition language tools
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
|
-
const _ = require('lodash');
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Retrieves a type description from its configuration or its related model
|
|
11
|
-
* @return String
|
|
12
|
-
*/
|
|
13
|
-
const getTypeDescription = (type, model = {}) => {
|
|
14
|
-
const str = _.get(type, '_description') || _.get(model, 'info.description');
|
|
15
|
-
|
|
16
|
-
if (str) {
|
|
17
|
-
return `"""\n${str}\n"""\n`;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return '';
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Receive an Object and return a string which is following the GraphQL specs.
|
|
25
|
-
* @param {Object} fields
|
|
26
|
-
* @param {Object} description
|
|
27
|
-
* @param {Object} model the underlying strapi model of those fields
|
|
28
|
-
* @param {string} type the type of object we are converting to SQL (query, mutation, or fields)
|
|
29
|
-
*/
|
|
30
|
-
const toSDL = (fields, configurations = {}, model = {}, type = 'field') => {
|
|
31
|
-
if (['query', 'mutation'].includes(type)) {
|
|
32
|
-
return operationToSDL({ fields, configurations });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return fieldsToSDL({ fields, model, configurations });
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Generated a SDL for a type
|
|
40
|
-
* @param {Object} options
|
|
41
|
-
* @param {Object} options.fields fields to convert to SDL
|
|
42
|
-
* @param {Object} options.configurations fields configurations (descriptions and deprecations)
|
|
43
|
-
* @param {Object} options.model the underlying strapi model of those fields
|
|
44
|
-
*/
|
|
45
|
-
const fieldsToSDL = ({ fields, configurations, model }) => {
|
|
46
|
-
return Object.entries(fields)
|
|
47
|
-
.map(([key, value]) => {
|
|
48
|
-
const [attr] = key.split('(');
|
|
49
|
-
const attributeName = _.trim(attr);
|
|
50
|
-
|
|
51
|
-
const description = _.isString(configurations[attributeName])
|
|
52
|
-
? configurations[attributeName]
|
|
53
|
-
: _.get(configurations, [attributeName, 'description']) ||
|
|
54
|
-
_.get(model, ['attributes', attributeName, 'description']);
|
|
55
|
-
|
|
56
|
-
const deprecated =
|
|
57
|
-
_.get(configurations, [attributeName, 'deprecated']) ||
|
|
58
|
-
_.get(model, ['attributes', attributeName, 'deprecated']);
|
|
59
|
-
|
|
60
|
-
return applyMetadatas(`${key}: ${value}`, { description, deprecated });
|
|
61
|
-
})
|
|
62
|
-
.join('\n');
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Generated a SDL for a query or a mutation object
|
|
67
|
-
* @param {Object} options
|
|
68
|
-
* @param {Object} options.fields fields to convert to SDL
|
|
69
|
-
* @param {Object} options.configurations fields configurations (descriptions and deprecations)
|
|
70
|
-
*/
|
|
71
|
-
const operationToSDL = ({ fields, configurations }) => {
|
|
72
|
-
return Object.entries(fields)
|
|
73
|
-
.map(([key, value]) => {
|
|
74
|
-
if (typeof value === 'string') {
|
|
75
|
-
const [attr] = key.split('(');
|
|
76
|
-
const attributeName = _.trim(attr);
|
|
77
|
-
|
|
78
|
-
return applyMetadatas(`${key}: ${value}`, configurations[attributeName]);
|
|
79
|
-
} else {
|
|
80
|
-
const { args = {}, type } = value;
|
|
81
|
-
|
|
82
|
-
const query = `${key}${argumentsToSDL(args)}: ${type}`;
|
|
83
|
-
return applyMetadatas(query, configurations[key]);
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
.join('\n');
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Converts an object of arguments into graphql SDL
|
|
91
|
-
* @param {object} args arguments
|
|
92
|
-
* @returns {string}
|
|
93
|
-
*/
|
|
94
|
-
const argumentsToSDL = args => {
|
|
95
|
-
if (_.isEmpty(args)) {
|
|
96
|
-
return '';
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const sdlArgs = Object.entries(args)
|
|
100
|
-
.map(([key, value]) => `${key}: ${value}`)
|
|
101
|
-
.join(', ');
|
|
102
|
-
|
|
103
|
-
return `(${sdlArgs})`;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Applies description and deprecated to a field definition
|
|
108
|
-
* @param {string} definition field definition
|
|
109
|
-
* @param {Object} metadatas field metadatas
|
|
110
|
-
* @param {string} metadatas.description field description
|
|
111
|
-
* @param {string} metadatas.deprecated field deprecation
|
|
112
|
-
*/
|
|
113
|
-
const applyMetadatas = (definition, metadatas = {}) => {
|
|
114
|
-
const { description, deprecated } = metadatas;
|
|
115
|
-
|
|
116
|
-
let tmpDef = definition;
|
|
117
|
-
if (description) {
|
|
118
|
-
tmpDef = `"""\n${description}\n"""\n${tmpDef}`;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (deprecated) {
|
|
122
|
-
tmpDef = `${tmpDef} @deprecated(reason: "${deprecated}")`;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return tmpDef;
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
module.exports = {
|
|
129
|
-
toSDL,
|
|
130
|
-
getTypeDescription,
|
|
131
|
-
};
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* GraphQL.js service
|
|
5
|
-
*
|
|
6
|
-
* @description: A set of functions similar to controller's actions to avoid code duplication.
|
|
7
|
-
*/
|
|
8
|
-
const { filterSchema } = require('@graphql-tools/utils');
|
|
9
|
-
const { buildFederatedSchema } = require('@apollo/federation');
|
|
10
|
-
const { gql, makeExecutableSchema } = require('apollo-server-koa');
|
|
11
|
-
const _ = require('lodash');
|
|
12
|
-
const graphql = require('graphql');
|
|
13
|
-
const PublicationState = require('../types/publication-state');
|
|
14
|
-
const Types = require('./type-builder');
|
|
15
|
-
const buildShadowCrud = require('./shadow-crud');
|
|
16
|
-
const { createDefaultSchema, diffResolvers } = require('./utils');
|
|
17
|
-
const { toSDL } = require('./schema-definitions');
|
|
18
|
-
const { buildQuery, buildMutation } = require('./resolvers-builder');
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Generate GraphQL schema.
|
|
22
|
-
*
|
|
23
|
-
* @return Schema
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
const generateSchema = () => {
|
|
27
|
-
const isFederated = _.get(strapi.plugins.graphql.config, 'federation', false);
|
|
28
|
-
const shadowCRUDEnabled = strapi.plugins.graphql.config.shadowCRUD !== false;
|
|
29
|
-
|
|
30
|
-
const _schema = strapi.plugins.graphql.config._schema.graphql;
|
|
31
|
-
|
|
32
|
-
const ctx = {
|
|
33
|
-
schema: _schema,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
// Generate type definition and query/mutation for models.
|
|
37
|
-
const shadowCRUD = shadowCRUDEnabled ? buildShadowCrud(ctx) : createDefaultSchema();
|
|
38
|
-
|
|
39
|
-
// Extract custom definition, query or resolver.
|
|
40
|
-
const { definition, query, mutation, resolver = {} } = _schema;
|
|
41
|
-
|
|
42
|
-
// Polymorphic.
|
|
43
|
-
const polymorphicSchema = Types.addPolymorphicUnionType(definition + shadowCRUD.definition);
|
|
44
|
-
|
|
45
|
-
const builtResolvers = _.merge({}, shadowCRUD.resolvers, polymorphicSchema.resolvers);
|
|
46
|
-
|
|
47
|
-
const extraResolvers = diffResolvers(_schema.resolver, builtResolvers);
|
|
48
|
-
|
|
49
|
-
const resolvers = _.merge({}, builtResolvers, buildResolvers(extraResolvers));
|
|
50
|
-
|
|
51
|
-
// Return empty schema when there is no model.
|
|
52
|
-
if (_.isEmpty(shadowCRUD.definition) && _.isEmpty(definition)) {
|
|
53
|
-
return {};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const queryFields = shadowCRUD.query && toSDL(shadowCRUD.query, resolver.Query, null, 'query');
|
|
57
|
-
|
|
58
|
-
const mutationFields =
|
|
59
|
-
shadowCRUD.mutation && toSDL(shadowCRUD.mutation, resolver.Mutation, null, 'mutation');
|
|
60
|
-
|
|
61
|
-
Object.assign(resolvers, PublicationState.resolver);
|
|
62
|
-
|
|
63
|
-
const scalars = Types.getScalars();
|
|
64
|
-
|
|
65
|
-
Object.assign(resolvers, scalars);
|
|
66
|
-
|
|
67
|
-
const scalarDef = Object.keys(scalars)
|
|
68
|
-
.map(key => `scalar ${key}`)
|
|
69
|
-
.join('\n');
|
|
70
|
-
|
|
71
|
-
// Concatenate.
|
|
72
|
-
// Manually defined to avoid exposing all attributes (like password etc.)
|
|
73
|
-
let typeDefs = `
|
|
74
|
-
${definition}
|
|
75
|
-
${shadowCRUD.definition}
|
|
76
|
-
${polymorphicSchema.definition}
|
|
77
|
-
${Types.addInput()}
|
|
78
|
-
|
|
79
|
-
${PublicationState.definition}
|
|
80
|
-
|
|
81
|
-
type AdminUser {
|
|
82
|
-
id: ID!
|
|
83
|
-
username: String
|
|
84
|
-
firstname: String!
|
|
85
|
-
lastname: String!
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
type Query {
|
|
89
|
-
${queryFields}
|
|
90
|
-
${query}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
type Mutation {
|
|
94
|
-
${mutationFields}
|
|
95
|
-
${mutation}
|
|
96
|
-
}
|
|
97
|
-
${scalarDef}
|
|
98
|
-
`;
|
|
99
|
-
|
|
100
|
-
// Build schema.
|
|
101
|
-
const schema = makeExecutableSchema({
|
|
102
|
-
typeDefs,
|
|
103
|
-
resolvers,
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
const generatedSchema = filterDisabledResolvers(schema, extraResolvers);
|
|
107
|
-
|
|
108
|
-
if (strapi.config.environment !== 'production') {
|
|
109
|
-
writeGenerateSchema(generatedSchema);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return isFederated ? getFederatedSchema(generatedSchema, resolvers) : generatedSchema;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const getFederatedSchema = (schema, resolvers) =>
|
|
116
|
-
buildFederatedSchema([{ typeDefs: gql(graphql.printSchema(schema)), resolvers }]);
|
|
117
|
-
|
|
118
|
-
const filterDisabledResolvers = (schema, extraResolvers) =>
|
|
119
|
-
filterSchema({
|
|
120
|
-
schema,
|
|
121
|
-
rootFieldFilter: (operationName, fieldName) => {
|
|
122
|
-
const resolver = _.get(extraResolvers[operationName], fieldName, true);
|
|
123
|
-
|
|
124
|
-
// resolvers set to false are filtered from the schema
|
|
125
|
-
if (resolver === false) {
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
return true;
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Save into a file the readable GraphQL schema.
|
|
134
|
-
*
|
|
135
|
-
* @return void
|
|
136
|
-
*/
|
|
137
|
-
const writeGenerateSchema = schema => {
|
|
138
|
-
const printSchema = graphql.printSchema(schema);
|
|
139
|
-
return strapi.fs.writeAppFile('exports/graphql/schema.graphql', printSchema);
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const buildResolvers = resolvers => {
|
|
143
|
-
// Transform object to only contain function.
|
|
144
|
-
return Object.keys(resolvers).reduce((acc, type) => {
|
|
145
|
-
if (graphql.isScalarType(resolvers[type])) {
|
|
146
|
-
return acc;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return Object.keys(resolvers[type]).reduce((acc, resolverName) => {
|
|
150
|
-
const resolverObj = resolvers[type][resolverName];
|
|
151
|
-
|
|
152
|
-
// Disabled this query.
|
|
153
|
-
if (resolverObj === false) return acc;
|
|
154
|
-
|
|
155
|
-
if (_.isFunction(resolverObj)) {
|
|
156
|
-
return _.set(acc, [type, resolverName], resolverObj);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
switch (type) {
|
|
160
|
-
case 'Mutation': {
|
|
161
|
-
_.set(acc, [type, resolverName], buildMutation(resolverName, resolverObj));
|
|
162
|
-
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
default: {
|
|
166
|
-
_.set(acc, [type, resolverName], buildQuery(resolverName, resolverObj));
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return acc;
|
|
172
|
-
}, acc);
|
|
173
|
-
}, {});
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
module.exports = {
|
|
177
|
-
generateSchema,
|
|
178
|
-
};
|