From 78eced340452940cd464bcd8ac2ebb41fd23001f Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Mon, 29 Aug 2022 12:03:31 +0200 Subject: [PATCH] fix(json-mapper): fix issue with ReadOnly decorator --- .../orm/mongoose/src/utils/createSchema.ts | 4 +-- .../test/readonly.integration.spec.ts | 4 ++- .../json-mapper/src/utils/deserialize.ts | 2 +- .../schema/src/domain/JsonEntityStore.spec.ts | 32 +++++++++++++++++++ .../schema/src/domain/JsonEntityStore.ts | 5 ++- 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/packages/orm/mongoose/src/utils/createSchema.ts b/packages/orm/mongoose/src/utils/createSchema.ts index da9f0c515bd..b0436846c47 100644 --- a/packages/orm/mongoose/src/utils/createSchema.ts +++ b/packages/orm/mongoose/src/utils/createSchema.ts @@ -116,10 +116,10 @@ export function buildMongooseSchema(target: any): MongooseSchemaMetadata { return; } - // Keeping the Mongoose Schema separate so it can overwrite everything once schema has been built. + // Keeping the Mongoose Schema separate, so it can overwrite everything once schema has been built. const schemaTypeOptions: any = propertyMetadata.store.get(MONGOOSE_SCHEMA) || {}; - if (schemaTypeOptions.schemaIgnore || propertyMetadata.schema.isReadOnly) { + if (schemaTypeOptions.schemaIgnore || propertyMetadata.isGetterOnly()) { return; } diff --git a/packages/orm/mongoose/test/readonly.integration.spec.ts b/packages/orm/mongoose/test/readonly.integration.spec.ts index 02e09cd8f06..6eff394e0ab 100644 --- a/packages/orm/mongoose/test/readonly.integration.spec.ts +++ b/packages/orm/mongoose/test/readonly.integration.spec.ts @@ -1,7 +1,7 @@ import {Inject, Injectable, PlatformTest} from "@tsed/common"; import {getJsonSchema, Groups, Name, Property, ReadOnly, Required} from "@tsed/schema"; import {TestMongooseContext} from "@tsed/testing-mongoose"; -import {Immutable, Model, MongooseModel, ObjectID} from "../src/index"; +import {Immutable, Model, MongooseModel, ObjectID, SchemaIgnore} from "../src/index"; class BaseModel { @ObjectID("id") @@ -12,12 +12,14 @@ class BaseModel { @Required() @Immutable() @ReadOnly() + @SchemaIgnore() @Name("created_at") @Groups("!create", "!update") createdAt: number = Date.now(); @Required() @ReadOnly() + @SchemaIgnore() @Name("updated_at") @Groups("!create", "!update") updatedAt: number = Date.now(); diff --git a/packages/specs/json-mapper/src/utils/deserialize.ts b/packages/specs/json-mapper/src/utils/deserialize.ts index 35f5d2c9146..28c651fe291 100644 --- a/packages/specs/json-mapper/src/utils/deserialize.ts +++ b/packages/specs/json-mapper/src/utils/deserialize.ts @@ -161,7 +161,7 @@ export function plainObjectToClass(src: any, options: JsonDeserializerO collectionType: propStore.collectionType }); - if (!propStore.schema.isReadOnly) { + if (!propStore.isGetterOnly()) { if (value !== undefined) { out[propStore.propertyName] = value; } else if (options.partial) { diff --git a/packages/specs/schema/src/domain/JsonEntityStore.spec.ts b/packages/specs/schema/src/domain/JsonEntityStore.spec.ts index 3b6e2f2e635..0c534aabc6f 100644 --- a/packages/specs/schema/src/domain/JsonEntityStore.spec.ts +++ b/packages/specs/schema/src/domain/JsonEntityStore.spec.ts @@ -53,6 +53,7 @@ describe("JsonEntityStore", () => { expect(storeProp.isPrimitive).toBe(true); expect(storeProp.isObject).toBe(false); expect(storeProp.isClass).toBe(false); + expect(storeProp.isGetterOnly()).toBeFalsy(); // METHOD const storeMethod = JsonEntityStore.from(Model).children.get("method") as JsonMethodStore; @@ -92,6 +93,7 @@ describe("JsonEntityStore", () => { expect(storeParam.isPrimitive).toBe(true); expect(storeParam.isObject).toBe(false); expect(storeParam.isClass).toBe(false); + expect(storeParam.isGetterOnly()).toBe(false); }); it("should manage enum from babel", () => { enum MyEnum { @@ -110,4 +112,34 @@ describe("JsonEntityStore", () => { expect(store.type).toEqual(String); }); + + describe("isGetterOnly()", () => { + it("should create JsonEntityStore on getter", () => { + class Model { + @Property() + get id() { + return "id"; + } + } + + // CLASS + // PROPERTY + const storeProp = JsonEntityStore.from(Model).children.get("id") as JsonPropertyStore; + expect(storeProp.isGetterOnly()).toBeTruthy(); + }); + it("should create JsonEntityStore on getter/setter", () => { + class Model { + @Property() + get id() { + return "id"; + } + set id(id: string) {} + } + + // CLASS + // PROPERTY + const storeProp = JsonEntityStore.from(Model).children.get("id") as JsonPropertyStore; + expect(storeProp.isGetterOnly()).toBeFalsy(); + }); + }); }); diff --git a/packages/specs/schema/src/domain/JsonEntityStore.ts b/packages/specs/schema/src/domain/JsonEntityStore.ts index d78c4302dd7..da139bb8c47 100644 --- a/packages/specs/schema/src/domain/JsonEntityStore.ts +++ b/packages/specs/schema/src/domain/JsonEntityStore.ts @@ -57,7 +57,7 @@ export abstract class JsonEntityStore implements JsonEntityStoreOptions { /** * Method's descriptor */ - readonly descriptor: number; + readonly descriptor: PropertyDescriptor; /** * Decorator type used to declare the JsonSchemaStore. */ @@ -95,6 +95,9 @@ export abstract class JsonEntityStore implements JsonEntityStoreOptions { this.parent = this; } + isGetterOnly() { + return isObject(this.descriptor) && !this.descriptor.value && this.descriptor.get && !this.descriptor.set; + } /** * Return the class name of the entity. * @returns {string}