Skip to content

Commit

Permalink
fix(json-mapper): fix issue with ReadOnly decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
Romakita committed Aug 29, 2022
1 parent dae7721 commit b36b23c
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 11 deletions.
6 changes: 3 additions & 3 deletions packages/di/coverage.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"statements": 99,
"branches": 93.12,
"lines": 99.1,
"functions": 98.46
"branches": 93.3,
"functions": 98.49,
"lines": 99.1
}
2 changes: 1 addition & 1 deletion packages/di/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@
"optional": false
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`@Inject() used on property should catch error when an object is given as token provider 1`] = `
exports[`@Inject() @property should catch error when an object is given as token provider 1`] = `
"Object isn't a valid token. Please check the token set on Test.test.
- Check that it is not a circular reference.
- Check that the token (class or symbol) exists"
Expand Down
17 changes: 16 additions & 1 deletion packages/di/src/decorators/inject.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {descriptorOf} from "@tsed/core";
import {catchError, descriptorOf} from "@tsed/core";
import {Required} from "@tsed/schema";
import {Inject, Injectable, InjectorService, registerProvider} from "../../src";

describe("@Inject()", () => {
Expand Down Expand Up @@ -107,6 +108,20 @@ describe("@Inject()", () => {
expect(instance.instances[1].type).toEqual("service2");
expect(instance.instances[2].type).toEqual("async");
});
it("should catch error when an object is given as token provider", async () => {
// GIVEN
@Injectable()
class Test {
@Required()
test: Object;
}

const error = catchError(() => {
Inject()(Test.prototype, "test");
});

expect(error?.message).toMatchSnapshot();
});
});

describe("@constructorParameters", () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/orm/mongoose/src/utils/createSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
4 changes: 3 additions & 1 deletion packages/orm/mongoose/test/readonly.integration.spec.ts
Original file line number Diff line number Diff line change
@@ -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")
Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion packages/specs/json-mapper/src/utils/deserialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export function plainObjectToClass<T = any>(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) {
Expand Down
32 changes: 32 additions & 0 deletions packages/specs/schema/src/domain/JsonEntityStore.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,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;
Expand Down Expand Up @@ -94,6 +95,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 {
Expand All @@ -113,6 +115,36 @@ 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();
});
});

describe("required() and allowRequiredValues", () => {
it("should return the required value", () => {
class Test {
Expand Down
5 changes: 4 additions & 1 deletion packages/specs/schema/src/domain/JsonEntityStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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}
Expand Down

0 comments on commit b36b23c

Please sign in to comment.