clone entity

This commit is contained in:
Marc-Roig 2023-03-19 19:29:22 +01:00 committed by Josh
parent 4c310e5659
commit 76eb559466
2 changed files with 86 additions and 16 deletions

View File

@ -80,6 +80,10 @@ const createRepository = (uid, db) => {
return db.entityManager.updateMany(uid, params);
},
clone(id, params) {
return db.entityManager.clone(uid, id, params);
},
delete(params) {
return db.entityManager.delete(uid, params);
},

View File

@ -1,26 +1,30 @@
'use strict';
const {
isUndefined,
castArray,
compact,
isNil,
has,
isString,
isInteger,
pick,
isPlainObject,
isEmpty,
isArray,
isNull,
uniqWith,
isEqual,
differenceWith,
isNumber,
map,
difference,
differenceWith,
flow,
has,
isArray,
isEmpty,
isEqual,
isInteger,
isNil,
isNull,
isNumber,
isPlainObject,
isString,
isUndefined,
map,
mergeWith,
omit,
pick,
uniqBy,
uniqWith,
} = require('lodash/fp');
const { mapAsync } = require('@strapi/utils');
const types = require('../types');
const { createField } = require('../fields');
@ -28,6 +32,7 @@ const { createQueryBuilder } = require('../query');
const { createRepository } = require('./entity-repository');
const { deleteRelatedMorphOneRelationsAfterMorphToManyUpdate } = require('./morph-relations');
const {
isPolymorphic,
isBidirectional,
isAnyToOne,
isOneToAny,
@ -365,6 +370,63 @@ const createEntityManager = (db) => {
return result;
},
async clone(uid, cloneId, params = {}) {
const states = await db.lifecycles.run('beforeCreate', uid, { params });
const metadata = db.metadata.get(uid);
const { data } = params;
if (!isNil(data) && !isPlainObject(data)) {
throw new Error('Create expects a data object');
}
// TODO: Handle join columns?
const entity = await this.findOne(uid, { where: { id: cloneId } });
const dataToInsert = flow(
// Omit unwanted properties
omit(['id', 'created_at', 'updated_at']),
// Merge with provided data, override to null if data attribute is null
mergeWith(params.data || {}, (a, b) => (b === null ? b : a)),
// Process data with metadata
(entity) => processData(metadata, entity, { withDefaults: true })
)(entity);
const res = await this.createQueryBuilder(uid).insert(dataToInsert).execute();
const id = res[0].id || res[0];
// TODO: try strapi.db.transaction(method) instead of trx.get()
const trx = await strapi.db.transaction();
try {
const cloneAttrs = Object.entries(metadata.attributes).reduce((acc, [attrName, attr]) => {
if (attr.type === 'relation' && attr.joinTable && !attr.component) {
acc[attrName] = true;
}
return acc;
}, {});
// How to get the relations of the clone entity ?
await this.cloneRelations(uid, id, cloneId, { cloneAttrs, transaction: trx.get() });
await this.updateRelations(uid, id, data, { transaction: trx.get() });
await trx.commit();
} catch (e) {
await trx.rollback();
await this.createQueryBuilder(uid).where({ id }).delete().execute();
throw e;
}
const result = await this.findOne(uid, {
where: { id },
select: params.select,
populate: params.populate,
});
await db.lifecycles.run('afterCreate', uid, { params, result }, states);
return result;
},
async delete(uid, params = {}) {
const states = await db.lifecycles.run('beforeDelete', uid, { params });
@ -1203,13 +1265,17 @@ const createEntityManager = (db) => {
);
}
if (isPolymorphic(attribute)) {
// TODO: add support for cloning polymorphic relations
return;
}
if (attribute.joinColumn) {
// TODO: add support for cloning oneToMany relations on the owning side
return;
}
if (!attribute.joinTable) {
// TODO: add support for cloning polymorphic relations
return;
}