Skip to content

Commit

Permalink
fix(mongoose): fix schema when default value is used on collection
Browse files Browse the repository at this point in the history
Closes: #2968
  • Loading branch information
Romakita committed Jan 24, 2025
1 parent 96f4ffc commit 6e64fcc
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 26 deletions.
78 changes: 62 additions & 16 deletions packages/orm/mongoose/src/utils/createSchema.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,12 +464,10 @@ describe("createSchema", () => {

// THEN
expect(testSchema.obj).toEqual({
tests: [
{
type: childrenSchema,
required: false
}
]
tests: {
type: [childrenSchema],
required: false
}
});

expect(childrenSchema.obj).toEqual({
Expand Down Expand Up @@ -498,6 +496,54 @@ describe("createSchema", () => {
}
});
});
it("should create schema with collection (Array of subdocument and default value undefined)", () => {
// GIVEN
enum MyEnum {
V1 = "v1",
V2 = "v2"
}

@Schema()
class Children {
@Name("id")
_id: string;

@Enum(MyEnum)
@Default(undefined)
enum?: MyEnum[];
}

@Model()
class Test6 {
@CollectionOf(Children)
@Default(undefined)
tests?: Children[];
}

// WHEN
const testSchema = getSchema(Test6);
const childrenSchema = getSchema(Children);

// THEN
expect(testSchema.obj).toEqual({
tests: {
type: [childrenSchema],
required: false
}
});

expect(childrenSchema.obj).toEqual({
_id: {
required: false,
type: String
},
enum: {
enum: ["v1", "v2"],
required: false,
type: [String]
}
});
});
it("should create schema with collection (Array of ref)", () => {
// GIVEN
enum MyEnum {
Expand Down Expand Up @@ -535,13 +581,11 @@ describe("createSchema", () => {

// THEN
expect(testSchema.obj).toEqual({
tests: [
{
type: SchemaMongoose.Types.ObjectId,
ref: "Children3",
required: false
}
]
tests: {
type: [SchemaMongoose.Types.ObjectId],
ref: "Children3",
required: false
}
});
});
it("should create schema with collection (Array of virtual ref", () => {
Expand Down Expand Up @@ -631,9 +675,9 @@ describe("createSchema", () => {
tests: {
type: Map,
of: {
type: childrenSchema,
required: false
}
type: childrenSchema
},
required: false
}
});

Expand Down Expand Up @@ -728,6 +772,7 @@ describe("createSchema", () => {
@DiscriminatorKey()
kind: string;
}

const testSchema = getSchema(Test11);
// @ts-ignore
const options = testSchema.options;
Expand All @@ -740,6 +785,7 @@ describe("createSchema", () => {
@VersionKey()
version: number;
}

const testSchema = getSchema(Test12);
// @ts-ignore
const options = testSchema.options;
Expand Down
25 changes: 17 additions & 8 deletions packages/orm/mongoose/src/utils/createSchema.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {cleanObject, nameOf, Store, Type} from "@tsed/core";
import {classOf, cleanObject, isClassObject, nameOf, Store, Type} from "@tsed/core";
import {deserialize, serialize} from "@tsed/json-mapper";
import {getProperties, JsonEntityStore, JsonSchema} from "@tsed/schema";
import {pascalCase} from "change-case";
import mongoose, {Schema, SchemaDefinition, SchemaOptions, SchemaTypeOptions} from "mongoose";
import mongoose, {Schema, SchemaDefinition, SchemaDefinitionProperty, SchemaOptions, SchemaTypeOptions} from "mongoose";
import {MONGOOSE_SCHEMA, MONGOOSE_SCHEMA_OPTIONS} from "../constants/constants.js";
import {MongooseSchemaOptions} from "../interfaces/MongooseSchemaOptions.js";
import {MongooseVirtualRefOptions} from "../interfaces/MongooseVirtualRefOptions.js";
Expand Down Expand Up @@ -141,11 +141,11 @@ export function buildMongooseSchema(target: any): MongooseSchemaMetadata {
/**
* @ignore
*/
export function createSchemaTypeOptions<T = any>(propEntity: JsonEntityStore): SchemaTypeOptions<T> | SchemaTypeOptions<T>[] {
export function createSchemaTypeOptions(propEntity: JsonEntityStore): SchemaDefinitionProperty {
const key = propEntity.propertyKey;
const rawMongooseSchema = propEntity.store.get(MONGOOSE_SCHEMA) || {};

let schemaTypeOptions: SchemaTypeOptions<T> = {
let schemaTypeOptions: SchemaTypeOptions<any> = {
required: propEntity.required
? function () {
return propEntity.isRequired(this[key]);
Expand All @@ -164,13 +164,13 @@ export function createSchemaTypeOptions<T = any>(propEntity: JsonEntityStore): S

schemaTypeOptions = {
...schemaTypeOptions,
type: propEntity.type,
type: jsonSchema["enum"] && isClassObject(propEntity.type) ? classOf(jsonSchema["enum"][0]) : propEntity.type,
match: match as RegExp,
min,
max,
minlength,
maxlength,
enum: /*jsonSchema["enum"] instanceof JsonSchema ? jsonSchema["enum"].toJSON().enum :*/ jsonSchema["enum"],
enum: jsonSchema["enum"],
default: jsonSchema["default"]
};
} else if (!rawMongooseSchema.ref) {
Expand All @@ -182,15 +182,24 @@ export function createSchemaTypeOptions<T = any>(propEntity: JsonEntityStore): S

if (propEntity.isCollection) {
if (propEntity.isArray) {
return [schemaTypeOptions];
return {
...schemaTypeOptions,
type: [schemaTypeOptions.type]
};
}
// Can be a Map or a Set;
// Mongoose implements only Map;
if (propEntity.collectionType !== Map) {
throw new Error(`Invalid collection type. ${nameOf(propEntity.collectionType)} is not supported.`);
}

return {type: Map, of: schemaTypeOptions} as unknown as SchemaTypeOptions<T>;
const {default: defaultValue, required, ...otherOpts} = schemaTypeOptions;
return {
type: Map,
of: otherOpts,
default: defaultValue,
required
};
}

return schemaTypeOptions;
Expand Down
4 changes: 3 additions & 1 deletion packages/specs/schema/src/decorators/common/default.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type {JSONSchema6Type} from "json-schema";

import {JsonEntityFn} from "./jsonEntityFn.js";

/**
Expand Down Expand Up @@ -40,7 +42,7 @@ import {JsonEntityFn} from "./jsonEntityFn.js";
* @schema
* @input
*/
export function Default(defaultValue: string | number | boolean | {}) {
export function Default(defaultValue: JSONSchema6Type | undefined) {
return JsonEntityFn((store) => {
store.itemSchema.default(defaultValue);
});
Expand Down
2 changes: 1 addition & 1 deletion packages/specs/schema/src/domain/JsonSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ export class JsonSchema extends Map<string, any> implements NestedGenerics {
* It is RECOMMENDED that a default value be valid against the associated schema.
* @see https://tools.ietf.org/html/draft-wright-json-schema-validation-01#section-7.3
*/
default(value: JSONSchema6Type) {
default(value: JSONSchema6Type | undefined) {
super.set("default", value);

return this;
Expand Down

0 comments on commit 6e64fcc

Please sign in to comment.