mirror of
https://github.com/strapi/strapi.git
synced 2025-09-21 14:31:16 +00:00
Support creation
This commit is contained in:
parent
a34f117a4a
commit
f82b05dc94
@ -364,57 +364,60 @@ const createOnFetchPopulateFn = ({
|
|||||||
// TODO: handle Dynamic zone
|
// TODO: handle Dynamic zone
|
||||||
componentAttributes.forEach(name => {
|
componentAttributes.forEach(name => {
|
||||||
const attr = definition.attributes[name];
|
const attr = definition.attributes[name];
|
||||||
|
const { type } = attr;
|
||||||
|
|
||||||
const component = strapi.components[attr.component];
|
if (type === 'component') {
|
||||||
|
const component = strapi.components[attr.component];
|
||||||
|
|
||||||
const assocs = (component.associations || []).filter(
|
const assocs = (component.associations || []).filter(
|
||||||
assoc => assoc.autoPopulate === true
|
assoc => assoc.autoPopulate === true
|
||||||
);
|
);
|
||||||
|
|
||||||
let subpopulates = [];
|
let subpopulates = [];
|
||||||
|
|
||||||
assocs.forEach(assoc => {
|
assocs.forEach(assoc => {
|
||||||
if (isPolymorphic({ assoc })) {
|
if (isPolymorphic({ assoc })) {
|
||||||
if (
|
if (
|
||||||
assoc.nature === 'oneToManyMorph' ||
|
assoc.nature === 'oneToManyMorph' ||
|
||||||
assoc.nature === 'manyToManyMorph'
|
assoc.nature === 'manyToManyMorph'
|
||||||
) {
|
) {
|
||||||
|
subpopulates.push({
|
||||||
|
path: assoc.alias,
|
||||||
|
match: {
|
||||||
|
[`${assoc.via}.${assoc.filter}`]: assoc.alias,
|
||||||
|
[`${assoc.via}.kind`]: definition.globalId,
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
sort: '-createdAt',
|
||||||
|
},
|
||||||
|
select: undefined,
|
||||||
|
model: undefined,
|
||||||
|
_docs: {},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
subpopulates.push({ path: `${assoc.alias}.ref`, _docs: {} });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
subpopulates.push({
|
subpopulates.push({
|
||||||
path: assoc.alias,
|
path: assoc.alias,
|
||||||
match: {
|
|
||||||
[`${assoc.via}.${assoc.filter}`]: assoc.alias,
|
|
||||||
[`${assoc.via}.kind`]: definition.globalId,
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
sort: '-createdAt',
|
|
||||||
},
|
|
||||||
select: undefined,
|
|
||||||
model: undefined,
|
|
||||||
_docs: {},
|
_docs: {},
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
subpopulates.push({ path: `${assoc.alias}.ref`, _docs: {} });
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
this._mongooseOptions.populate &&
|
||||||
|
this._mongooseOptions.populate[name]
|
||||||
|
) {
|
||||||
|
this._mongooseOptions.populate[name].path = `${name}.ref`;
|
||||||
|
this._mongooseOptions.populate[name].populate = subpopulates;
|
||||||
} else {
|
} else {
|
||||||
subpopulates.push({
|
_.set(this._mongooseOptions, ['populate', name], {
|
||||||
path: assoc.alias,
|
path: `${name}.ref`,
|
||||||
|
populate: subpopulates,
|
||||||
_docs: {},
|
_docs: {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (
|
|
||||||
this._mongooseOptions.populate &&
|
|
||||||
this._mongooseOptions.populate[name]
|
|
||||||
) {
|
|
||||||
this._mongooseOptions.populate[name].path = `${name}.ref`;
|
|
||||||
this._mongooseOptions.populate[name].populate = subpopulates;
|
|
||||||
} else {
|
|
||||||
_.set(this._mongooseOptions, ['populate', name], {
|
|
||||||
path: `${name}.ref`,
|
|
||||||
populate: subpopulates,
|
|
||||||
_docs: {},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -16,9 +16,10 @@ module.exports = ({ model, modelKey, strapi }) => {
|
|||||||
_.has(obj, model.primaryKey) ? obj[model.primaryKey] : obj.id;
|
_.has(obj, model.primaryKey) ? obj[model.primaryKey] : obj.id;
|
||||||
|
|
||||||
const assocKeys = model.associations.map(ast => ast.alias);
|
const assocKeys = model.associations.map(ast => ast.alias);
|
||||||
const componentKeys = Object.keys(model.attributes).filter(key => {
|
const componentKeys = Object.keys(model.attributes).filter(key =>
|
||||||
return model.attributes[key].type === 'component';
|
['component', 'dynamiczone'].includes(model.attributes[key].type)
|
||||||
});
|
);
|
||||||
|
|
||||||
const excludedKeys = assocKeys.concat(componentKeys);
|
const excludedKeys = assocKeys.concat(componentKeys);
|
||||||
|
|
||||||
const defaultPopulate = model.associations
|
const defaultPopulate = model.associations
|
||||||
@ -38,49 +39,96 @@ module.exports = ({ model, modelKey, strapi }) => {
|
|||||||
|
|
||||||
for (let key of componentKeys) {
|
for (let key of componentKeys) {
|
||||||
const attr = model.attributes[key];
|
const attr = model.attributes[key];
|
||||||
const { component, required = false, repeatable = false } = attr;
|
const { type } = attr;
|
||||||
|
|
||||||
const componentModel = strapi.components[component];
|
if (type === 'component') {
|
||||||
|
const { component, required = false, repeatable = false } = attr;
|
||||||
|
|
||||||
if (required === true && !_.has(values, key)) {
|
const componentModel = strapi.components[component];
|
||||||
const err = new Error(`Component ${key} is required`);
|
|
||||||
err.status = 400;
|
if (required === true && !_.has(values, key)) {
|
||||||
throw err;
|
const err = new Error(`Component ${key} is required`);
|
||||||
|
err.status = 400;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_.has(values, key)) continue;
|
||||||
|
|
||||||
|
const componentValue = values[key];
|
||||||
|
|
||||||
|
if (repeatable === true) {
|
||||||
|
validateRepeatableInput(componentValue, { key, ...attr });
|
||||||
|
const components = await Promise.all(
|
||||||
|
componentValue.map(value => {
|
||||||
|
return strapi.query(component).create(value);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const componentsArr = components.map(componentEntry => ({
|
||||||
|
kind: componentModel.globalId,
|
||||||
|
ref: componentEntry,
|
||||||
|
}));
|
||||||
|
|
||||||
|
entry[key] = componentsArr;
|
||||||
|
await entry.save();
|
||||||
|
} else {
|
||||||
|
validateNonRepeatableInput(componentValue, { key, ...attr });
|
||||||
|
if (componentValue === null) continue;
|
||||||
|
|
||||||
|
const componentEntry = await strapi
|
||||||
|
.query(component)
|
||||||
|
.create(componentValue);
|
||||||
|
entry[key] = [
|
||||||
|
{
|
||||||
|
kind: componentModel.globalId,
|
||||||
|
ref: componentEntry,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await entry.save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.has(values, key)) continue;
|
if (type === 'dynamiczone') {
|
||||||
|
const { required = false } = attr;
|
||||||
|
|
||||||
const componentValue = values[key];
|
if (required === true && !_.has(values, key)) {
|
||||||
|
const err = new Error(`Dynamiczone ${key} is required`);
|
||||||
|
err.status = 400;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
if (repeatable === true) {
|
if (!_.has(values, key)) continue;
|
||||||
validateRepeatableInput(componentValue, { key, ...attr });
|
|
||||||
const components = await Promise.all(
|
const dynamiczoneValues = values[key];
|
||||||
componentValue.map(value => {
|
|
||||||
return strapi.query(component).create(value);
|
validateDynamiczoneInput(dynamiczoneValues, { key, ...attr });
|
||||||
|
|
||||||
|
const dynamiczones = await Promise.all(
|
||||||
|
dynamiczoneValues.map(value => {
|
||||||
|
const component = value.__component;
|
||||||
|
return strapi
|
||||||
|
.query(component)
|
||||||
|
.create(value)
|
||||||
|
.then(entity => {
|
||||||
|
return {
|
||||||
|
__component: value.__component,
|
||||||
|
entity,
|
||||||
|
};
|
||||||
|
});
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const componentsArr = components.map(componentEntry => ({
|
const componentsArr = dynamiczones.map(({ __component, entity }) => {
|
||||||
kind: componentModel.globalId,
|
const componentModel = strapi.components[__component];
|
||||||
ref: componentEntry,
|
|
||||||
}));
|
return {
|
||||||
|
kind: componentModel.globalId,
|
||||||
|
ref: entity,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
entry[key] = componentsArr;
|
entry[key] = componentsArr;
|
||||||
await entry.save();
|
await entry.save();
|
||||||
} else {
|
|
||||||
validateNonRepeatableInput(componentValue, { key, ...attr });
|
|
||||||
if (componentValue === null) continue;
|
|
||||||
|
|
||||||
const componentEntry = await strapi
|
|
||||||
.query(component)
|
|
||||||
.create(componentValue);
|
|
||||||
entry[key] = [
|
|
||||||
{
|
|
||||||
kind: componentModel.globalId,
|
|
||||||
ref: componentEntry,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
await entry.save();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -454,3 +502,56 @@ function validateNonRepeatableInput(value, { key, required }) {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateDynamiczoneInput(
|
||||||
|
value,
|
||||||
|
{ key, min, max, components, required }
|
||||||
|
) {
|
||||||
|
if (!Array.isArray(value)) {
|
||||||
|
const err = new Error(`Dynamiczone ${key} is invalid. Expected an array`);
|
||||||
|
err.status = 400;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
value.forEach(val => {
|
||||||
|
if (typeof val !== 'object' || Array.isArray(val) || val === null) {
|
||||||
|
const err = new Error(
|
||||||
|
`Dynamiczone ${key} has invalid items. Expected each items to be objects`
|
||||||
|
);
|
||||||
|
err.status = 400;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_.has(val, '__component')) {
|
||||||
|
const err = new Error(
|
||||||
|
`Dynamiczone ${key} has invalid items. Expected each items to have a valid __component key`
|
||||||
|
);
|
||||||
|
err.status = 400;
|
||||||
|
throw err;
|
||||||
|
} else if (!components.includes(val.__component)) {
|
||||||
|
const err = new Error(
|
||||||
|
`Dynamiczone ${key} has invalid items. Each item must have a __component key that is present in the attribute definition`
|
||||||
|
);
|
||||||
|
err.status = 400;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
(required === true || (required !== true && value.length > 0)) &&
|
||||||
|
(min && value.length < min)
|
||||||
|
) {
|
||||||
|
const err = new Error(
|
||||||
|
`Dynamiczone ${key} must contain at least ${min} items`
|
||||||
|
);
|
||||||
|
err.status = 400;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
if (max && value.length > max) {
|
||||||
|
const err = new Error(
|
||||||
|
`Dynamiczone ${key} must contain at most ${max} items`
|
||||||
|
);
|
||||||
|
err.status = 400;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user