add transaction in DB entity manager

This commit is contained in:
Pierre Noël 2022-10-06 18:03:10 +02:00
parent 76c0ffb791
commit 6e67d82f5f
4 changed files with 154 additions and 60 deletions

View File

@ -211,12 +211,24 @@ const createEntityManager = (db) => {
} }
const dataToInsert = processData(metadata, data, { withDefaults: true }); const dataToInsert = processData(metadata, data, { withDefaults: true });
let id;
const res = await this.createQueryBuilder(uid).insert(dataToInsert).execute(); const trx = await strapi.db.transaction();
try {
const res = await this.createQueryBuilder(uid)
.insert(dataToInsert)
.transacting(trx)
.execute();
const id = res[0].id || res[0]; id = res[0].id || res[0];
await this.attachRelations(uid, id, data); await this.attachRelations(uid, id, data, { transaction: trx });
await trx.commit();
} catch (e) {
await trx.rollback();
throw e;
}
// TODO: in case there is no select or populate specified return the inserted data ? // TODO: in case there is no select or populate specified return the inserted data ?
// TODO: do not trigger the findOne lifecycles ? // TODO: do not trigger the findOne lifecycles ?
@ -281,14 +293,26 @@ const createEntityManager = (db) => {
const { id } = entity; const { id } = entity;
const dataToUpdate = processData(metadata, data); const trx = await strapi.db.transaction();
try {
const dataToUpdate = processData(metadata, data);
if (!isEmpty(dataToUpdate)) { if (!isEmpty(dataToUpdate)) {
await this.createQueryBuilder(uid).where({ id }).update(dataToUpdate).execute(); await this.createQueryBuilder(uid)
.where({ id })
.update(dataToUpdate)
.transacting(trx)
.execute();
}
await this.updateRelations(uid, id, data, { transaction: trx });
await trx.commit();
} catch (e) {
await trx.rollback();
throw e;
} }
await this.updateRelations(uid, id, data);
// TODO: do not trigger the findOne lifecycles ? // TODO: do not trigger the findOne lifecycles ?
const result = await this.findOne(uid, { const result = await this.findOne(uid, {
where: { id }, where: { id },
@ -348,9 +372,17 @@ const createEntityManager = (db) => {
const { id } = entity; const { id } = entity;
await this.createQueryBuilder(uid).where({ id }).delete().execute(); const trx = await strapi.db.transaction();
try {
await this.createQueryBuilder(uid).where({ id }).delete().transacting(trx).execute();
await this.deleteRelations(uid, id); await this.deleteRelations(uid, id, { transaction: trx });
await trx.commit();
} catch (e) {
await trx.rollback();
throw e;
}
await db.lifecycles.run('afterDelete', uid, { params, result: entity }, states); await db.lifecycles.run('afterDelete', uid, { params, result: entity }, states);
@ -381,7 +413,7 @@ const createEntityManager = (db) => {
* @param {object} data - data received for creation * @param {object} data - data received for creation
*/ */
// TODO: wrap Transaction // TODO: wrap Transaction
async attachRelations(uid, id, data) { async attachRelations(uid, id, data, { transaction: trx }) {
const { attributes } = db.metadata.get(uid); const { attributes } = db.metadata.get(uid);
for (const attributeName of Object.keys(attributes)) { for (const attributeName of Object.keys(attributes)) {
@ -409,6 +441,7 @@ const createEntityManager = (db) => {
await this.createQueryBuilder(target) await this.createQueryBuilder(target)
.update({ [idColumn.name]: id, [typeColumn.name]: uid }) .update({ [idColumn.name]: id, [typeColumn.name]: uid })
.where({ id: relId }) .where({ id: relId })
.transacting(trx)
.execute(); .execute();
} else if (targetAttribute.relation === 'morphToMany') { } else if (targetAttribute.relation === 'morphToMany') {
const { joinTable } = targetAttribute; const { joinTable } = targetAttribute;
@ -432,7 +465,7 @@ const createEntityManager = (db) => {
}; };
}); });
await this.createQueryBuilder(joinTable.name).insert(rows).execute(); await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute();
} }
continue; continue;
@ -464,9 +497,10 @@ const createEntityManager = (db) => {
attributeName, attributeName,
joinTable, joinTable,
db, db,
transaction: trx,
}); });
await this.createQueryBuilder(joinTable.name).insert(rows).execute(); await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute();
continue; continue;
} }
@ -481,6 +515,7 @@ const createEntityManager = (db) => {
await this.createQueryBuilder(uid) await this.createQueryBuilder(uid)
.where({ [attribute.joinColumn.name]: relIdsToAdd, id: { $ne: id } }) .where({ [attribute.joinColumn.name]: relIdsToAdd, id: { $ne: id } })
.update({ [attribute.joinColumn.name]: null }) .update({ [attribute.joinColumn.name]: null })
.transacting(trx)
.execute(); .execute();
} }
@ -498,12 +533,14 @@ const createEntityManager = (db) => {
await this.createQueryBuilder(target) await this.createQueryBuilder(target)
.where({ [attribute.joinColumn.referencedColumn]: id }) .where({ [attribute.joinColumn.referencedColumn]: id })
.update({ [attribute.joinColumn.referencedColumn]: null }) .update({ [attribute.joinColumn.referencedColumn]: null })
.transacting(trx)
.execute(); .execute();
await this.createQueryBuilder(target) await this.createQueryBuilder(target)
.update({ [attribute.joinColumn.referencedColumn]: id }) .update({ [attribute.joinColumn.referencedColumn]: id })
// NOTE: works if it is an array or a single id // NOTE: works if it is an array or a single id
.where({ id: relIdsToAdd }) .where({ id: relIdsToAdd })
.transacting(trx)
.execute(); .execute();
} }
@ -518,7 +555,13 @@ const createEntityManager = (db) => {
const relIdsToadd = toIds(relsToAdd); const relIdsToadd = toIds(relsToAdd);
if (isBidirectional(attribute) && isOneToAny(attribute)) { if (isBidirectional(attribute) && isOneToAny(attribute)) {
await deletePreviousOneToAnyRelations({ id, attribute, relIdsToadd, db }); await deletePreviousOneToAnyRelations({
id,
attribute,
relIdsToadd,
db,
transaction: trx,
});
} }
// prepare new relations to insert // prepare new relations to insert
@ -546,7 +589,8 @@ const createEntityManager = (db) => {
.whereIn(inverseJoinColumn.name, relIdsToadd) .whereIn(inverseJoinColumn.name, relIdsToadd)
.where(joinTable.on || {}) .where(joinTable.on || {})
.groupBy(inverseJoinColumn.name) .groupBy(inverseJoinColumn.name)
.from(joinTable.name); .from(joinTable.name)
.transacting(trx);
const maxMap = maxResults.reduce( const maxMap = maxResults.reduce(
(acc, res) => Object.assign(acc, { [res[inverseJoinColumn.name]]: res.max }), (acc, res) => Object.assign(acc, { [res[inverseJoinColumn.name]]: res.max }),
@ -563,7 +607,7 @@ const createEntityManager = (db) => {
} }
// insert new relations // insert new relations
await this.createQueryBuilder(joinTable.name).insert(insert).execute(); await this.createQueryBuilder(joinTable.name).insert(insert).transacting(trx).execute();
} }
} }
}, },
@ -578,7 +622,7 @@ const createEntityManager = (db) => {
*/ */
// TODO: check relation exists (handled by FKs except for polymorphics) // TODO: check relation exists (handled by FKs except for polymorphics)
// TODO: wrap Transaction // TODO: wrap Transaction
async updateRelations(uid, id, data) { async updateRelations(uid, id, data, { transaction: trx }) {
const { attributes } = db.metadata.get(uid); const { attributes } = db.metadata.get(uid);
for (const attributeName of Object.keys(attributes)) { for (const attributeName of Object.keys(attributes)) {
@ -603,6 +647,7 @@ const createEntityManager = (db) => {
await this.createQueryBuilder(target) await this.createQueryBuilder(target)
.update({ [idColumn.name]: null, [typeColumn.name]: null }) .update({ [idColumn.name]: null, [typeColumn.name]: null })
.where({ [idColumn.name]: id, [typeColumn.name]: uid }) .where({ [idColumn.name]: id, [typeColumn.name]: uid })
.transacting(trx)
.execute(); .execute();
if (!isNull(cleanRelationData.set)) { if (!isNull(cleanRelationData.set)) {
@ -610,6 +655,7 @@ const createEntityManager = (db) => {
await this.createQueryBuilder(target) await this.createQueryBuilder(target)
.update({ [idColumn.name]: id, [typeColumn.name]: uid }) .update({ [idColumn.name]: id, [typeColumn.name]: uid })
.where({ id: relId }) .where({ id: relId })
.transacting(trx)
.execute(); .execute();
} }
} else if (targetAttribute.relation === 'morphToMany') { } else if (targetAttribute.relation === 'morphToMany') {
@ -626,6 +672,7 @@ const createEntityManager = (db) => {
...(joinTable.on || {}), ...(joinTable.on || {}),
field: attributeName, field: attributeName,
}) })
.transacting(trx)
.execute(); .execute();
if (isEmpty(cleanRelationData.set)) { if (isEmpty(cleanRelationData.set)) {
@ -642,7 +689,7 @@ const createEntityManager = (db) => {
field: attributeName, field: attributeName,
})); }));
await this.createQueryBuilder(joinTable.name).insert(rows).execute(); await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute();
} }
continue; continue;
@ -665,6 +712,7 @@ const createEntityManager = (db) => {
[joinColumn.name]: id, [joinColumn.name]: id,
...(joinTable.on || {}), ...(joinTable.on || {}),
}) })
.transacting(trx)
.execute(); .execute();
if (isEmpty(cleanRelationData.set)) { if (isEmpty(cleanRelationData.set)) {
@ -686,9 +734,10 @@ const createEntityManager = (db) => {
attributeName, attributeName,
joinTable, joinTable,
db, db,
transaction: trx,
}); });
await this.createQueryBuilder(joinTable.name).insert(rows).execute(); await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute();
continue; continue;
} }
@ -707,6 +756,7 @@ const createEntityManager = (db) => {
await this.createQueryBuilder(target) await this.createQueryBuilder(target)
.where({ [attribute.joinColumn.referencedColumn]: id }) .where({ [attribute.joinColumn.referencedColumn]: id })
.update({ [attribute.joinColumn.referencedColumn]: null }) .update({ [attribute.joinColumn.referencedColumn]: null })
.transacting(trx)
.execute(); .execute();
if (!isNull(cleanRelationData.set)) { if (!isNull(cleanRelationData.set)) {
@ -714,6 +764,7 @@ const createEntityManager = (db) => {
await this.createQueryBuilder(target) await this.createQueryBuilder(target)
.where({ id: relIdsToAdd }) .where({ id: relIdsToAdd })
.update({ [attribute.joinColumn.referencedColumn]: id }) .update({ [attribute.joinColumn.referencedColumn]: id })
.transacting(trx)
.execute(); .execute();
} }
} }
@ -732,7 +783,7 @@ const createEntityManager = (db) => {
// only delete relations // only delete relations
if (isNull(cleanRelationData.set)) { if (isNull(cleanRelationData.set)) {
await deleteRelations({ id, attribute, db, relIdsToDelete: 'all' }); await deleteRelations({ id, attribute, db, relIdsToDelete: 'all', transaction: trx });
} else { } else {
const isPartialUpdate = !has('set', cleanRelationData); const isPartialUpdate = !has('set', cleanRelationData);
let relIdsToaddOrMove; let relIdsToaddOrMove;
@ -747,7 +798,7 @@ const createEntityManager = (db) => {
); );
if (!isEmpty(relIdsToDelete)) { if (!isEmpty(relIdsToDelete)) {
await deleteRelations({ id, attribute, db, relIdsToDelete }); await deleteRelations({ id, attribute, db, relIdsToDelete, transaction: trx });
} }
if (isEmpty(cleanRelationData.connect)) { if (isEmpty(cleanRelationData.connect)) {
@ -764,6 +815,7 @@ const createEntityManager = (db) => {
[inverseJoinColumn.name]: { $in: relIdsToaddOrMove }, [inverseJoinColumn.name]: { $in: relIdsToaddOrMove },
}) })
.where(joinTable.on || {}) .where(joinTable.on || {})
.transacting(trx)
.execute(); .execute();
} }
@ -783,6 +835,7 @@ const createEntityManager = (db) => {
.where({ [joinColumn.name]: id }) .where({ [joinColumn.name]: id })
.where(joinTable.on || {}) .where(joinTable.on || {})
.first() .first()
.transacting(trx)
.execute() .execute()
).max; ).max;
@ -805,7 +858,8 @@ const createEntityManager = (db) => {
.whereIn(inverseJoinColumn.name, nonExistingRelsIds) .whereIn(inverseJoinColumn.name, nonExistingRelsIds)
.where(joinTable.on || {}) .where(joinTable.on || {})
.groupBy(inverseJoinColumn.name) .groupBy(inverseJoinColumn.name)
.from(joinTable.name); .from(joinTable.name)
.transacting(trx);
const maxMap = maxResults.reduce( const maxMap = maxResults.reduce(
(acc, res) => Object.assign(acc, { [res[inverseJoinColumn.name]]: res.max }), (acc, res) => Object.assign(acc, { [res[inverseJoinColumn.name]]: res.max }),
@ -820,7 +874,8 @@ const createEntityManager = (db) => {
// insert rows // insert rows
const query = this.createQueryBuilder(joinTable.name) const query = this.createQueryBuilder(joinTable.name)
.insert(insert) .insert(insert)
.onConflict(joinTable.pivotColumns); .onConflict(joinTable.pivotColumns)
.transacting(trx);
if (hasOrderColumn(attribute)) { if (hasOrderColumn(attribute)) {
query.merge([orderColumnName]); query.merge([orderColumnName]);
@ -831,7 +886,7 @@ const createEntityManager = (db) => {
await query.execute(); await query.execute();
// remove gap between orders // remove gap between orders
await cleanOrderColumns({ attribute, db, id }); await cleanOrderColumns({ attribute, db, id, transaction: trx });
} else { } else {
if (isAnyToOne(attribute)) { if (isAnyToOne(attribute)) {
cleanRelationData.set = cleanRelationData.set.slice(-1); cleanRelationData.set = cleanRelationData.set.slice(-1);
@ -844,6 +899,7 @@ const createEntityManager = (db) => {
db, db,
relIdsToDelete: 'all', relIdsToDelete: 'all',
relIdsToNotDelete: relIdsToaddOrMove, relIdsToNotDelete: relIdsToaddOrMove,
transaction: trx,
}); });
if (isEmpty(cleanRelationData.set)) { if (isEmpty(cleanRelationData.set)) {
@ -873,6 +929,7 @@ const createEntityManager = (db) => {
[inverseJoinColumn.name]: { $in: relIdsToaddOrMove }, [inverseJoinColumn.name]: { $in: relIdsToaddOrMove },
}) })
.where(joinTable.on || {}) .where(joinTable.on || {})
.transacting(trx)
.execute(); .execute();
const nonExistingRelsIds = difference( const nonExistingRelsIds = difference(
@ -887,7 +944,8 @@ const createEntityManager = (db) => {
.whereIn(inverseJoinColumn.name, nonExistingRelsIds) .whereIn(inverseJoinColumn.name, nonExistingRelsIds)
.where(joinTable.on || {}) .where(joinTable.on || {})
.groupBy(inverseJoinColumn.name) .groupBy(inverseJoinColumn.name)
.from(joinTable.name); .from(joinTable.name)
.transacting(trx);
const maxMap = maxResults.reduce( const maxMap = maxResults.reduce(
(acc, res) => Object.assign(acc, { [res[inverseJoinColumn.name]]: res.max }), (acc, res) => Object.assign(acc, { [res[inverseJoinColumn.name]]: res.max }),
@ -902,7 +960,8 @@ const createEntityManager = (db) => {
// insert rows // insert rows
const query = this.createQueryBuilder(joinTable.name) const query = this.createQueryBuilder(joinTable.name)
.insert(insert) .insert(insert)
.onConflict(joinTable.pivotColumns); .onConflict(joinTable.pivotColumns)
.transacting(trx);
if (hasOrderColumn(attribute)) { if (hasOrderColumn(attribute)) {
query.merge([orderColumnName]); query.merge([orderColumnName]);
@ -920,6 +979,7 @@ const createEntityManager = (db) => {
attribute, attribute,
relIdsToadd: relIdsToaddOrMove, relIdsToadd: relIdsToaddOrMove,
db, db,
transaction: trx,
}); });
} }
@ -930,6 +990,7 @@ const createEntityManager = (db) => {
attribute, attribute,
relIdToadd: relIdsToaddOrMove[0], relIdToadd: relIdsToaddOrMove[0],
db, db,
transaction: trx,
}); });
} }
} }
@ -947,7 +1008,7 @@ const createEntityManager = (db) => {
* @param {ID} id - entity ID * @param {ID} id - entity ID
*/ */
// TODO: wrap Transaction // TODO: wrap Transaction
async deleteRelations(uid, id) { async deleteRelations(uid, id, { transaction: trx }) {
const { attributes } = db.metadata.get(uid); const { attributes } = db.metadata.get(uid);
for (const attributeName of Object.keys(attributes)) { for (const attributeName of Object.keys(attributes)) {
@ -976,6 +1037,7 @@ const createEntityManager = (db) => {
await this.createQueryBuilder(target) await this.createQueryBuilder(target)
.update({ [idColumn.name]: null, [typeColumn.name]: null }) .update({ [idColumn.name]: null, [typeColumn.name]: null })
.where({ [idColumn.name]: id, [typeColumn.name]: uid }) .where({ [idColumn.name]: id, [typeColumn.name]: uid })
.transacting(trx)
.execute(); .execute();
} else if (targetAttribute.relation === 'morphToMany') { } else if (targetAttribute.relation === 'morphToMany') {
const { joinTable } = targetAttribute; const { joinTable } = targetAttribute;
@ -991,6 +1053,7 @@ const createEntityManager = (db) => {
...(joinTable.on || {}), ...(joinTable.on || {}),
field: attributeName, field: attributeName,
}) })
.transacting(trx)
.execute(); .execute();
} }
@ -1019,6 +1082,7 @@ const createEntityManager = (db) => {
[joinColumn.name]: id, [joinColumn.name]: id,
...(joinTable.on || {}), ...(joinTable.on || {}),
}) })
.transacting(trx)
.execute(); .execute();
continue; continue;
@ -1043,11 +1107,12 @@ const createEntityManager = (db) => {
await this.createQueryBuilder(target) await this.createQueryBuilder(target)
.where({ [attribute.joinColumn.referencedColumn]: id }) .where({ [attribute.joinColumn.referencedColumn]: id })
.update({ [attribute.joinColumn.referencedColumn]: null }) .update({ [attribute.joinColumn.referencedColumn]: null })
.transacting(trx)
.execute(); .execute();
} }
if (attribute.joinTable) { if (attribute.joinTable) {
await deleteRelations({ id, attribute, db, relIdsToDelete: 'all' }); await deleteRelations({ id, attribute, db, relIdsToDelete: 'all', transaction: trx });
} }
} }
}, },

