mirror of
https://github.com/strapi/strapi.git
synced 2025-07-15 21:11:28 +00:00
201 lines
4.7 KiB
JavaScript
201 lines
4.7 KiB
JavaScript
'use strict';
|
|
|
|
const _ = require('lodash');
|
|
const { QUERY_OPERATORS } = require('@strapi/utils');
|
|
|
|
/**
|
|
* @typedef {object} Schema
|
|
* @property {object} resolvers
|
|
* @property {object} mutation
|
|
* @property {object} query
|
|
* @property {string} definition
|
|
*/
|
|
|
|
/**
|
|
* Merges strapi graphql schema together
|
|
* @param {Schema} object - destination object
|
|
* @param {Schema[]} sources - source objects to merge into the destination object
|
|
* @returns {Schema}
|
|
*/
|
|
const mergeSchemas = (object, ...sources) => {
|
|
sources.forEach(sub => {
|
|
if (_.isEmpty(sub)) return;
|
|
const { definition = '', query = {}, mutation = {}, resolvers = {} } = sub;
|
|
|
|
object.definition += '\n' + definition;
|
|
_.merge(object, {
|
|
query,
|
|
mutation,
|
|
resolvers,
|
|
});
|
|
});
|
|
|
|
return object;
|
|
};
|
|
|
|
/**
|
|
* Returns an empty schema
|
|
* @returns {Schema}
|
|
*/
|
|
const createDefaultSchema = () => ({
|
|
definition: '',
|
|
query: {},
|
|
mutation: {},
|
|
resolvers: {},
|
|
});
|
|
|
|
const diffResolvers = (object, base) => {
|
|
let newObj = {};
|
|
|
|
Object.keys(object).forEach(type => {
|
|
Object.keys(object[type]).forEach(resolver => {
|
|
if (type === 'Query' || type === 'Mutation') {
|
|
if (!_.has(base, [type, resolver])) {
|
|
_.set(newObj, [type, resolver], _.get(object, [type, resolver]));
|
|
}
|
|
} else {
|
|
_.set(newObj, [type, resolver], _.get(object, [type, resolver]));
|
|
}
|
|
});
|
|
});
|
|
|
|
return newObj;
|
|
};
|
|
|
|
const convertToParams = params => {
|
|
return Object.keys(params).reduce((acc, current) => {
|
|
const key = current === 'id' ? 'id' : `_${current}`;
|
|
acc[key] = params[current];
|
|
return acc;
|
|
}, {});
|
|
};
|
|
|
|
const convertToQuery = params => {
|
|
const result = {};
|
|
|
|
_.forEach(params, (value, key) => {
|
|
if (QUERY_OPERATORS.includes(key)) {
|
|
result[key] = _.isArray(value) ? value.map(convertToQuery) : convertToQuery(value);
|
|
} else if (_.isPlainObject(value)) {
|
|
const flatObject = convertToQuery(value);
|
|
_.forEach(flatObject, (_value, _key) => {
|
|
result[`${key}.${_key}`] = _value;
|
|
});
|
|
} else {
|
|
result[key] = value;
|
|
}
|
|
});
|
|
|
|
return result;
|
|
};
|
|
|
|
const amountLimiting = (params = {}) => {
|
|
const { amountLimit } = strapi.plugins.graphql.config;
|
|
|
|
if (!amountLimit) return params;
|
|
|
|
if (_.isNil(params.limit) || params.limit === -1 || params.limit > amountLimit) {
|
|
params.limit = amountLimit;
|
|
} else if (params.limit < 0) {
|
|
params.limit = 0;
|
|
}
|
|
|
|
return params;
|
|
};
|
|
|
|
const nonRequired = type => type.replace('!', '');
|
|
|
|
const actionExists = ({ resolver, resolverOf }) => {
|
|
if (isResolvablePath(resolverOf)) {
|
|
return true;
|
|
} else if (_.isFunction(resolver)) {
|
|
return true;
|
|
} else if (_.isString(resolver)) {
|
|
return _.isFunction(getActionFn(getActionDetails(resolver)));
|
|
} else {
|
|
throw new Error(
|
|
`Error building query. Expected \`resolver\` as string or a function, or \`resolverOf\` as a string. got ${{
|
|
resolver,
|
|
resolverOf,
|
|
}}`
|
|
);
|
|
}
|
|
};
|
|
|
|
const getAction = resolver => {
|
|
if (!_.isString(resolver)) {
|
|
throw new Error(`Error building query. Expected a string, got ${resolver}`);
|
|
}
|
|
|
|
const actionDetails = getActionDetails(resolver);
|
|
const actionFn = getActionFn(actionDetails);
|
|
|
|
if (!actionFn) {
|
|
throw new Error(
|
|
`[GraphQL] Cannot find action "${resolver}". Check your graphql configurations.`
|
|
);
|
|
}
|
|
|
|
return actionFn;
|
|
};
|
|
|
|
const getActionFn = details => {
|
|
const { controller, action, plugin, api } = details;
|
|
|
|
if (plugin) {
|
|
return _.get(strapi.plugins, [_.toLower(plugin), 'controllers', _.toLower(controller), action]);
|
|
}
|
|
|
|
return _.get(strapi.api, [_.toLower(api), 'controllers', _.toLower(controller), action]);
|
|
};
|
|
|
|
const getActionDetails = resolver => {
|
|
if (resolver.startsWith('plugin::')) {
|
|
const [, path] = resolver.split('::');
|
|
const [plugin, controller, action] = path.split('.');
|
|
|
|
return { plugin, controller, action };
|
|
}
|
|
|
|
if (resolver.startsWith('api::')) {
|
|
const [, path] = resolver.split('::');
|
|
const [api, controller, action] = path.split('.');
|
|
|
|
return { api, controller, action };
|
|
}
|
|
|
|
const args = resolver.split('.');
|
|
|
|
if (args.length === 3) {
|
|
const [api, controller, action] = args;
|
|
return { api, controller, action };
|
|
}
|
|
|
|
// if direct api access
|
|
if (args.length === 2) {
|
|
const [controller, action] = args;
|
|
return { api: controller, controller, action };
|
|
}
|
|
|
|
throw new Error(
|
|
`[GraphQL] Could not find action for resolver "${resolver}". Check your graphql configurations.`
|
|
);
|
|
};
|
|
|
|
const isResolvablePath = path => _.isString(path) && !_.isEmpty(path);
|
|
|
|
module.exports = {
|
|
diffResolvers,
|
|
mergeSchemas,
|
|
createDefaultSchema,
|
|
convertToParams,
|
|
convertToQuery,
|
|
amountLimiting,
|
|
nonRequired,
|
|
actionExists,
|
|
getAction,
|
|
getActionDetails,
|
|
getActionFn,
|
|
isResolvablePath,
|
|
};
|