From 76eb559466cb4802e8acfb2a4da97ef11e869315 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Sun, 19 Mar 2023 19:29:22 +0100 Subject: [PATCH] clone entity --- .../lib/entity-manager/entity-repository.js | 4 + .../core/database/lib/entity-manager/index.js | 98 ++++++++++++++++--- 2 files changed, 86 insertions(+), 16 deletions(-) diff --git a/packages/core/database/lib/entity-manager/entity-repository.js b/packages/core/database/lib/entity-manager/entity-repository.js index 0e6ec1f29a..16d222046a 100644 --- a/packages/core/database/lib/entity-manager/entity-repository.js +++ b/packages/core/database/lib/entity-manager/entity-repository.js @@ -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); }, diff --git a/packages/core/database/lib/entity-manager/index.js b/packages/core/database/lib/entity-manager/index.js index 49bea37ed7..25f698cddd 100644 --- a/packages/core/database/lib/entity-manager/index.js +++ b/packages/core/database/lib/entity-manager/index.js @@ -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; }