2018-03-27 17:15:28 +02:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GraphQL.js service
|
|
|
|
*
|
|
|
|
* @description: A set of functions similar to controller's actions to avoid code duplication.
|
|
|
|
*/
|
|
|
|
|
2018-03-28 18:40:59 +02:00
|
|
|
const fs = require('fs');
|
|
|
|
const path = require('path');
|
|
|
|
|
|
|
|
const _ = require('lodash');
|
2018-03-27 19:02:04 +02:00
|
|
|
const { makeExecutableSchema } = require('graphql-tools');
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
|
2018-03-28 18:40:59 +02:00
|
|
|
formatGQL: (str) => JSON.stringify(str, null, 2).replace(/['"]+/g, ''),
|
|
|
|
|
2018-03-27 19:02:04 +02:00
|
|
|
convertType: (type) => {
|
|
|
|
switch (type) {
|
|
|
|
case 'string':
|
|
|
|
case 'text':
|
|
|
|
return 'String';
|
|
|
|
case 'boolean':
|
|
|
|
return 'Boolean';
|
|
|
|
default:
|
|
|
|
return 'String';
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-03-28 18:40:59 +02:00
|
|
|
shadowCRUD: function (models) {
|
2018-03-27 19:02:04 +02:00
|
|
|
// Retrieve generic service from the Content Manager plugin.
|
|
|
|
const resolvers = strapi.plugins['content-manager'].services['contentmanager'];
|
|
|
|
|
2018-03-28 18:40:59 +02:00
|
|
|
return models.reduce((acc, model) => {
|
|
|
|
const params = {
|
|
|
|
model
|
|
|
|
};
|
2018-03-27 19:02:04 +02:00
|
|
|
|
2018-03-28 18:40:59 +02:00
|
|
|
const query = {};
|
2018-03-27 19:02:04 +02:00
|
|
|
|
|
|
|
// Convert our layer Model to the GraphQL DL.
|
2018-03-28 18:40:59 +02:00
|
|
|
const attributes = Object.keys(strapi.models[model].attributes)
|
2018-03-27 19:02:04 +02:00
|
|
|
.reduce((acc, attribute) => {
|
|
|
|
// Convert our type to the GraphQL type.
|
2018-03-28 18:40:59 +02:00
|
|
|
acc[attribute] = this.convertType(strapi.models[model].attributes[attribute].type);
|
2018-03-27 19:02:04 +02:00
|
|
|
|
|
|
|
return acc;
|
2018-03-28 20:13:09 +02:00
|
|
|
}, { [strapi.models[model].primaryKey]: 'String' });
|
2018-03-27 19:02:04 +02:00
|
|
|
|
2018-03-28 18:40:59 +02:00
|
|
|
acc.definition += `type ${strapi.models[model].globalId} ${this.formatGQL(attributes)}\n\n`;
|
2018-03-27 19:02:04 +02:00
|
|
|
|
2018-03-28 18:40:59 +02:00
|
|
|
Object.assign(acc.query, {
|
|
|
|
[`${model}s`]: `[${strapi.models[model].globalId}]`,
|
|
|
|
[`${model}(id: String!)`]: strapi.models[model].globalId
|
|
|
|
});
|
2018-03-27 19:02:04 +02:00
|
|
|
|
2018-03-28 18:40:59 +02:00
|
|
|
// TODO
|
|
|
|
// - Apply and execute policies first.
|
|
|
|
// - Use pluralize to generate shadow query.
|
|
|
|
// - Handle mutations.
|
|
|
|
Object.assign(acc.resolver, {
|
|
|
|
[`${model}s`]: (_, options) => resolvers.fetchAll(params, {...query, ...options}),
|
|
|
|
[`${model}`]: (_, { id }) => resolvers.fetch({ ...params, id }, query)
|
2018-03-27 19:02:04 +02:00
|
|
|
});
|
|
|
|
|
2018-03-28 18:40:59 +02:00
|
|
|
return acc;
|
|
|
|
}, { definition: ``, query: {}, resolver: {} });
|
|
|
|
},
|
|
|
|
|
|
|
|
generateSchema: function () {
|
|
|
|
// Exclude core models.
|
|
|
|
const models = Object.keys(strapi.models).filter(model => model !== 'core_store');
|
|
|
|
|
|
|
|
// Generate type definition and query/mutation for models.
|
|
|
|
const shadowCRUD = true ? this.shadowCRUD(models) : {};
|
2018-03-27 19:02:04 +02:00
|
|
|
|
2018-03-28 18:40:59 +02:00
|
|
|
// Build resolvers.
|
|
|
|
const resolvers = {
|
|
|
|
Query: shadowCRUD.resolver || {}
|
|
|
|
};
|
2018-03-27 19:02:04 +02:00
|
|
|
|
|
|
|
// Concatenate.
|
2018-03-28 18:40:59 +02:00
|
|
|
const typeDefs = shadowCRUD.definition + `type Query ${this.formatGQL(shadowCRUD.query)}`;
|
|
|
|
|
|
|
|
// Write schema.
|
|
|
|
this.writeGenerateSchema(typeDefs);
|
|
|
|
|
2018-03-27 19:02:04 +02:00
|
|
|
// Build schema.
|
|
|
|
const schema = makeExecutableSchema({
|
|
|
|
typeDefs,
|
|
|
|
resolvers,
|
|
|
|
});
|
|
|
|
|
|
|
|
return schema;
|
2018-03-28 18:40:59 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
writeGenerateSchema(schema) {
|
2018-03-28 20:13:09 +02:00
|
|
|
// Disable auto-reload.
|
|
|
|
strapi.reload.isWatching = false;
|
|
|
|
|
2018-03-28 18:40:59 +02:00
|
|
|
const generatedFolder = path.resolve(strapi.config.appPath, 'plugins', 'graphql', 'config', 'generated');
|
|
|
|
|
|
|
|
// Create folder if necessary.
|
|
|
|
try {
|
|
|
|
fs.accessSync(generatedFolder, fs.constants.R_OK | fs.constants.W_OK);
|
|
|
|
} catch (err) {
|
|
|
|
if (err && err.code === 'ENOENT') {
|
|
|
|
fs.mkdirSync(generatedFolder);
|
|
|
|
} else {
|
|
|
|
console.error(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fs.writeFileSync(path.join(generatedFolder, 'schema.graphql'), schema);
|
2018-03-28 20:13:09 +02:00
|
|
|
|
|
|
|
strapi.reload.isWatching = true;
|
2018-03-27 19:02:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|