mirror of
https://github.com/strapi/strapi.git
synced 2025-07-28 11:30:21 +00:00
187 lines
4.8 KiB
JavaScript
187 lines
4.8 KiB
JavaScript
![]() |
'use strict';
|
||
|
|
||
|
const _ = require('lodash');
|
||
|
const { getComponentAttributes } = require('./utils/attributes');
|
||
|
const { findModelByAssoc, isPolymorphic } = require('./utils/associations');
|
||
|
|
||
|
/**
|
||
|
* Create utilities to populate a model on fetch
|
||
|
*/
|
||
|
|
||
|
const populateFetch = (definition, options) => {
|
||
|
// do not populate anything
|
||
|
if (options.withRelated === false) return;
|
||
|
if (options.isEager === true) return;
|
||
|
|
||
|
if (_.isNil(options.withRelated)) {
|
||
|
options.withRelated = []
|
||
|
.concat(createComponentsPopulate(definition))
|
||
|
.concat(createAssociationPopulate(definition));
|
||
|
} else if (_.isEmpty(options.withRelated)) {
|
||
|
options.withRelated = createComponentsPopulate(definition);
|
||
|
} else {
|
||
|
options.withRelated = formatPopulateOptions(
|
||
|
definition,
|
||
|
options.withRelated
|
||
|
);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const isComponent = (def, key) =>
|
||
|
_.get(def, ['attributes', key, 'type']) === 'component';
|
||
|
|
||
|
const createAssociationPopulate = definition => {
|
||
|
return definition.associations
|
||
|
.filter(ast => ast.autoPopulate !== false)
|
||
|
.map(assoc => {
|
||
|
if (isPolymorphic({ assoc })) {
|
||
|
return formatPolymorphicPopulate({
|
||
|
assoc,
|
||
|
path: assoc.alias,
|
||
|
});
|
||
|
}
|
||
|
|
||
|
let path = assoc.alias;
|
||
|
let extraAssocs = [];
|
||
|
if (assoc) {
|
||
|
const assocModel = findModelByAssoc({ assoc });
|
||
|
|
||
|
extraAssocs = assocModel.associations
|
||
|
.filter(assoc => isPolymorphic({ assoc }))
|
||
|
.map(assoc =>
|
||
|
formatPolymorphicPopulate({
|
||
|
assoc,
|
||
|
path: assoc.alias,
|
||
|
prefix: `${path}.`,
|
||
|
})
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return [assoc.alias, ...extraAssocs];
|
||
|
})
|
||
|
.reduce((acc, val) => acc.concat(val), []);
|
||
|
};
|
||
|
|
||
|
const formatPopulateOptions = (definition, withRelated) => {
|
||
|
if (!Array.isArray(withRelated)) withRelated = [withRelated];
|
||
|
|
||
|
const obj = withRelated.reduce((acc, key) => {
|
||
|
if (_.isString(key)) {
|
||
|
acc[key] = () => {};
|
||
|
return acc;
|
||
|
}
|
||
|
|
||
|
return _.extend(acc, key);
|
||
|
}, {});
|
||
|
|
||
|
// if components are no
|
||
|
const finalObj = Object.keys(obj).reduce((acc, key) => {
|
||
|
// check the key path and update it if necessary nothing more
|
||
|
const parts = key.split('.');
|
||
|
|
||
|
let newKey;
|
||
|
let prefix = '';
|
||
|
let tmpModel = definition;
|
||
|
for (let part of parts) {
|
||
|
if (isComponent(tmpModel, part)) {
|
||
|
tmpModel = strapi.components[tmpModel.attributes[part].component];
|
||
|
// add component path and there relations / images
|
||
|
const path = `${prefix}${part}.component`;
|
||
|
|
||
|
newKey = path;
|
||
|
prefix = `${path}.`;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
const assoc = tmpModel.associations.find(
|
||
|
association => association.alias === part
|
||
|
);
|
||
|
|
||
|
if (!assoc) return acc;
|
||
|
|
||
|
tmpModel = findModelByAssoc({ assoc });
|
||
|
|
||
|
if (isPolymorphic({ assoc })) {
|
||
|
const path = formatPolymorphicPopulate({
|
||
|
assoc,
|
||
|
path: assoc.alias,
|
||
|
prefix,
|
||
|
});
|
||
|
|
||
|
return _.extend(acc, path);
|
||
|
}
|
||
|
|
||
|
newKey = `${prefix}${part}`;
|
||
|
prefix = `${newKey}.`;
|
||
|
}
|
||
|
|
||
|
acc[newKey] = obj[key];
|
||
|
return acc;
|
||
|
}, {});
|
||
|
|
||
|
return [finalObj];
|
||
|
};
|
||
|
|
||
|
const populateComponent = (key, attr) => {
|
||
|
if (attr.type === 'dynamiczone') return [`${key}.component`];
|
||
|
|
||
|
let paths = [];
|
||
|
const component = strapi.components[attr.component];
|
||
|
|
||
|
const assocs = (component.associations || []).filter(
|
||
|
assoc => assoc.autoPopulate === true
|
||
|
);
|
||
|
|
||
|
// paths.push(`${key}.component`);
|
||
|
assocs.forEach(assoc => {
|
||
|
if (isPolymorphic({ assoc })) {
|
||
|
const rel = formatPolymorphicPopulate({
|
||
|
assoc,
|
||
|
path: assoc.alias,
|
||
|
prefix: `${key}.component.`,
|
||
|
});
|
||
|
|
||
|
paths.push(rel);
|
||
|
} else {
|
||
|
paths.push(`${key}.component.${assoc.alias}`);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return [`${key}.component`, ...paths];
|
||
|
};
|
||
|
|
||
|
const createComponentsPopulate = definition => {
|
||
|
return getComponentAttributes(definition).reduce((acc, key) => {
|
||
|
const attribute = definition.attributes[key];
|
||
|
const autoPopulate = _.get(attribute, ['autoPopulate'], true);
|
||
|
|
||
|
if (autoPopulate === true) {
|
||
|
return acc.concat(populateComponent(key, attribute));
|
||
|
}
|
||
|
return acc;
|
||
|
}, []);
|
||
|
};
|
||
|
|
||
|
const formatPolymorphicPopulate = ({ assoc, path, prefix = '' }) => {
|
||
|
if (_.isString(path) && path === assoc.via) {
|
||
|
return { [`related.${assoc.via}`]: () => {} };
|
||
|
} else if (_.isString(path) && path === assoc.alias) {
|
||
|
// MorphTo side.
|
||
|
if (assoc.related) {
|
||
|
return { [`${prefix}${assoc.alias}.related`]: () => {} };
|
||
|
}
|
||
|
|
||
|
// oneToMorph or manyToMorph side.
|
||
|
// Retrieve collection name because we are using it to build our hidden model.
|
||
|
const model = findModelByAssoc({ assoc });
|
||
|
|
||
|
return {
|
||
|
[`${prefix}${assoc.alias}.${model.collectionName}`]: function(query) {
|
||
|
query.orderBy('created_at', 'desc');
|
||
|
},
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
module.exports = populateFetch;
|