From 35a9681e41912d263ddeb5b719cb834c135ce543 Mon Sep 17 00:00:00 2001 From: Stefan Bieliauskas Date: Tue, 24 Sep 2019 16:42:14 +0200 Subject: [PATCH] Add Inheritance Tests - add more inheritance tests - add support for custom discriminator properties - add ".idea" to gitignore - prop: add support for extended array items this is a squash merge of typegoose/typegoose#21 --- .gitignore | 1 + src/prop.ts | 8 +++--- src/typegoose.ts | 7 +++++- test/index.test.ts | 3 +++ test/models/discriminators.ts | 8 ++++++ test/models/inheritanceClass.ts | 41 +++++++++++++++++++++++++++++++ test/tests/inheritance.test.ts | 43 +++++++++++++++++++++++++++++++++ test/tests/shouldRun.test.ts | 6 ++--- 8 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 test/models/inheritanceClass.ts create mode 100644 test/tests/inheritance.test.ts diff --git a/.gitignore b/.gitignore index 9edc8803..85c2adbe 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ crashlytics.properties crashlytics-build.properties fabric.properties +.idea ### Linux ### *~ diff --git a/src/prop.ts b/src/prop.ts index 74ecb9a5..a0d81d49 100644 --- a/src/prop.ts +++ b/src/prop.ts @@ -245,13 +245,13 @@ function baseProp( switch (whatis) { case WhatIsIt.ARRAY: + const virtualSchemaArrayItem = buildSchema(Type, { + _id: typeof rawOptions._id === 'boolean' ? rawOptions._id : true + }); schemas.get(name)[key] = { ...schemas.get(name)[key][0], // [0] is needed, because "initasArray" adds this (empty) ...options, - type: [{ - ...(typeof options._id === 'boolean' ? { _id: options._id } : {}), - ...subSchema - }] + type: [virtualSchemaArrayItem] }; return; diff --git a/src/typegoose.ts b/src/typegoose.ts index eece1c82..681f104e 100644 --- a/src/typegoose.ts +++ b/src/typegoose.ts @@ -199,8 +199,13 @@ export function getDiscriminatorModelForClass; } + const sch = buildSchema(cl) as mongoose.Schema & {paths: object}; + + const discriminatorKey = sch.get('discriminatorKey'); + if (sch.path(discriminatorKey)) { + sch.paths[discriminatorKey].options.$skipDiscriminatorCheck = true; + } - const sch = buildSchema(cl); const model = from.discriminator(name, sch, id ? id : name); return addModelToTypegoose(model, cl); diff --git a/test/index.test.ts b/test/index.test.ts index 7ccd56d7..d564d412 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -13,6 +13,7 @@ import { suite as ShouldAddTest } from './tests/shouldAdd.test'; import { suite as ShouldRunTests } from './tests/shouldRun.test'; import { suite as StringValidatorTests } from './tests/stringValidator.test'; import { suite as TypeguardsTest } from './tests/typeguards.test'; +import { suite as Inheritance } from './tests/inheritance.test'; import { connect, disconnect } from './utils/mongooseConnect'; @@ -44,5 +45,7 @@ describe('Typegoose', () => { describe('Ref tests', RefTest.bind(this)); + describe('inheritance', Inheritance.bind(this)); + describe('customName', customNameTests.bind(this)); }); diff --git a/test/models/discriminators.ts b/test/models/discriminators.ts index 0081b9fd..e35efe8d 100644 --- a/test/models/discriminators.ts +++ b/test/models/discriminators.ts @@ -3,11 +3,19 @@ import { getDiscriminatorModelForClass, getModelForClass, prop } from '../../src export class DisMain { @prop({ required: true, default: 'hello main1' }) public main1: string; + + @prop({ default: undefined }) + // tslint:disable-next-line:variable-name + public __t: string; } export class DisAbove extends DisMain { @prop({ required: true, default: 'hello above1' }) public above1: string; + + @prop({ default: 'DisAbove' }) + // tslint:disable-next-line:variable-name + public __t: string; } export const DisMainModel = getModelForClass(DisMain); diff --git a/test/models/inheritanceClass.ts b/test/models/inheritanceClass.ts new file mode 100644 index 00000000..15078a84 --- /dev/null +++ b/test/models/inheritanceClass.ts @@ -0,0 +1,41 @@ +import { arrayProp, prop } from '../../src/prop'; +import { getModelForClass, modelOptions } from '../../src/typegoose'; + +@modelOptions({ + schemaOptions: { + discriminatorKey: 'width', + collection: 'buildings' + } +}) +export class Building { + @prop({default: 100}) + public width: number; +} + +export class OfficeBuilding extends Building { + @prop({default: 4}) + public doors: number; +} + +export class Garage extends Building { + @prop({default: 10}) + public slotsForCars: number; +} + +@modelOptions({ + schemaOptions: { + collection: 'skyscrapers' + } +}) +export class Skyscraper extends OfficeBuilding { + @prop({default: 'Some cool string'}) + public name: string; + + @prop() + public mainGarage: Garage; + + @arrayProp({items: Garage}) + public garagesInArea: Garage[]; +} + +export const model = getModelForClass(Skyscraper); diff --git a/test/tests/inheritance.test.ts b/test/tests/inheritance.test.ts new file mode 100644 index 00000000..b259bd09 --- /dev/null +++ b/test/tests/inheritance.test.ts @@ -0,0 +1,43 @@ +import { expect } from 'chai'; +import { model as inheritanceClass, Skyscraper } from '../models/inheritanceClass'; + +export function suite() { + it('should set all direct parent props', async () => { + const instance = await inheritanceClass.create({}); + expect(instance.name).to.equals('Some cool string'); + expect(instance.doors).to.equals(4); + expect(instance.width).to.equals(100); + }); + + it('should merge all parent schema options', async () => { + const instance = await inheritanceClass.create({}); + expect(instance.schema.get('collection')).to.equals('skyscrapers'); + expect(instance.schema.get('discriminatorKey')).to.equals('width'); + }); + + it('should set all parent props for nested schemas', async () => { + const input = { + mainGarage: { + slotsForCars: 3 + } + } as Skyscraper; + const instance = await inheritanceClass.create(input); + expect(instance.mainGarage.slotsForCars).to.equals(3); + expect(instance.mainGarage.width).to.equals(100); + expect(instance.mainGarage.doors).to.equals(undefined); + }); + + it('should set all parent props for nested array items', async () => { + const input = { + garagesInArea: [{ + slotsForCars: 2 + }] + } as Skyscraper; + const instance = await inheritanceClass.create(input); + expect(instance.garagesInArea).to.be.lengthOf(1); + const firstGarage = instance.garagesInArea.pop(); + expect(firstGarage.slotsForCars).to.equals(2); + expect(firstGarage.width).to.equals(100); + expect(firstGarage.doors).to.be.equals(undefined); + }); +} diff --git a/test/tests/shouldRun.test.ts b/test/tests/shouldRun.test.ts index 129eb95d..b01381e7 100644 --- a/test/tests/shouldRun.test.ts +++ b/test/tests/shouldRun.test.ts @@ -59,14 +59,12 @@ export function suite() { expect(dmmdoc).to.not.be.an('undefined'); expect(dmmdoc.main1).to.equals('hello DMM'); expect(dmmdoc).to.not.have.property('above1'); - // any is required otherwise typescript complains about "__t" not existing - expect((dmmdoc as any).__t).to.be.an('undefined'); + expect(dmmdoc.__t).to.be.an('undefined'); expect(damdoc).to.not.be.an('undefined'); expect(damdoc.main1).to.equals('hello DAM'); expect(damdoc.above1).to.equals('hello DAM'); - // any is required otherwise typescript complains about "__t" not existing - expect((damdoc as any).__t).to.equals('DisAbove'); + expect(damdoc.__t).to.equals('DisAbove'); }); it('should make use of addModelToTypegoose', async () => {