Split graphql schema generator code

Signed-off-by: Alexandre Bodin <bodin.alex@gmail.com>
This commit is contained in:
Alexandre Bodin 2020-01-27 22:43:44 +01:00
parent 44b7ab6858
commit c02625e438
3 changed files with 140 additions and 131 deletions

View File

@ -13,7 +13,7 @@ const Query = require('./Query.js');
const Mutation = require('./Mutation.js'); const Mutation = require('./Mutation.js');
const Types = require('./Types.js'); const Types = require('./Types.js');
const Resolvers = require('./Resolvers.js'); const Resolvers = require('./Resolvers.js');
const { mergeSchemas } = require('./utils'); const { mergeSchemas, createDefaultSchema } = require('./utils');
const schemaBuilder = { const schemaBuilder = {
/** /**
@ -128,39 +128,13 @@ const schemaBuilder = {
*/ */
generateSchema: function() { generateSchema: function() {
const shadowCRUDEnabled =
strapi.plugins.graphql.config.shadowCRUD !== false;
// Generate type definition and query/mutation for models. // Generate type definition and query/mutation for models.
let shadowCRUD = { definition: '', query: '', mutation: '', resolvers: {} }; const shadowCRUD = shadowCRUDEnabled
? this.buildShadowCRUD()
// build defaults schemas if shadowCRUD is enabled : createDefaultSchema();
if (strapi.plugins.graphql.config.shadowCRUD !== false) {
const modelCruds = Resolvers.buildShadowCRUD(
_.omitBy(strapi.models, model => model.internal === true)
);
shadowCRUD = Object.keys(strapi.plugins).reduce((acc, plugin) => {
const {
definition,
query,
mutation,
resolvers,
} = Resolvers.buildShadowCRUD(strapi.plugins[plugin].models);
// We cannot put this in the merge because it's a string.
acc.definition += definition || '';
return _.merge(acc, {
query,
resolvers,
mutation,
});
}, modelCruds);
}
const componentSchemas = Object.values(strapi.components).map(compo =>
Resolvers.buildComponent(compo)
);
mergeSchemas(shadowCRUD, ...componentSchemas);
// Extract custom definition, query or resolver. // Extract custom definition, query or resolver.
const { const {
@ -171,114 +145,57 @@ const schemaBuilder = {
} = strapi.plugins.graphql.config._schema.graphql; } = strapi.plugins.graphql.config._schema.graphql;
// Polymorphic. // Polymorphic.
const { const polymorphicSchema = Types.addPolymorphicUnionType(
polymorphicDef, definition + shadowCRUD.definition
polymorphicResolver, );
} = Types.addPolymorphicUnionType(definition, shadowCRUD.definition);
// Build resolvers. // Build resolvers.
const resolvers = const resolvers =
_.omitBy( _.omitBy(
_.merge(shadowCRUD.resolvers, resolver, polymorphicResolver), _.merge(shadowCRUD.resolvers, resolver, polymorphicSchema.resolvers),
_.isEmpty _.isEmpty
) || {}; ) || {};
// Transform object to only contain function. this.buildResolvers(resolvers);
Object.keys(resolvers).reduce((acc, type) => {
if (graphql.isScalarType(acc[type])) {
return acc;
}
return Object.keys(acc[type]).reduce((acc, resolverName) => {
const resolverObj = acc[type][resolverName];
// Disabled this query.
if (resolverObj === false) {
delete acc[type][resolverName];
return acc;
}
if (_.isFunction(resolverObj)) {
return acc;
}
let plugin;
if (_.has(resolverObj, ['plugin'])) {
plugin = resolverObj.plugin;
} else if (_.has(resolverObj, ['resolver', 'plugin'])) {
plugin = resolverObj.resolver.plugin;
}
switch (type) {
case 'Mutation': {
let name, action;
if (
_.has(resolverObj, ['resolver']) &&
_.isString(resolverObj.resolver)
) {
[name, action] = resolverObj.resolver.split('.');
} else if (
_.has(resolverObj, ['resolver', 'handler']) &&
_.isString(resolverObj.resolver.handler)
) {
[name, action] = resolverObj.resolver.handler.split('.');
} else {
name = null;
action = resolverName;
}
const mutationResolver = Mutation.composeMutationResolver({
_schema: strapi.plugins.graphql.config._schema.graphql,
plugin,
name: _.toLower(name),
action,
});
acc[type][resolverName] = mutationResolver;
break;
}
case 'Query':
default: {
acc[type][resolverName] = Query.composeQueryResolver({
_schema: strapi.plugins.graphql.config._schema.graphql,
plugin,
name: resolverName,
isSingular: 'force', // Avoid singular/pluralize and force query name.
});
break;
}
}
return acc;
}, acc);
}, resolvers);
// Return empty schema when there is no model. // Return empty schema when there is no model.
if (_.isEmpty(shadowCRUD.definition) && _.isEmpty(definition)) { if (_.isEmpty(shadowCRUD.definition) && _.isEmpty(definition)) {
return {}; return {};
} }
const queryFields = this.formatGQL(
shadowCRUD.query,
resolver.Query,
null,
'query'
);
const mutationFields = this.formatGQL(
shadowCRUD.mutation,
resolver.Mutation,
null,
'mutation'
);
// Concatenate. // Concatenate.
let typeDefs = ` let typeDefs = `
${definition} ${definition}
${shadowCRUD.definition} ${shadowCRUD.definition}
type Query {${shadowCRUD.query && ${polymorphicSchema.definition}
this.formatGQL(
shadowCRUD.query,
resolver.Query,
null,
'query'
)}${query}}
type Mutation {${shadowCRUD.mutation &&
this.formatGQL(
shadowCRUD.mutation,
resolver.Mutation,
null,
'mutation'
)}${mutation}}
${Types.addCustomScalar(resolvers)}
${Types.addInput()} ${Types.addInput()}
${polymorphicDef}
type Query {
${queryFields}
${query}
}
type Mutation {
${mutationFields}
${mutation}
}
${Types.addCustomScalar(resolvers)}
`; `;
// // Build schema. // // Build schema.
@ -310,6 +227,92 @@ const schemaBuilder = {
writeGenerateSchema: schema => { writeGenerateSchema: schema => {
return strapi.fs.writeAppFile('exports/graphql/schema.graphql', schema); return strapi.fs.writeAppFile('exports/graphql/schema.graphql', schema);
}, },
buildShadowCRUD() {
const modelSchema = Resolvers.buildShadowCRUD(
_.omitBy(strapi.models, model => model.internal === true)
);
const pluginSchemas = Object.keys(strapi.plugins).reduce((acc, plugin) => {
const schemas = Resolvers.buildShadowCRUD(strapi.plugins[plugin].models);
return acc.concat(schemas);
}, []);
const componentSchemas = Object.values(strapi.components).map(compo =>
Resolvers.buildComponent(compo)
);
const schema = { definition: '', resolvers: {}, query: {}, mutation: {} };
mergeSchemas(schema, modelSchema, ...pluginSchemas, ...componentSchemas);
return schema;
},
buildResolvers(resolvers) {
// Transform object to only contain function.
Object.keys(resolvers).reduce((acc, type) => {
if (graphql.isScalarType(acc[type])) {
return acc;
}
return Object.keys(acc[type]).reduce((acc, resolverName) => {
const resolverObj = acc[type][resolverName];
// Disabled this query.
if (resolverObj === false) {
delete acc[type][resolverName];
return acc;
}
if (_.isFunction(resolverObj)) {
return acc;
}
const plugin =
_.get(resolverObj, ['plugin']) ||
_.get(resolverObj, ['resolver', 'plugin']);
switch (type) {
case 'Mutation': {
const resolver =
_.get(resolverObj, ['resolver', 'handler']) ||
_.get(resolverObj, ['resolver']);
let name, action;
if (_.isString(resolver)) {
[name, action] = resolver.split('.');
} else {
name = null;
action = resolverName;
}
const mutationResolver = Mutation.composeMutationResolver({
_schema: strapi.plugins.graphql.config._schema.graphql,
plugin,
name: _.toLower(name),
action,
});
acc[type][resolverName] = mutationResolver;
break;
}
case 'Query':
default: {
acc[type][resolverName] = Query.composeQueryResolver({
_schema: strapi.plugins.graphql.config._schema.graphql,
plugin,
name: resolverName,
isSingular: 'force', // Avoid singular/pluralize and force query name.
});
break;
}
}
return acc;
}, acc);
}, resolvers);
},
}; };
module.exports = schemaBuilder; module.exports = schemaBuilder;

View File

@ -205,11 +205,9 @@ module.exports = {
* @return string * @return string
*/ */
addPolymorphicUnionType(customDefs, defs) { addPolymorphicUnionType(definition) {
const def = customDefs + defs;
const types = graphql const types = graphql
.parse(def) .parse(definition)
.definitions.filter( .definitions.filter(
def => def.kind === 'ObjectTypeDefinition' && def.name.value !== 'Query' def => def.kind === 'ObjectTypeDefinition' && def.name.value !== 'Query'
) )
@ -217,8 +215,8 @@ module.exports = {
if (types.length > 0) { if (types.length > 0) {
return { return {
polymorphicDef: `union Morph = ${types.join(' | ')}`, definition: `union Morph = ${types.join(' | ')}`,
polymorphicResolver: { resolvers: {
Morph: { Morph: {
__resolveType(obj) { __resolveType(obj) {
return obj.kind || obj.__contentType || null; return obj.kind || obj.__contentType || null;
@ -229,8 +227,8 @@ module.exports = {
} }
return { return {
polymorphicDef: '', definition: '',
polymorphicResolver: {}, resolvers: {},
}; };
}, },

View File

@ -19,6 +19,14 @@ const mergeSchemas = (root, ...subs) => {
}); });
}; };
const createDefaultSchema = () => ({
definition: '',
query: '',
mutation: '',
resolvers: {},
});
module.exports = { module.exports = {
mergeSchemas, mergeSchemas,
createDefaultSchema,
}; };