Add updateRelations on models and update generated API to use this method

This commit is contained in:
Aurelsicoko 2018-05-09 12:52:32 +02:00
parent fc44709069
commit dfec0b630b
4 changed files with 72 additions and 34 deletions

View File

@ -18,15 +18,21 @@ module.exports = {
*/ */
fetchAll: (params) => { fetchAll: (params) => {
const convertedParams = strapi.utils.models.convertParams('<%= globalID.toLowerCase() %>', params); // Convert `params` object to filters compatible with Mongo.
const filters = strapi.utils.models.convertParams('<%= globalID.toLowerCase() %>', params);
// Select field to populate.
const populate = <%= globalID %>.associations
.filter(ast => ast.autoPopulate !== false)
.map(ast => ast.alias)
.join(' ');
return <%= globalID %> return <%= globalID %>
.find() .find()
.where(convertedParams.where) .where(filters.where)
.sort(convertedParams.sort) .sort(filters.sort)
.skip(convertedParams.start) .skip(filters.start)
.limit(convertedParams.limit) .limit(filters.limit)
.populate(_.keys(_.groupBy(_.reject(strapi.models.<%= id %>.associations, {autoPopulate: false}), 'alias')).join(' ')); .populate(populate);
}, },
/** /**
@ -36,9 +42,15 @@ module.exports = {
*/ */
fetch: (params) => { fetch: (params) => {
// Select field to populate.
const populate = <%= globalID %>.associations
.filter(ast => ast.autoPopulate !== false)
.map(ast => ast.alias)
.join(' ');
return <%= globalID %> return <%= globalID %>
.findOne(_.pick(params, _.keys(<%= globalID %>.schema.paths))) .findOne(_.pick(params, _.keys(<%= globalID %>.schema.paths)))
.populate(_.keys(_.groupBy(_.reject(strapi.models.<%= id %>.associations, {autoPopulate: false}), 'alias')).join(' ')); .populate(populate);
}, },
/** /**
@ -48,12 +60,15 @@ module.exports = {
*/ */
add: async (values) => { add: async (values) => {
const query = await <%= globalID %>.create(_.omit(values, _.keys(_.groupBy(strapi.models.<%= id %>.associations, 'alias')))); // Extract values related to relational data.
const data = query.toJSON ? query.toJSON() : query; const relations = _.pick(values, <%= globalID %>.associations.map(ast => ast.alias));
const data = _.omit(values, <%= globalID %>.associations.map(ast => ast.alias));
await strapi.hook.mongoose.manageRelations('<%= id %>', _.merge(data, { values })); // Create entry with no-relational data.
const entry = await <%= globalID %>.create(data);
return query; // Create relational data and return the entry.
return <%= globalID %>.updateRelations({ id: entry.id, values: relations });
}, },
/** /**
@ -63,11 +78,15 @@ module.exports = {
*/ */
edit: async (params, values) => { edit: async (params, values) => {
// Note: The current method will return the full response of Mongo. // Extract values related to relational data.
// To get the updated object, you have to execute the `findOne()` method const relations = _.pick(values, <%= globalID %>.associations.map(a => a.alias));
// or use the `findOneOrUpdate()` method with `{ new:true }` option. const data = _.omit(values, <%= globalID %>.associations.map(a => a.alias));
await strapi.hook.mongoose.manageRelations('<%= id %>', _.merge(_.clone(params), { values }));
return <%= globalID %>.update(params, values, { multi: true }); // Update entry with no-relational data.
const entry = await <%= globalID %>.update(params, data, { multi: true });
// Update relational data and return the entry.
return <%= globalID %>.updateRelations(Object.assign(params, { values: relations }));
}, },
/** /**
@ -77,20 +96,31 @@ module.exports = {
*/ */
remove: async params => { remove: async params => {
// Select field to populate.
const populate = <%= globalID %>.associations
.filter(ast => ast.autoPopulate !== false)
.map(ast => ast.alias)
.join(' ');
// Note: To get the full response of Mongo, use the `remove()` method // Note: To get the full response of Mongo, use the `remove()` method
// or add spent the parameter `{ passRawResult: true }` as second argument. // or add spent the parameter `{ passRawResult: true }` as second argument.
const data = await <%= globalID %>.findOneAndRemove(params, {}) const data = await <%= globalID %>
.populate(_.keys(_.groupBy(_.reject(strapi.models.<%= id %>.associations, {autoPopulate: false}), 'alias')).join(' ')); .findOneAndRemove(params, {})
.populate(populate);
_.forEach(<%= globalID %>.associations, async association => { await Promise.all(
const search = (_.endsWith(association.nature, 'One')) ? { [association.via]: data._id } : { [association.via]: { $in: [data._id] } }; <%= globalID %>.associations.map(async association => {
const update = (_.endsWith(association.nature, 'One')) ? { [association.via]: null } : { $pull: { [association.via]: data._id } }; const search = _.endsWith(association.nature, 'One') || association.nature === 'oneToMany' ? { [association.via]: data._id } : { [association.via]: { $in: [data._id] } };
const update = _.endsWith(association.nature, 'One') || association.nature === 'oneToMany' ? { [association.via]: null } : { $pull: { [association.via]: data._id } };
await strapi.models[association.model || association.collection].update( // Retrieve model.
search, const model = association.plugin ?
update, strapi.plugins[association.plugin].models[association.model || association.collection] :
{ multi: true }); strapi.models[association.model || association.collection];
});
return model.update(search, update, { multi: true });
})
);
return data; return data;
} }

View File

@ -8,7 +8,7 @@
const _ = require('lodash'); const _ = require('lodash');
module.exports = { module.exports = {
getModel: async function (model, plugin) { getModel: function (model, plugin) {
return _.get(strapi.plugins, [plugin, 'models', model]) || get(strapi, ['models', model]) || undefined; return _.get(strapi.plugins, [plugin, 'models', model]) || get(strapi, ['models', model]) || undefined;
}, },
@ -125,6 +125,8 @@ module.exports = {
// Push the work into the flow process. // Push the work into the flow process.
toAdd.forEach(value => { toAdd.forEach(value => {
value = _.isString(value) ? { [this.primaryKey]: value } : value;
if (association.nature === 'manyToMany' && !_.isArray(params.values[this.primaryKey] || params[this.primaryKey])) { if (association.nature === 'manyToMany' && !_.isArray(params.values[this.primaryKey] || params[this.primaryKey])) {
value[details.via] = (value[details.via] || []) value[details.via] = (value[details.via] || [])
.concat([(params.values[this.primaryKey] || params[this.primaryKey])]) .concat([(params.values[this.primaryKey] || params[this.primaryKey])])
@ -136,7 +138,7 @@ module.exports = {
} }
virtualFields.push( virtualFields.push(
module.exports.addRelation(model, { module.exports.addRelation.call(model, {
id: value[this.primaryKey] || value.id || value._id, id: value[this.primaryKey] || value.id || value._id,
values: _.pick(value, [this.primaryKey, details.via]), values: _.pick(value, [this.primaryKey, details.via]),
foreignKey: current foreignKey: current
@ -145,6 +147,8 @@ module.exports = {
}); });
toRemove.forEach(value => { toRemove.forEach(value => {
value = _.isString(value) ? { [this.primaryKey]: value } : value;
if (association.nature === 'manyToMany' && !_.isArray(params.values[this.primaryKey])) { if (association.nature === 'manyToMany' && !_.isArray(params.values[this.primaryKey])) {
value[details.via] = value[details.via].filter(x => x.toString() !== params.values[this.primaryKey].toString()); value[details.via] = value[details.via].filter(x => x.toString() !== params.values[this.primaryKey].toString());
} else { } else {
@ -152,7 +156,7 @@ module.exports = {
} }
virtualFields.push( virtualFields.push(
module.export.removeRelation(model, { module.exports.removeRelation.call(model, {
id: value[this.primaryKey] || value.id || value._id, id: value[this.primaryKey] || value.id || value._id,
values: _.pick(value, [this.primaryKey, details.via]), values: _.pick(value, [this.primaryKey, details.via]),
foreignKey: current foreignKey: current
@ -213,7 +217,7 @@ module.exports = {
// Remove relations in the other side. // Remove relations in the other side.
toAdd.forEach(id => { toAdd.forEach(id => {
virtualFields.push( virtualFields.push(
module.exports.addRelationMorph(model, { module.exports.addRelationMorph.call(model, {
id, id,
alias: association.via, alias: association.via,
ref: this.globalId, ref: this.globalId,
@ -226,7 +230,7 @@ module.exports = {
// Remove relations in the other side. // Remove relations in the other side.
toRemove.forEach(id => { toRemove.forEach(id => {
virtualFields.push( virtualFields.push(
module.exports.removeRelationMorph(model, { module.exports.removeRelationMorph.call(model, {
id, id,
alias: association.via, alias: association.via,
ref: this.globalId, ref: this.globalId,
@ -262,7 +266,7 @@ module.exports = {
.findOne({ .findOne({
[this.primaryKey]: params[this.primaryKey] || params.id [this.primaryKey]: params[this.primaryKey] || params.id
}) })
.populate(model.associations.map(x => x.alias).join(' ')); .populate(this.associations.map(x => x.alias).join(' '));
}, },
addRelation: async function (params) { addRelation: async function (params) {

View File

@ -38,6 +38,10 @@
"via": "users", "via": "users",
"plugin": "users-permissions", "plugin": "users-permissions",
"configurable": false "configurable": false
},
"article": {
"model": "article",
"via": "authors"
} }
} }
} }

View File

@ -25,7 +25,7 @@ module.exports = strapi => {
await next(); await next();
} catch (error) { } catch (error) {
// Log error. // Log error.
strapi.log.error(error); console.error(error);
// Wrap error into a Boom's response. // Wrap error into a Boom's response.
ctx.status = error.status || 500; ctx.status = error.status || 500;