diff --git a/packages/specs/json-mapper/src/domain/JsonSerializer.ts b/packages/specs/json-mapper/src/domain/JsonSerializer.ts index cecbf97c076..8dec7883d00 100644 --- a/packages/specs/json-mapper/src/domain/JsonSerializer.ts +++ b/packages/specs/json-mapper/src/domain/JsonSerializer.ts @@ -180,15 +180,21 @@ export class JsonSerializer extends JsonMapperCompiler { } private getPropertyFiller(propertyStore: JsonPropertyStore, key: string, groups: false | string[], formatOpts: any) { + const isGeneric = propertyStore.itemSchema.isGeneric; + if (propertyStore.isCollection) { const type = propertyStore.getBestType(); - const nestedMapper = this.compile(type, groups); + const nestedMapper = isGeneric ? {id: ""} : this.compile(type, groups); return (writer: Writer) => writer.callMapper(nameOf(propertyStore.collectionType), varKey(key), `id: '${nestedMapper.id}'`, formatOpts); } + if (isGeneric) { + return (writer: Writer) => writer.set(varKey(key), `compileAndMap(${varKey(key)}, options)`); + } + const type = propertyStore.getBestType(); const nestedMapper = this.compile(type, groups); diff --git a/packages/specs/json-mapper/test/integration/generics.integration.spec.ts b/packages/specs/json-mapper/test/integration/generics.integration.spec.ts index 5585dfecc44..aa922b2d559 100644 --- a/packages/specs/json-mapper/test/integration/generics.integration.spec.ts +++ b/packages/specs/json-mapper/test/integration/generics.integration.spec.ts @@ -1,5 +1,21 @@ -import {boolean, date, GenericOf, Generics, number, Property, string} from "@tsed/schema"; +import {Controller} from "@tsed/di"; +import { + boolean, + CollectionOf, + date, + GenericOf, + Generics, + Get, + Ignore, + JsonEntityStore, + number, + Property, + Required, + Returns, + string +} from "@tsed/schema"; import {deserialize} from "../../src/utils/deserialize"; +import {serialize} from "../../src/utils/serialize"; describe("Generics", () => { describe("using Functional api", () => { @@ -268,4 +284,133 @@ describe("Generics", () => { }); }); }); + + describe("Pagination", () => { + it("should serialize correctly the return object from controller (generic array)", () => { + @Generics("T") + class Pagination { + @CollectionOf("T") + @Required() + items: T[]; + + @Required() + totalCount: number; + + constructor(partial: Partial>) { + Object.assign(this, partial); + } + } + + class TestEntity { + @Property("id") + public _id: string; + + @Property() + name: string; + + @Property() + @Ignore() + secret: string; + } + + @Controller("/hello-world") + class HelloWorldController { + constructor() {} + + @Get("/") + @Returns(200, Pagination).Of(TestEntity) + get() {} + } + + const endpoint = JsonEntityStore.fromMethod(HelloWorldController, "get"); + + const responseOpts = endpoint.getResponseOptions(200, {}); + + const item = new TestEntity(); + item._id = "64f05e452ecc156cff3b58f4"; + item.name = "Test"; + item.secret = "top"; + + const paginated = new Pagination({items: [item], totalCount: 1}); + + const result = serialize(paginated, { + useAlias: true, + additionalProperties: false, + ...responseOpts, + endpoint: true + }); + + expect(result).toEqual({ + items: [ + { + _id: "64f05e452ecc156cff3b58f4", + name: "Test" + } + ], + totalCount: 1 + }); + }); + it("should serialize correctly the return object from controller (generic item)", () => { + @Generics("T") + class Pagination { + @Property("T") + @Required() + item: T; + + @Required() + totalCount: number; + + constructor(partial: Partial>) { + Object.assign(this, partial); + } + } + + class TestEntity { + @Property("id") + public _id: string; + + @Property() + name: string; + + @Property() + @Ignore() + secret: string; + } + + @Controller("/hello-world") + class HelloWorldController { + constructor() {} + + @Get("/") + @Returns(200, Pagination).Of(TestEntity) + get() {} + } + + const endpoint = JsonEntityStore.fromMethod(HelloWorldController, "get"); + + const responseOpts = endpoint.getResponseOptions(200, {}); + + const item = new TestEntity(); + item._id = "64f05e452ecc156cff3b58f4"; + item.name = "Test"; + item.secret = "top"; + + const paginated = new Pagination({item: item, totalCount: 1}); + + const result = serialize(paginated, { + useAlias: true, + additionalProperties: false, + ...responseOpts, + endpoint: true + }); + + expect(result).toEqual({ + item: { + _id: "64f05e452ecc156cff3b58f4", + name: "Test" + }, + totalCount: 1 + }); + }); + }); });