View File

@ -20,7 +20,7 @@ const getMorphToManyRowsLinkedToMorphOne = (rows, { uid, attributeName, typeColu
const deleteRelatedMorphOneRelationsAfterMorphToManyUpdate = async ( const deleteRelatedMorphOneRelationsAfterMorphToManyUpdate = async (
rows, rows,
{ uid, attributeName, joinTable, db } { uid, attributeName, joinTable, db, transaction: trx }
) => { ) => {
const { morphColumn } = joinTable; const { morphColumn } = joinTable;
const { idColumn, typeColumn } = morphColumn; const { idColumn, typeColumn } = morphColumn;
@ -50,7 +50,11 @@ const deleteRelatedMorphOneRelationsAfterMorphToManyUpdate = async (
} }
if (!isEmpty(orWhere)) { if (!isEmpty(orWhere)) {
await createQueryBuilder(joinTable.name, db).delete().where({ $or: orWhere }).execute(); await createQueryBuilder(joinTable.name, db)
.delete()
.where({ $or: orWhere })
.transacting(trx)
.execute();
} }
}; };

View File

@ -19,7 +19,13 @@ const { createQueryBuilder } = require('../query');
* @param {string} params.inverseRelIds - entity ids of the inverse side for which the current relations will be deleted * @param {string} params.inverseRelIds - entity ids of the inverse side for which the current relations will be deleted
* @param {string} params.db - database instance * @param {string} params.db - database instance
*/ */
const deletePreviousOneToAnyRelations = async ({ id, attribute, relIdsToadd, db }) => { const deletePreviousOneToAnyRelations = async ({
id,
attribute,
relIdsToadd,
db,
transaction: trx,
}) => {
if (!(isBidirectional(attribute) && isOneToAny(attribute))) { if (!(isBidirectional(attribute) && isOneToAny(attribute))) {
throw new Error( throw new Error(
'deletePreviousOneToAnyRelations can only be called for bidirectional oneToAny relations' 'deletePreviousOneToAnyRelations can only be called for bidirectional oneToAny relations'
@ -35,9 +41,10 @@ const deletePreviousOneToAnyRelations = async ({ id, attribute, relIdsToadd, db
[joinColumn.name]: { $ne: id }, [joinColumn.name]: { $ne: id },
}) })
.where(joinTable.on || {}) .where(joinTable.on || {})
.transacting(trx)
.execute(); .execute();
await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToadd }); await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToadd, transaction: trx });
}; };
/** /**
@ -48,7 +55,13 @@ const deletePreviousOneToAnyRelations = async ({ id, attribute, relIdsToadd, db
* @param {string} params.relIdToadd - entity id of the new relation * @param {string} params.relIdToadd - entity id of the new relation
* @param {string} params.db - database instance * @param {string} params.db - database instance
*/ */
const deletePreviousAnyToOneRelations = async ({ id, attribute, relIdToadd, db }) => { const deletePreviousAnyToOneRelations = async ({
id,
attribute,
relIdToadd,
db,
transaction: trx,
}) => {
const { joinTable } = attribute; const { joinTable } = attribute;
const { joinColumn, inverseJoinColumn } = joinTable; const { joinColumn, inverseJoinColumn } = joinTable;
@ -67,6 +80,7 @@ const deletePreviousAnyToOneRelations = async ({ id, attribute, relIdToadd, db }
[inverseJoinColumn.name]: { $ne: relIdToadd }, [inverseJoinColumn.name]: { $ne: relIdToadd },
}) })
.where(joinTable.on || {}) .where(joinTable.on || {})
.transacting(trx)
.execute(); .execute();
const relIdsToDelete = map(inverseJoinColumn.name, relsToDelete); const relIdsToDelete = map(inverseJoinColumn.name, relsToDelete);
@ -78,9 +92,10 @@ const deletePreviousAnyToOneRelations = async ({ id, attribute, relIdToadd, db }
[inverseJoinColumn.name]: { $in: relIdsToDelete }, [inverseJoinColumn.name]: { $in: relIdsToDelete },
}) })
.where(joinTable.on || {}) .where(joinTable.on || {})
.transacting(trx)
.execute(); .execute();
await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToDelete }); await cleanOrderColumns({ attribute, db, inverseRelIds: relIdsToDelete, transaction: trx });
// handling oneToOne // handling oneToOne
} else { } else {
@ -91,6 +106,7 @@ const deletePreviousAnyToOneRelations = async ({ id, attribute, relIdToadd, db }
[inverseJoinColumn.name]: { $ne: relIdToadd }, [inverseJoinColumn.name]: { $ne: relIdToadd },
}) })
.where(joinTable.on || {}) .where(joinTable.on || {})
.transacting(trx)
.execute(); .execute();
} }
}; };
@ -110,6 +126,7 @@ const deleteRelations = async ({
db, db,
relIdsToNotDelete = [], relIdsToNotDelete = [],
relIdsToDelete = [], relIdsToDelete = [],
transaction: trx,
}) => { }) => {
const { joinTable } = attribute; const { joinTable } = attribute;
const { joinColumn, inverseJoinColumn } = joinTable; const { joinColumn, inverseJoinColumn } = joinTable;
@ -131,6 +148,7 @@ const deleteRelations = async ({
.where(joinTable.on || {}) .where(joinTable.on || {})
.orderBy('id') .orderBy('id')
.limit(batchSize) .limit(batchSize)
.transacting(trx)
.execute(); .execute();
done = batchToDelete.length < batchSize; done = batchToDelete.length < batchSize;
lastId = batchToDelete[batchToDelete.length - 1]?.id; lastId = batchToDelete[batchToDelete.length - 1]?.id;
@ -144,9 +162,10 @@ const deleteRelations = async ({
[inverseJoinColumn.name]: { $in: batchIds }, [inverseJoinColumn.name]: { $in: batchIds },
}) })
.where(joinTable.on || {}) .where(joinTable.on || {})
.transacting(trx)
.execute(); .execute();
await cleanOrderColumns({ attribute, db, id, inverseRelIds: batchIds }); await cleanOrderColumns({ attribute, db, id, inverseRelIds: batchIds, transaction: trx });
} }
} else { } else {
await createQueryBuilder(joinTable.name, db) await createQueryBuilder(joinTable.name, db)
@ -157,6 +176,7 @@ const deleteRelations = async ({
...(all ? {} : { [inverseJoinColumn.name]: { $in: relIdsToDelete } }), ...(all ? {} : { [inverseJoinColumn.name]: { $in: relIdsToDelete } }),
}) })
.where(joinTable.on || {}) .where(joinTable.on || {})
.transacting(trx)
.execute(); .execute();
} }
}; };
@ -169,7 +189,7 @@ const deleteRelations = async ({
* @param {string} params.db - database instance * @param {string} params.db - database instance
* @param {string} params.inverseRelIds - entity ids of the inverse side for which the clean will be done * @param {string} params.inverseRelIds - entity ids of the inverse side for which the clean will be done
*/ */
const cleanOrderColumns = async ({ id, attribute, db, inverseRelIds }) => { const cleanOrderColumns = async ({ id, attribute, db, inverseRelIds, transaction: trx }) => {
if ( if (
!(hasOrderColumn(attribute) && id) && !(hasOrderColumn(attribute) && id) &&
!(hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds)) !(hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds))
@ -208,31 +228,37 @@ const cleanOrderColumns = async ({ id, attribute, db, inverseRelIds }) => {
// https://github.com/knex/knex/issues/2504 // https://github.com/knex/knex/issues/2504
switch (strapi.db.dialect.client) { switch (strapi.db.dialect.client) {
case 'mysql': case 'mysql':
await db.getConnection().raw( await db
`UPDATE .getConnection()
?? as a, .raw(
( `UPDATE
SELECT ${select.join(', ')} ?? as a,
FROM ?? (
WHERE ${where.join(' OR ')} SELECT ${select.join(', ')}
) AS b FROM ??
SET ${update.join(', ')} WHERE ${where.join(' OR ')}
WHERE b.id = a.id`, ) AS b
[joinTable.name, ...selectBinding, joinTable.name, ...whereBinding, ...updateBinding] SET ${update.join(', ')}
); WHERE b.id = a.id`,
[joinTable.name, ...selectBinding, joinTable.name, ...whereBinding, ...updateBinding]
)
.transacting(trx);
break; break;
default: default:
await db.getConnection().raw( await db
`UPDATE ?? as a .getConnection()
SET ${update.join(', ')} .raw(
FROM ( `UPDATE ?? as a
SELECT ${select.join(', ')} SET ${update.join(', ')}
FROM ?? FROM (
WHERE ${where.join(' OR ')} SELECT ${select.join(', ')}
) AS b FROM ??
WHERE b.id = a.id`, WHERE ${where.join(' OR ')}
[joinTable.name, ...updateBinding, ...selectBinding, joinTable.name, ...whereBinding] ) AS b
); WHERE b.id = a.id`,
[joinTable.name, ...updateBinding, ...selectBinding, joinTable.name, ...whereBinding]
)
.transacting(trx);
/* /*
`UPDATE :joinTable: as a `UPDATE :joinTable: as a
SET :orderColumn: = b.src_order, :inverseOrderColumn: = b.inv_order SET :orderColumn: = b.src_order, :inverseOrderColumn: = b.inv_order

View File

@ -47,7 +47,6 @@ const createComponents = async (uid, data) => {
componentValue.map((value) => createComponent(componentUID, value)) componentValue.map((value) => createComponent(componentUID, value))
); );
// TODO: add order
componentBody[attributeName] = components.map(({ id }) => { componentBody[attributeName] = components.map(({ id }) => {
return { return {
id, id,