fix: relations are not returned in the correct order

When removing or adding a relation in an entity, other entities from the same Content Type were seeing that same relation reordered.

Cause: We were updating the order of the other entities when we should only be updating the inverse order.
This commit is contained in:
Marc-Roig 2023-07-11 10:17:06 +02:00
parent 1141d65f7d
commit f6246c145d
No known key found for this signature in database
GPG Key ID: FB4E2C43A0BEE249

View File

@ -206,29 +206,40 @@ const cleanOrderColumns = async ({ id, attribute, db, inverseRelIds, transaction
const { joinTable } = attribute; const { joinTable } = attribute;
const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable; const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
// Build the update query based on the relation type
// See query below for more details
const update = []; const update = [];
const updateBinding = []; const updateBinding = [];
const select = ['??']; const selectEntityRelations = db.connection(joinTable.name).select('id');
const selectBinding = ['id']; const selectInverseEntityRelations = db.connection(joinTable.name).select('id');
const where = [];
const whereBinding = [];
if (hasOrderColumn(attribute) && id) { if (hasOrderColumn(attribute) && id) {
// Update order column of join table
update.push('?? = b.src_order'); update.push('?? = b.src_order');
updateBinding.push(orderColumnName); updateBinding.push(orderColumnName);
select.push('ROW_NUMBER() OVER (PARTITION BY ?? ORDER BY ??) AS src_order');
selectBinding.push(joinColumn.name, orderColumnName); // Calculate order column of entity relations
where.push('?? = ?'); selectEntityRelations
whereBinding.push(joinColumn.name, id); .rowNumber('src_order', joinColumn.name, orderColumnName)
.where(joinColumn.name, id);
// Do not update the order column of entities that were also using the same relations
selectInverseEntityRelations.select({ src_order: orderColumnName });
} }
if (hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds)) { if (hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds)) {
// Update inverse order column of join table
update.push('?? = b.inv_order'); update.push('?? = b.inv_order');
updateBinding.push(inverseOrderColumnName); updateBinding.push(inverseOrderColumnName);
select.push('ROW_NUMBER() OVER (PARTITION BY ?? ORDER BY ??) AS inv_order');
selectBinding.push(inverseJoinColumn.name, inverseOrderColumnName); // Calculate inv order column of inverse side for the entity relations
where.push(`?? IN (${inverseRelIds.map(() => '?').join(', ')})`); selectEntityRelations.rowNumber('inv_order', inverseJoinColumn.name, inverseOrderColumnName);
whereBinding.push(inverseJoinColumn.name, ...inverseRelIds);
// Calculate inv order column of entities that were also using the same relations
selectInverseEntityRelations
.rowNumber('inv_order', inverseJoinColumn.name, inverseOrderColumnName)
.where(inverseJoinColumn.name, 'in', inverseRelIds);
} }
switch (strapi.db.dialect.client) { switch (strapi.db.dialect.client) {
@ -237,16 +248,20 @@ const cleanOrderColumns = async ({ id, attribute, db, inverseRelIds, transaction
await db await db
.getConnection() .getConnection()
.raw( .raw(
`UPDATE `UPDATE ?? as a,
?? as a,
( (
SELECT ${select.join(', ')} ${selectEntityRelations.toSQL().sql}
FROM ?? UNION
WHERE ${where.join(' OR ')} ${selectInverseEntityRelations.toSQL().sql}
) AS b ) AS b
SET ${update.join(', ')} SET ${update.join(', ')}
WHERE b.id = a.id`, WHERE b.id = a.id`,
[joinTable.name, ...selectBinding, joinTable.name, ...whereBinding, ...updateBinding] [
joinTable.name,
...selectEntityRelations.toSQL().bindings,
...selectInverseEntityRelations.toSQL().bindings,
...updateBinding,
]
) )
.transacting(trx); .transacting(trx);
break; break;
@ -254,12 +269,21 @@ const cleanOrderColumns = async ({ id, attribute, db, inverseRelIds, transaction
UPDATE UPDATE
:joinTable: as a, :joinTable: as a,
( (
-- Update the updated entity order columns
SELECT SELECT
id, id,
ROW_NUMBER() OVER ( PARTITION BY :joinColumn: ORDER BY :orderColumn:) AS src_order, ROW_NUMBER() OVER ( PARTITION BY :joinColumn: ORDER BY :orderColumn:) AS src_order,
ROW_NUMBER() OVER ( PARTITION BY :inverseJoinColumn: ORDER BY :inverseOrderColumn:) AS inv_order ROW_NUMBER() OVER ( PARTITION BY :inverseJoinColumn: ORDER BY :inverseOrderColumn:) AS inv_order
FROM :joinTable: FROM :joinTable:
WHERE :joinColumn: = :id OR :inverseJoinColumn: IN (:inverseRelIds) WHERE :joinColumn: = :id
UNION
-- Update the inverse side order columns of entities that relate to the same inverse side
SELECT
id,
:orderColumn: AS src_order,
ROW_NUMBER() OVER ( PARTITION BY :inverseJoinColumn: ORDER BY :inverseOrderColumn:) AS inv_order
FROM :joinTable:
WHERE :inverseJoinColumn: IN (:inverseRelIds)
) AS b ) AS b
SET :orderColumn: = b.src_order, :inverseOrderColumn: = b.inv_order SET :orderColumn: = b.src_order, :inverseOrderColumn: = b.inv_order
WHERE b.id = a.id; WHERE b.id = a.id;
@ -274,12 +298,17 @@ const cleanOrderColumns = async ({ id, attribute, db, inverseRelIds, transaction
`UPDATE ?? as a `UPDATE ?? as a
SET ${update.join(', ')} SET ${update.join(', ')}
FROM ( FROM (
SELECT ${select.join(', ')} ${selectEntityRelations.toSQL().sql}
FROM ?? UNION
WHERE ${where.join(' OR ')} ${selectInverseEntityRelations.toSQL().sql}
) AS b ) AS b
WHERE b.id = a.id`, WHERE b.id = a.id`,
[joinTableName, ...updateBinding, ...selectBinding, joinTableName, ...whereBinding] [
joinTableName,
...updateBinding,
...selectEntityRelations.toSQL().bindings,
...selectInverseEntityRelations.toSQL().bindings,
]
) )
.transacting(trx); .transacting(trx);