diff --git a/packages/core/src/model.js b/packages/core/src/model.js index f552e84d81b2..dc372b0c505f 100644 --- a/packages/core/src/model.js +++ b/packages/core/src/model.js @@ -3213,7 +3213,7 @@ Instead of specifying a Model, either: options = options ?? EMPTY_OBJECT; - const { attributes, attributesWithGetters } = this.constructor.modelDefinition; + const { attributes, attributesWithGetters, rawAttributes } = this.constructor.modelDefinition; if (attributeName) { const attribute = attributes.get(attributeName); @@ -3242,7 +3242,8 @@ Instead of specifying a Model, either: || options.plain && this._options.include || options.clone ) { - const values = Object.create(null); + let values = Object.create(null); + if (attributesWithGetters.size > 0) { for (const attributeName2 of attributesWithGetters) { if (!this._options.attributes?.includes(attributeName2)) { @@ -3262,6 +3263,18 @@ Instead of specifying a Model, either: } } + const keysOrder = Object.keys(rawAttributes); + + values = Object.fromEntries( + Object.entries(values) + .sort(([keyA], [keyB]) => { + const indexA = keysOrder.indexOf(keyA); + const indexB = keysOrder.indexOf(keyB); + + return indexA - indexB; + }), + ); + return values; } diff --git a/packages/core/test/integration/model/attributes/types.test.js b/packages/core/test/integration/model/attributes/types.test.js index fddd21c97fa3..f6ff83cd99c6 100644 --- a/packages/core/test/integration/model/attributes/types.test.js +++ b/packages/core/test/integration/model/attributes/types.test.js @@ -189,6 +189,18 @@ describe(Support.getTestDialectTeaser('Model'), () => { expect(user.field2).to.equal(42); }); + + it('should keep the order of virtual fields as declared in the model definition', async function () { + const user = this.User.build({ + field1: 'field1_value', + field2: 'field2_value', + }); + + const modelAttributes = Object.keys(this.User.modelDefinition.rawAttributes).join(','); + const resultAttributes = Object.keys(user.get()).join(','); + + expect(resultAttributes).to.equal(modelAttributes); + }); }); }); });