Skip to content

Commit 6e64fcc

Browse files
committed
fix(mongoose): fix schema when default value is used on collection
Closes: #2968
1 parent 96f4ffc commit 6e64fcc

File tree

4 files changed

+83
-26
lines changed

4 files changed

+83
-26
lines changed

Diff for: packages/orm/mongoose/src/utils/createSchema.spec.ts

+62-16
Original file line numberDiff line numberDiff line change
@@ -464,12 +464,10 @@ describe("createSchema", () => {
464464

465465
// THEN
466466
expect(testSchema.obj).toEqual({
467-
tests: [
468-
{
469-
type: childrenSchema,
470-
required: false
471-
}
472-
]
467+
tests: {
468+
type: [childrenSchema],
469+
required: false
470+
}
473471
});
474472

475473
expect(childrenSchema.obj).toEqual({
@@ -498,6 +496,54 @@ describe("createSchema", () => {
498496
}
499497
});
500498
});
499+
it("should create schema with collection (Array of subdocument and default value undefined)", () => {
500+
// GIVEN
501+
enum MyEnum {
502+
V1 = "v1",
503+
V2 = "v2"
504+
}
505+
506+
@Schema()
507+
class Children {
508+
@Name("id")
509+
_id: string;
510+
511+
@Enum(MyEnum)
512+
@Default(undefined)
513+
enum?: MyEnum[];
514+
}
515+
516+
@Model()
517+
class Test6 {
518+
@CollectionOf(Children)
519+
@Default(undefined)
520+
tests?: Children[];
521+
}
522+
523+
// WHEN
524+
const testSchema = getSchema(Test6);
525+
const childrenSchema = getSchema(Children);
526+
527+
// THEN
528+
expect(testSchema.obj).toEqual({
529+
tests: {
530+
type: [childrenSchema],
531+
required: false
532+
}
533+
});
534+
535+
expect(childrenSchema.obj).toEqual({
536+
_id: {
537+
required: false,
538+
type: String
539+
},
540+
enum: {
541+
enum: ["v1", "v2"],
542+
required: false,
543+
type: [String]
544+
}
545+
});
546+
});
501547
it("should create schema with collection (Array of ref)", () => {
502548
// GIVEN
503549
enum MyEnum {
@@ -535,13 +581,11 @@ describe("createSchema", () => {
535581

536582
// THEN
537583
expect(testSchema.obj).toEqual({
538-
tests: [
539-
{
540-
type: SchemaMongoose.Types.ObjectId,
541-
ref: "Children3",
542-
required: false
543-
}
544-
]
584+
tests: {
585+
type: [SchemaMongoose.Types.ObjectId],
586+
ref: "Children3",
587+
required: false
588+
}
545589
});
546590
});
547591
it("should create schema with collection (Array of virtual ref", () => {
@@ -631,9 +675,9 @@ describe("createSchema", () => {
631675
tests: {
632676
type: Map,
633677
of: {
634-
type: childrenSchema,
635-
required: false
636-
}
678+
type: childrenSchema
679+
},
680+
required: false
637681
}
638682
});
639683

@@ -728,6 +772,7 @@ describe("createSchema", () => {
728772
@DiscriminatorKey()
729773
kind: string;
730774
}
775+
731776
const testSchema = getSchema(Test11);
732777
// @ts-ignore
733778
const options = testSchema.options;
@@ -740,6 +785,7 @@ describe("createSchema", () => {
740785
@VersionKey()
741786
version: number;
742787
}
788+
743789
const testSchema = getSchema(Test12);
744790
// @ts-ignore
745791
const options = testSchema.options;

Diff for: packages/orm/mongoose/src/utils/createSchema.ts

+17-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import {cleanObject, nameOf, Store, Type} from "@tsed/core";
1+
import {classOf, cleanObject, isClassObject, nameOf, Store, Type} from "@tsed/core";
22
import {deserialize, serialize} from "@tsed/json-mapper";
33
import {getProperties, JsonEntityStore, JsonSchema} from "@tsed/schema";
44
import {pascalCase} from "change-case";
5-
import mongoose, {Schema, SchemaDefinition, SchemaOptions, SchemaTypeOptions} from "mongoose";
5+
import mongoose, {Schema, SchemaDefinition, SchemaDefinitionProperty, SchemaOptions, SchemaTypeOptions} from "mongoose";
66
import {MONGOOSE_SCHEMA, MONGOOSE_SCHEMA_OPTIONS} from "../constants/constants.js";
77
import {MongooseSchemaOptions} from "../interfaces/MongooseSchemaOptions.js";
88
import {MongooseVirtualRefOptions} from "../interfaces/MongooseVirtualRefOptions.js";
@@ -141,11 +141,11 @@ export function buildMongooseSchema(target: any): MongooseSchemaMetadata {
141141
/**
142142
* @ignore
143143
*/
144-
export function createSchemaTypeOptions<T = any>(propEntity: JsonEntityStore): SchemaTypeOptions<T> | SchemaTypeOptions<T>[] {
144+
export function createSchemaTypeOptions(propEntity: JsonEntityStore): SchemaDefinitionProperty {
145145
const key = propEntity.propertyKey;
146146
const rawMongooseSchema = propEntity.store.get(MONGOOSE_SCHEMA) || {};
147147

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

165165
schemaTypeOptions = {
166166
...schemaTypeOptions,
167-
type: propEntity.type,
167+
type: jsonSchema["enum"] && isClassObject(propEntity.type) ? classOf(jsonSchema["enum"][0]) : propEntity.type,
168168
match: match as RegExp,
169169
min,
170170
max,
171171
minlength,
172172
maxlength,
173-
enum: /*jsonSchema["enum"] instanceof JsonSchema ? jsonSchema["enum"].toJSON().enum :*/ jsonSchema["enum"],
173+
enum: jsonSchema["enum"],
174174
default: jsonSchema["default"]
175175
};
176176
} else if (!rawMongooseSchema.ref) {
@@ -182,15 +182,24 @@ export function createSchemaTypeOptions<T = any>(propEntity: JsonEntityStore): S
182182

183183
if (propEntity.isCollection) {
184184
if (propEntity.isArray) {
185-
return [schemaTypeOptions];
185+
return {
186+
...schemaTypeOptions,
187+
type: [schemaTypeOptions.type]
188+
};
186189
}
187190
// Can be a Map or a Set;
188191
// Mongoose implements only Map;
189192
if (propEntity.collectionType !== Map) {
190193
throw new Error(`Invalid collection type. ${nameOf(propEntity.collectionType)} is not supported.`);
191194
}
192195

193-
return {type: Map, of: schemaTypeOptions} as unknown as SchemaTypeOptions<T>;
196+
const {default: defaultValue, required, ...otherOpts} = schemaTypeOptions;
197+
return {
198+
type: Map,
199+
of: otherOpts,
200+
default: defaultValue,
201+
required
202+
};
194203
}
195204

196205
return schemaTypeOptions;

Diff for: packages/specs/schema/src/decorators/common/default.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type {JSONSchema6Type} from "json-schema";
2+
13
import {JsonEntityFn} from "./jsonEntityFn.js";
24

35
/**
@@ -40,7 +42,7 @@ import {JsonEntityFn} from "./jsonEntityFn.js";
4042
* @schema
4143
* @input
4244
*/
43-
export function Default(defaultValue: string | number | boolean | {}) {
45+
export function Default(defaultValue: JSONSchema6Type | undefined) {
4446
return JsonEntityFn((store) => {
4547
store.itemSchema.default(defaultValue);
4648
});

Diff for: packages/specs/schema/src/domain/JsonSchema.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ export class JsonSchema extends Map<string, any> implements NestedGenerics {
270270
* It is RECOMMENDED that a default value be valid against the associated schema.
271271
* @see https://tools.ietf.org/html/draft-wright-json-schema-validation-01#section-7.3
272272
*/
273-
default(value: JSONSchema6Type) {
273+
default(value: JSONSchema6Type | undefined) {
274274
super.set("default", value);
275275

276276
return this;

0 commit comments

Comments
 (0)