diff --git a/packages/core/database/lib/entity-manager/regular-relations.js b/packages/core/database/lib/entity-manager/regular-relations.js index bba3e9b72f..0443ce9330 100644 --- a/packages/core/database/lib/entity-manager/regular-relations.js +++ b/packages/core/database/lib/entity-manager/regular-relations.js @@ -296,7 +296,9 @@ const cleanOrderColumnsForInnoDB = async ({ FROM :joinTableName: b WHERE a.:orderColumnName: >= b.:orderColumnName: AND a.:joinColumnName: = b.:joinColumnName: AND a.:joinColumnName: = :id ) AS src_order - FROM :joinTableName: a`, + FROM :joinTableName: a + WHERE a.:joinColumnName: = :id + `, { tempOrderTableName, joinTableName: joinTable.name, @@ -338,7 +340,9 @@ const cleanOrderColumnsForInnoDB = async ({ .map(() => '?') .join(', ')}) ) AS inv_order - FROM ?? a`, + FROM ?? a + WHERE a.?? IN (${inverseRelIds.map(() => '?').join(', ')}) + `, [ tempInvOrderTableName, joinTable.name, @@ -349,6 +353,8 @@ const cleanOrderColumnsForInnoDB = async ({ inverseJoinColumn.name, ...inverseRelIds, joinTable.name, + inverseJoinColumn.name, + ...inverseRelIds, ] ) .transacting(trx); diff --git a/packages/core/strapi/tests/components/repeatable-order.test.api.js b/packages/core/strapi/tests/components/repeatable-order.test.api.js new file mode 100644 index 0000000000..4dca110c6e --- /dev/null +++ b/packages/core/strapi/tests/components/repeatable-order.test.api.js @@ -0,0 +1,97 @@ +'use strict'; + +const { createTestBuilder } = require('../../../../../test/helpers/builder'); +const { createStrapiInstance } = require('../../../../../test/helpers/strapi'); +const { createContentAPIRequest } = require('../../../../../test/helpers/request'); + +let strapi; +let rq; + +const component = { + displayName: 'somecomponent', + attributes: { + name: { + type: 'string', + }, + }, +}; + +const ct = { + displayName: 'withcomponent', + singularName: 'withcomponent', + pluralName: 'withcomponents', + attributes: { + field: { + type: 'component', + component: 'default.somecomponent', + repeatable: true, + required: false, + }, + }, +}; + +const createEntity = async (data) => { + return rq.post('/', { + body: { data }, + qs: { populate: ['field'] }, + }); +}; + +const updateEntity = async (id, data) => { + return rq.put(`/${id}`, { + body: { data }, + qs: { populate: ['field'] }, + }); +}; + +const getEntity = async (id) => { + return rq.get(`/${id}`, { + qs: { populate: ['field'] }, + }); +}; + +describe('Given a content type with a repeatable component and two entities created', () => { + const builder = createTestBuilder(); + let entity1; + let entity2; + + beforeAll(async () => { + await builder.addComponent(component).addContentType(ct).build(); + + strapi = await createStrapiInstance(); + rq = await createContentAPIRequest({ strapi }); + rq.setURLPrefix('/api/withcomponents'); + + // Create two entities + const res1 = await createEntity({ field: [{ name: 'field1' }, { name: 'field2' }] }); + entity1 = res1.body.data; + + const res2 = await createEntity({ field: [{ name: 'field1' }, { name: 'field2' }] }); + entity2 = res2.body.data; + }); + + afterAll(async () => { + await strapi.destroy(); + await builder.cleanup(); + }); + + describe('When I update the order of one of the entities components', () => { + test('Then the order of both entity components is preserved', async () => { + const updatedEntity1 = await updateEntity(entity1.id, { + field: [entity1.attributes.field[1], entity1.attributes.field[0]], + }); + + const res = await getEntity(entity2.id); + + expect(updatedEntity1.body.data.attributes.field).toEqual([ + { id: expect.anything(), name: 'field2' }, + { id: expect.anything(), name: 'field1' }, + ]); + expect(res.statusCode).toBe(200); + expect(res.body.data.attributes.field).toEqual([ + { id: expect.anything(), name: 'field1' }, + { id: expect.anything(), name: 'field2' }, + ]); + }); + }); +});