Skip to content

Commit

Permalink
fix(json-schema): fix mongoose usecases
Browse files Browse the repository at this point in the history
  • Loading branch information
Romakita committed Aug 20, 2023
1 parent e3768c0 commit dda69c8
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 27 deletions.
6 changes: 5 additions & 1 deletion packages/core/src/utils/objects/isMongooseObject.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import {hasJsonMethod} from "./hasJsonMethod";

export function isObjectID(obj: any) {
return obj && obj._bsontype;
}

export function isMongooseObject(obj: any) {
return !!((hasJsonMethod(obj) && obj.$isMongooseModelPrototype) || (obj && obj._bsontype));
return !!((hasJsonMethod(obj) && obj.$isMongooseModelPrototype) || isObjectID(obj));
}
2 changes: 1 addition & 1 deletion packages/orm/mongoose/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = {
coverageThreshold: {
global: {
statements: 99.06,
branches: 95.43,
branches: 95.4,
functions: 99,
lines: 99.06
}
Expand Down
4 changes: 2 additions & 2 deletions packages/orm/mongoose/src/decorators/ref.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {isArrowFn, isObject, isString, StoreMerge, Type, useDecorators} from "@tsed/core";
import {isArrowFn, isObject, isObjectID, isString, StoreMerge, Type, useDecorators} from "@tsed/core";
import {OnDeserialize, OnSerialize, serialize, deserialize} from "@tsed/json-mapper";
import {ForwardGroups, JsonEntityFn, lazyRef, matchGroups, OneOf, Property, string} from "@tsed/schema";
import {Schema as MongooseSchema} from "mongoose";
Expand All @@ -12,7 +12,7 @@ interface RefOptions {
}

function isRef(value: undefined | string | any) {
return (value && value._bsontype) || isString(value);
return isObjectID(value) || isString(value);
}

function PopulateGroups(populatedGroups: string[]) {
Expand Down
4 changes: 3 additions & 1 deletion packages/orm/mongoose/test/ref.integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ class ProfilesCtrl {
}

@Get("/")
getTest(@QueryParams("full") full: boolean) {
async getTest(@QueryParams("full") full: boolean) {
const result = await this.ProfileModel.find();
console.log(result);
return full ? this.ProfileModel.find().populate("user") : this.ProfileModel.find();
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/specs/json-mapper/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ module.exports = {
roots: ["<rootDir>/src", "<rootDir>/test"],
coverageThreshold: {
global: {
statements: 99.78,
branches: 98.16,
statements: 99.57,
branches: 97.89,
functions: 100,
lines: 99.78
lines: 99.57
}
},
moduleNameMapper: {
Expand Down
5 changes: 5 additions & 0 deletions packages/specs/json-mapper/src/domain/JsonMapperCompiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
isMongooseObject,
isNil,
isObject,
isObjectID,
nameOf,
objectKeys,
Type
Expand Down Expand Up @@ -165,6 +166,10 @@ export abstract class JsonMapperCompiler<Options extends Record<string, any> = a
}

protected execMapper(id: string, value: any, options: Options) {
if (isObjectID(value)) {
return value.toString();
}

return this.mappers[id](value, options);
}

Expand Down
87 changes: 86 additions & 1 deletion packages/specs/json-mapper/src/domain/JsonSerializer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import {isBoolean} from "@tsed/core";
import {Unique} from "@faker-js/faker/unique";
import {isBoolean, isObjectID} from "@tsed/core";
import {
AdditionalProperties,
CollectionOf,
DiscriminatorKey,
DiscriminatorValue,
Groups,
Ignore,
JsonHookContext,
MinLength,
Name,
Nullable,
Property,
Expand All @@ -30,6 +33,16 @@ function createMap(value: any) {
return new Map([["test", value]]);
}

class ObjectId {
_bsontype = true;

constructor(public id: string) {}

toString() {
return this.id;
}
}

describe("JsonSerializer", () => {
describe("Primitives", () => {
it("should serialize values", () => {
Expand Down Expand Up @@ -593,6 +606,7 @@ describe("JsonSerializer", () => {
@Property()
id: string;
}

class NullModel {
@Property()
prop1: string;
Expand Down Expand Up @@ -734,6 +748,77 @@ describe("JsonSerializer", () => {
}
]);
});
it("should serialize model with nested model and not populated data (mongoose)", () => {
class Workspace {
@Property()
_id: string;

@Property()
name: string;
}

class MyWorkspace {
@Property()
workspaceId: Workspace;

@Property()
title: string;
}

class UserWorkspace {
@Property()
_id: string;

@CollectionOf(MyWorkspace)
workspaces: MyWorkspace[];
}

const userWorkspace = new UserWorkspace();
userWorkspace._id = new ObjectId("64e061ba7356daf00a66c130") as unknown as string;
userWorkspace.workspaces = [new MyWorkspace()];
userWorkspace.workspaces[0].title = "MyTest";
userWorkspace.workspaces[0].workspaceId = new ObjectId("64e061ba7356daf00a66c130") as unknown as Workspace;

expect(serialize(userWorkspace, {type: UserWorkspace})).toEqual({
_id: "64e061ba7356daf00a66c130",
workspaces: [
{
title: "MyTest",
workspaceId: "64e061ba7356daf00a66c130"
}
]
});
});
it("should serialize model with nested model and not populated data (Ref mongoose)", () => {
class TestUser {
@Required()
email: string;

@Required()
@MinLength(6)
@Groups("creation")
password: string;
}
class TestProfile {
@OnSerialize((value, ctx) => {
if (isObjectID(value)) {
return value.toString();
}

return serialize(value, {...ctx, type: TestUser});
})
user: any;
}

const profile = new TestProfile();
profile.user = new ObjectId("64e061ba7356daf00a66c130");

expect(serialize([profile])).toEqual([
{
user: "64e061ba7356daf00a66c130"
}
]);
});
it("should serialize model (inherited class)", () => {
class Role {
@Property()
Expand Down
7 changes: 7 additions & 0 deletions packages/specs/json-mapper/src/domain/JsonSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
isMongooseObject,
isNil,
isObject,
isPrimitive,
nameOf,
Type
} from "@tsed/core";
Expand Down Expand Up @@ -38,6 +39,7 @@ export class JsonSerializer extends JsonMapperCompiler<JsonSerializerOptions> {
this.addTypeMapper(Map, this.mapMap.bind(this));
this.addTypeMapper(Set, this.mapSet.bind(this));
this.addGlobal("mapJSON", this.mapJSON.bind(this));
this.addTypeMapper("ObjectId", (value: any) => String(value));
}

map(input: any, options: JsonSerializerOptions = {}) {
Expand Down Expand Up @@ -212,6 +214,11 @@ export class JsonSerializer extends JsonMapperCompiler<JsonSerializerOptions> {
}

private mapObject(input: any, {type, ...options}: JsonSerializerOptions) {
if (input && isPrimitive(input)) {
// prevent mongoose mapping error
return input;
}

if (input && isCollection(input)) {
return this.execMapper(nameOf(classOf(input)), input, options);
}
Expand Down
18 changes: 0 additions & 18 deletions packages/specs/json-mapper/src/tsconfig.json

This file was deleted.

0 comments on commit dda69c8

Please sign in to comment.