'use strict'; /* global <%= globalID %> */ /** * <%= filename %> service * * @description: A set of functions similar to controller's actions to avoid code duplication. */ // Public dependencies. const _ = require('lodash'); module.exports = { /** * Promise to fetch all <%= humanizeIdPluralized %>. * * @return {Promise} */ fetchAll: (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) .reduce((acc, ast) => { // Strapi Model const model = ast.plugin ? strapi.plugins[ast.plugin].models[ast.collection || ast.model] : strapi.models[ast.collection || ast.model]; const from = model.collectionName; const as = ast.alias; const localField = ast.dominant ? '_id' : ast.via === <%= globalID %>.collectionName || ast.via === 'related' ? '_id' : ast.alias; const foreignField = ast.filter ? `${ast.via}.ref` : ast.dominant ? (ast.via === <%= globalID %>.collectionName ? ast.via : '_id') : (ast.via === <%= globalID %>.collectionName ? '_id' : ast.via); // Add the juncture like the `.populate()` function acc.push({ $lookup: { from, localField, foreignField, as, } }); // Unwind the relation's result if only one is expected if (ast.type === 'model') { acc.push({ $unwind: { path: `$${ast.alias}`, preserveNullAndEmptyArrays: true } }); } // Preserve relation field if it is empty acc.push({ $addFields: { [ast.alias]: { $ifNull: [`$${ast.alias}`, null] } } }); // Filtrate the result depending of params if (filters.relations) { Object.keys(filters.relations).forEach( (relationName) => { if (ast.alias === relationName) { const association = <%= globalID %>.associations.find(a => a.alias === relationName); if (association) { const relation = filters.relations[relationName]; Object.keys(relation).forEach( (filter) => { acc.push({ $match: { [`${relationName}.${filter}`]: relation[filter] } }); } ); } } } ); } return acc; }, []); const result = <%= globalID %> .aggregate([ { $match: filters.where }, ...populate, ]) .skip(filters.start) .limit(filters.limit); if (filters.sort) result.sort(filters.sort); return result; }, /** * Promise to fetch a/an <%= id %>. * * @return {Promise} */ fetch: (params) => { // Select field to populate. const populate = <%= globalID %>.associations .filter(ast => ast.autoPopulate !== false) .map(ast => ast.alias) .join(' '); return <%= globalID %> .findOne(_.pick(params, _.keys(<%= globalID %>.schema.paths))) .populate(populate); }, /** * Promise to count <%= humanizeIdPluralized %>. * * @return {Promise} */ count: (params) => { // Convert `params` object to filters compatible with Mongo. const filters = strapi.utils.models.convertParams('<%= globalID.toLowerCase() %>', params); return <%= globalID %> .count() .where(filters.where); }, /** * Promise to add a/an <%= id %>. * * @return {Promise} */ add: async (values) => { // Extract values related to relational data. const relations = _.pick(values, <%= globalID %>.associations.map(ast => ast.alias)); const data = _.omit(values, <%= globalID %>.associations.map(ast => ast.alias)); // Create entry with no-relational data. const entry = await <%= globalID %>.create(data); // Create relational data and return the entry. return <%= globalID %>.updateRelations({ _id: entry.id, values: relations }); }, /** * Promise to edit a/an <%= id %>. * * @return {Promise} */ edit: async (params, values) => { // Extract values related to relational data. const relations = _.pick(values, <%= globalID %>.associations.map(a => a.alias)); const data = _.omit(values, <%= globalID %>.associations.map(a => a.alias)); // 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 })); }, /** * Promise to remove a/an <%= id %>. * * @return {Promise} */ 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 // or add spent the parameter `{ passRawResult: true }` as second argument. const data = await <%= globalID %> .findOneAndRemove(params, {}) .populate(populate); if (!data) { return data; } await Promise.all( <%= globalID %>.associations.map(async association => { if (!association.via || !data._id) { return true; } 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 } }; // Retrieve model. const model = association.plugin ? strapi.plugins[association.plugin].models[association.model || association.collection] : strapi.models[association.model || association.collection]; return model.update(search, update, { multi: true }); }) ); return data; }, /** * Promise to search a/an <%= id %>. * * @return {Promise} */ search: async (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(' '); const $or = Object.keys(<%= globalID %>.attributes).reduce((acc, curr) => { switch (<%= globalID %>.attributes[curr].type) { case 'integer': case 'float': case 'decimal': if (!_.isNaN(_.toNumber(params._q))) { return acc.concat({ [curr]: params._q }); } return acc; case 'string': case 'text': case 'password': return acc.concat({ [curr]: { $regex: params._q, $options: 'i' } }); case 'boolean': if (params._q === 'true' || params._q === 'false') { return acc.concat({ [curr]: params._q === 'true' }); } return acc; default: return acc; } }, []); return <%= globalID %> .find({ $or }) .sort(filters.sort) .skip(filters.start) .limit(filters.limit) .populate(populate); } };