Skip to content

Commit

Permalink
feat(): support class based refs
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilmysliwiec committed Jan 7, 2021
1 parent 9619024 commit 3725961
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 2 deletions.
22 changes: 22 additions & 0 deletions lib/factories/definitions.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export class DefinitionsFactory {
}
schemaMetadata.properties?.forEach((item) => {
const options = this.inspectTypeDefinition(item.options as any);
this.inspectRef(item.options as any);

schemaDefinition = {
[item.propertyKey]: options as any,
...schemaDefinition,
Expand All @@ -49,6 +51,10 @@ export class DefinitionsFactory {
} else if (this.isMongooseSchemaType(optionsOrType)) {
return optionsOrType;
}
const isClass = /^class\s/.test(
Function.prototype.toString.call(optionsOrType),
);
optionsOrType = isClass ? optionsOrType : optionsOrType();

const schemaDefinition = this.createForClass(
optionsOrType as Type<unknown>,
Expand Down Expand Up @@ -77,6 +83,22 @@ export class DefinitionsFactory {
return optionsOrType;
}

private static inspectRef(
optionsOrType: mongoose.SchemaTypeOptions<unknown> | Function,
) {
if (!optionsOrType || typeof optionsOrType !== 'object') {
return;
}
if (typeof optionsOrType?.ref === 'function') {
optionsOrType.ref =
(optionsOrType.ref as Function)()?.name ?? optionsOrType.ref;
} else if (Array.isArray(optionsOrType.type)) {
if (optionsOrType.type.length > 0) {
this.inspectRef(optionsOrType.type[0]);
}
}
}

private static isPrimitive(type: Function) {
return BUILT_IN_TYPES.includes(type);
}
Expand Down
52 changes: 50 additions & 2 deletions tests/e2e/schema-definitions.factory.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ import * as mongoose from 'mongoose';
import { DefinitionsFactory, Prop, raw, Schema } from '../../lib';
import { CannotDetermineTypeError } from '../../lib/errors';

@Schema()
class RefClass {
@Prop()
title: string;

@Prop({ type: mongoose.Schema.Types.ObjectId, ref: () => ExampleClass })
host;
}

@Schema()
class ChildClass {
@Prop()
Expand Down Expand Up @@ -45,8 +54,16 @@ class ExampleClass {
@Prop()
number: number;

@Prop({
type: [{ type: mongoose.Schema.Types.ObjectId, ref: () => RefClass }],
})
ref: RefClass[];

@Prop({ required: true })
children: ChildClass;
child: ChildClass;

@Prop({ type: () => ChildClass })
child2: ChildClass;

@Prop([ChildClass])
nodes: ChildClass[];
Expand All @@ -71,6 +88,14 @@ describe('DefinitionsFactory', () => {
objectId: {
type: mongoose.Schema.Types.ObjectId,
},
ref: {
type: [
{
ref: 'RefClass',
type: mongoose.Schema.Types.ObjectId,
},
],
},
name: {
required: true,
type: String,
Expand All @@ -87,7 +112,7 @@ describe('DefinitionsFactory', () => {
],
buffer: { type: mongoose.Schema.Types.Buffer },
decimal: { type: mongoose.Schema.Types.Decimal128 },
children: {
child: {
required: true,
type: {
id: {
Expand All @@ -98,6 +123,16 @@ describe('DefinitionsFactory', () => {
},
},
},
child2: {
type: {
id: {
type: Number,
},
name: {
type: String,
},
},
},
any: { type: mongoose.Schema.Types.Mixed },
array: { type: [] },
customArray: [{ custom: 'literal', object: true }],
Expand All @@ -117,6 +152,19 @@ describe('DefinitionsFactory', () => {
});
});

it('should generate a valid schema definition (class reference) for cyclic deps', () => {
const refClassDefinition = DefinitionsFactory.createForClass(RefClass);
expect(refClassDefinition).toEqual({
host: {
ref: 'ExampleClass',
type: mongoose.Schema.Types.ObjectId,
},
title: {
type: String,
},
});
});

it('should throw an error when type is ambiguous', () => {
try {
class AmbiguousField {
Expand Down

0 comments on commit 3725961

Please sign in to comment.