diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ccca609..c3f096d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -54,7 +54,7 @@ jobs: node: 18 - name: macOS machine: macos-latest - node: 14 + node: 16 - name: Windows machine: windows-latest node: 14 diff --git a/src/classes/polymorphic-serialiser.ts b/src/classes/polymorphic-serialiser.ts index 050539a..cf9f0be 100644 --- a/src/classes/polymorphic-serialiser.ts +++ b/src/classes/polymorphic-serialiser.ts @@ -66,6 +66,17 @@ export default class PolymorphicSerializer< return result; }, document); + // Sort data to match input order - this is important for cases where + // data has been sorted prior to serialization. + if (Array.isArray(document.data)) { + document.data = document.data.sort((a, b) => { + const aIndex = data.findIndex((datum) => datum.id === a.id); + const bIndex = data.findIndex((datum) => datum.id === b.id); + + return aIndex - bIndex; + }); + } + // Handle meta if (options?.metaizers?.document) { document.meta = options.metaizers.document.metaize(data); diff --git a/test/issue-92.test.ts b/test/issue-92.test.ts new file mode 100644 index 0000000..5a2ca14 --- /dev/null +++ b/test/issue-92.test.ts @@ -0,0 +1,68 @@ +import { PolymorphicSerializer, Serializer } from '../lib'; +import Resource from '../lib/models/resource.model'; + +describe('Issue #92 - Polymorphic serializer ordering', () => { + abstract class Model { + public type: string; + + constructor(public id: string) {} + } + + class Model1 extends Model { + constructor(id: string) { + super(id); + this.type = 'type:Model1'; + } + } + + class Model2 extends Model { + constructor(id: string) { + super(id); + this.type = 'type:Model2'; + } + } + + it('should maintain data input ordering', async () => { + const model1A: Model1 = new Model1('1a'); + const model1B: Model1 = new Model1('1b'); + const model1C: Model1 = new Model1('1c'); + const model2A: Model2 = new Model2('2a'); + const model2B: Model2 = new Model2('2b'); + + const Model1Serializer = new Serializer('Model1'); + const Model2Serializer = new Serializer('Model2'); + + const PolySerializer = new PolymorphicSerializer('Model', 'type', { + 'type:Model1': Model1Serializer, + 'type:Model2': Model2Serializer, + }); + + const data = (await PolySerializer.serialize([ + model1A, + model2A, + model1C, + model2B, + model1B, + ])) as { + data: Resource; + }; + + expect(data.data).toBeInstanceOf(Array); + expect(data.data).toHaveLength(5); + + expect(data.data[0].id).toEqual('1a'); + expect(data.data[0].type).toEqual('Model1'); + + expect(data.data[1].id).toEqual('2a'); + expect(data.data[1].type).toEqual('Model2'); + + expect(data.data[2].id).toEqual('1c'); + expect(data.data[2].type).toEqual('Model1'); + + expect(data.data[3].id).toEqual('2b'); + expect(data.data[3].type).toEqual('Model2'); + + expect(data.data[4].id).toEqual('1b'); + expect(data.data[4].type).toEqual('Model1'); + }); +});