Skip to content

Commit

Permalink
feat: change build order to bottom-up (when extending classes) (#243)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Build order for Classes to Schemas is changed to bottom-up, which can affect some environments

Co-authored-by: hasezoey <hasezoey@gmail.com>
  • Loading branch information
ggurkal and hasezoey committed Aug 26, 2021
1 parent bd6790d commit 79977ee
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 2 deletions.
15 changes: 13 additions & 2 deletions src/typegoose.ts
Expand Up @@ -129,13 +129,24 @@ export function buildSchema<U extends AnyParamConstructor<any>>(
let sch: mongoose.Schema<DocumentType<InstanceType<U>>> | undefined = undefined;
/** Parent Constructor */
let parentCtor = Object.getPrototypeOf(cl.prototype).constructor;
/* This array is to execute from lowest class to highest (when extending) */
const parentClasses: AnyParamConstructor<any>[] = [];

// iterate trough all parents
while (parentCtor?.name !== 'Object') {
// extend schema
sch = _buildSchema(parentCtor, sch, mergedOptions, false, overwriteOptions);
// add lower classes (when extending) to the front of the arrray to be processed first
parentClasses.unshift(parentCtor);

// set next parent
parentCtor = Object.getPrototypeOf(parentCtor.prototype).constructor;
}

// iterate and build class schemas from lowest to highest (when extending classes, the lower class will get build first) see https://github.com/typegoose/typegoose/pull/243
for (const parentClass of parentClasses) {
// extend schema
sch = _buildSchema(parentClass, sch!, mergedOptions, false);
}

// get schema of current model
sch = _buildSchema(cl, sch, mergedOptions, true, overwriteOptions);

Expand Down
12 changes: 12 additions & 0 deletions test/models/inheritanceClass.ts
Expand Up @@ -9,6 +9,14 @@ import { getModelForClass, modelOptions, prop } from '../../src/typegoose';
export class Building {
@prop({ default: 100 })
public width?: number;

public get calculatedWidth() {
return this.width;
}

public get assignedGardenArea() {
return 300;
}
}

export class OfficeBuilding extends Building {
Expand All @@ -35,6 +43,10 @@ export class Skyscraper extends OfficeBuilding {

@prop({ type: Garage, _id: false })
public garagesInArea?: Garage[];

public get calculatedWidth() {
return this.width! * this.doors!;
}
}

export const SkyscraperModel = getModelForClass(Skyscraper);
7 changes: 7 additions & 0 deletions test/tests/inheritance.test.ts
Expand Up @@ -50,3 +50,10 @@ it('should set all parent props for nested array items', async () => {
// sanity check
expect(firstGarage).not.toHaveProperty('_id');
});

it('should override inherited property accessor', () => {
const instance = new SkyscraperModel();

expect(instance.calculatedWidth).toEqual(400);
expect(instance.assignedGardenArea).toEqual(300);
});
30 changes: 30 additions & 0 deletions test/tests/shouldRun.test.ts
Expand Up @@ -414,6 +414,36 @@ it('should add query Methods', async () => {
expect(found[0].toObject()).toEqual(doc.toObject());
});

it('should output correct defaults with multiple inheritance [typegoose/typegoose#292]', () => {
class Parent {
// put default as a function if it needs to be dynamic
@prop({ default: () => 'base' })
public UID?: string;
}

class Child extends Parent {
@prop({ default: () => 'overwritten' })
public UID?: string;
}

class GrandChild extends Child {
@prop()
public something?: string;
}

const BaseModel = getModelForClass(Parent);
const ChildModel = getModelForClass(Child);
const GrandChildModel = getModelForClass(GrandChild);

const baseDoc = new BaseModel();
const childDoc = new ChildModel();
const grandChildDoc = new GrandChildModel();

expect(baseDoc.UID).toEqual('base');
expect(childDoc.UID).toEqual('overwritten');
expect(grandChildDoc.UID).toEqual('overwritten');
});

it('should be map none/array/map correctly if using get/set options [typegoose#422]', async () => {
class TestGetSetOptions {
@prop({ get: () => 0, set: () => 1 })
Expand Down

0 comments on commit 79977ee

Please sign in to comment.