clone components

This commit is contained in:
Marc-Roig 2023-03-21 14:09:30 +01:00 committed by Josh
parent 460099408b
commit 1cc853a5eb
2 changed files with 108 additions and 3 deletions

View File

@ -322,6 +322,91 @@ const deleteComponents = async (uid, entityToDelete, { loadComponents = true } =
}
};
const cloneComponents = async (uid, entityToClone, data) => {
const { attributes = {} } = strapi.getModel(uid);
const componentBody = {};
const componentData = await getComponents(uid, entityToClone);
for (const attributeName of Object.keys(attributes)) {
const attribute = attributes[attributeName];
// If the attribute is not set or on the component to clone, skip it
if (!has(attributeName, data) && !has(attributeName, componentData)) {
continue;
}
if (attribute.type === 'component') {
const { component: componentUID, repeatable = false } = attribute;
const componentValue = has(attributeName, data)
? data[attributeName]
: componentData[attributeName];
if (repeatable === true) {
if (!Array.isArray(componentValue)) {
throw new Error('Expected an array to create repeatable component');
}
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
const components = await mapAsync(
componentValue,
(value) => cloneComponent(componentUID, value),
{ concurrency: isDialectMySQL() ? 1 : Infinity }
);
componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => {
return {
id,
__pivot: {
field: attributeName,
component_type: componentUID,
},
};
});
} else {
const component = await cloneComponent(componentUID, componentValue);
componentBody[attributeName] = component && {
id: component.id,
__pivot: {
field: attributeName,
component_type: componentUID,
},
};
}
continue;
}
if (attribute.type === 'dynamiczone') {
const dynamiczoneValues = has(attributeName, data)
? data[attributeName]
: componentData[attributeName];
if (!Array.isArray(dynamiczoneValues)) {
throw new Error('Expected an array to create repeatable component');
}
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
componentBody[attributeName] = await mapAsync(
dynamiczoneValues,
async (value) => {
const { id } = await cloneComponent(value.__component, value);
return {
id,
__component: value.__component,
__pivot: {
field: attributeName,
},
};
},
{ concurrency: isDialectMySQL() ? 1 : Infinity }
);
continue;
}
}
return componentBody;
};
/** *************************
Component queries
************************** */
@ -377,6 +462,26 @@ const deleteComponent = async (uid, componentToDelete) => {
await strapi.query(uid).delete({ where: { id: componentToDelete.id } });
};
const cloneComponent = async (uid, data) => {
const model = strapi.getModel(uid);
if (!has('id', data)) {
return createComponent(uid, data);
}
const componentData = await cloneComponents(uid, { id: data.id }, data);
const transform = pipe(
// Make sure we don't save the component with a pre-defined ID
omit('id'),
// Remove the component data from the original data object ...
(payload) => omitComponentData(model, payload),
// ... and assign the newly created component instead
assign(componentData)
);
return strapi.query(uid).clone(data.id, { data: transform(data) });
};
module.exports = {
omitComponentData,
getComponents,
@ -384,4 +489,5 @@ module.exports = {
updateComponents,
deleteComponents,
deleteComponent,
cloneComponents,
};

View File

@ -16,6 +16,7 @@ const {
createComponents,
updateComponents,
deleteComponents,
cloneComponents,
} = require('./components');
const { pickSelectionParams } = require('./params');
const { applyTransforms } = require('./attributes');
@ -291,9 +292,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
// TODO: wrap into transaction
// TODO: Implement cloneComponents
// const componentData = await cloneComponents(uid, validData);
const componentData = await createComponents(uid, validData);
const componentData = await cloneComponents(uid, entityToClone, validData);
const entityData = creationPipeline(
Object.assign(omitComponentData(model, validData), componentData),