UNPKG

custom-deep-populate

Version:

This plugin streamlines the process of populating complex content structures through the REST API. It enables you to specify a custom depth for data retrieval, eliminate unwanted fields, and filter out nested fields with identical names. Best of all, each

131 lines (115 loc) 4.42 kB
const { isEmpty, merge } = require("lodash/fp"); const getModelPopulationAttributes = (model) => { /** * Get the population attributes for the given model * @param {Object} model - The model object to get the population attributes for * @returns {Object} - The population attributes */ if (model.uid === "plugin::upload.file") { const { related, ...attributes } = model.attributes; return attributes; } return model.attributes; }; const populateKey = (populate, key, value, maxDepth, ignore) => { /** * Populate the given key with the given value, maxDepth level and 'ignore' array if provided. * Checking the value type and populating accordingly, each key is populated with the full populated object, * and depending on the type of the value, the populated object is updated accordingly. * @param {Object} populate - The object to populate the key with * @param {String} key - The key to populate * @param {Object} value - The value to populate * @param {Number} maxDepth - The maximum depth to populate * @param {Array} ignore - The collection names to ignore * @returns {Object} - The populated object */ if (!value) return populate; switch (value.type) { case "component": populate[key] = getFullPopulateObject(value.component, maxDepth - 1); break; case "dynamiczone": const dynamicPopulate = getDynamicPopulate(value.components, maxDepth); populate[key] = isEmpty(dynamicPopulate) ? true : dynamicPopulate; break; case "relation": const relationPopulate = getRelationPopulate( value.target, key, maxDepth, ignore ); if (relationPopulate) populate[key] = relationPopulate; break; case "media": populate[key] = true; break; } return populate; }; const getDynamicPopulate = (components, maxDepth) => { /** * Get the dynamic population for the given components and maxDepth level * @param {Array} components - The components to populate * @param {Number} maxDepth - The maximum depth to populate * @returns {Object} - The populated object */ return components.reduce((prev, cur) => { const curPopulate = getFullPopulateObject(cur, maxDepth - 1); return curPopulate === true ? prev : merge(prev, curPopulate); }, {}); }; const getRelationPopulate = (target, key, maxDepth, ignore) => { /** * Get the relation population for the given target, key, maxDepth level and ignore array if provided * @param {String} target - The target to populate * @param {String} key - The key to populate * @param {Number} maxDepth - The maximum depth to populate * @param {Array} ignore - The collection names to ignore * @returns {Object} - The populated object */ return getFullPopulateObject( target, key === "localizations" && maxDepth > 2 ? 1 : maxDepth - 1, ignore ); }; const getFullPopulateObject = ( modelUid, maxDepth = 20, ignore = [], specific = [] ) => { /** * Get the populated object for the given modelUid and maxDepth level, ignoring the given collection * names in the 'ignore' array if provided * @param {String} modelUid - The model uid to get the populated object for * @param {Number} maxDepth - The maximum depth to populate * @param {Array} ignore - The collection names to ignore * @returns {Object} - The populated object */ const skipCreatorFields = strapi .plugin("custom-deep-populate") ?.config("skipCreatorFields"); if (maxDepth <= 1) return true; if (modelUid === "admin::user" && skipCreatorFields) return undefined; let populate = {}; const model = strapi.getModel(modelUid); if (ignore && !ignore.includes(model.collectionName)) ignore.push(model.collectionName); for (const [key, value] of Object.entries( getModelPopulationAttributes(model) )) { if (ignore?.includes(key)) continue; if (specific.length > 0 && specific.includes(key)) { populate = populateKey(populate, key, value, maxDepth, ignore); continue; } if (specific.length === 0) populate = populateKey(populate, key, value, maxDepth, ignore); } return isEmpty(populate) ? true : { populate }; }; module.exports = { getFullPopulateObject, };