Typegoose: [Inheritance] prop options get overwritten by extended class

Created on 14 Jun 2020  路  5Comments  路  Source: typegoose/typegoose

Versions

image

Code Example

import { prop, getModelForClass } from "@typegoose/typegoose";

class Base {
  // put default as a function if it needs to be dynamic
  @prop({ unique: true, default: () => "base" })
  UID?: string;
}

class Child extends Base {
  @prop({ unique: true, default: () => "overwritten" })
  UID?: string;
}

class GrandChild extends Child {}

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

// # Working

const b = new BaseModel();
const c = new ChildModel();
const gc = new GrandChildModel();

console.log(b.UID);          // base

console.log(c.UID);         // overwritten

console.log(gc.UID);       // base ??  Should it print "overwritten" or I miss something?

link to sandbox

What should happen?

The GrandChildModel UID default value should be from Child, not from the base.

Do you know why it happens?

no

bug cant fix

Most helpful comment

Confirmed, happening even with an prop

// NodeJS: 14.4.0
// MongoDB: 4.2-bionic (Docker)
import { getModelForClass, prop } from "@typegoose/typegoose"; // @typegoose/[email protected]
import * as mongoose from "mongoose"; // [email protected] @types/[email protected]

class Base {
  // put default as a function if it needs to be dynamic
  @prop({ unique: true, default: () => "base" })
  public UID?: string;
}

class Child extends Base {
  @prop({ unique: true, default: () => "overwritten" })
  public UID?: string;
}

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

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

(async () => {
  await mongoose.connect(`mongodb://localhost:27017/`, { useNewUrlParser: true, dbName: "verify292", useCreateIndex: true, useUnifiedTopology: true });

  const b = new BaseModel();
  const c = new ChildModel();
  const gc = new GrandChildModel();

  console.log(b.UID);

  console.log(c.UID);

  console.log(gc.UID);

  await mongoose.disconnect();
})();

Note: at first i thought it might be a problem related that GrandChild is empty, which causes some other issues

All 5 comments

Confirmed, happening even with an prop

// NodeJS: 14.4.0
// MongoDB: 4.2-bionic (Docker)
import { getModelForClass, prop } from "@typegoose/typegoose"; // @typegoose/[email protected]
import * as mongoose from "mongoose"; // [email protected] @types/[email protected]

class Base {
  // put default as a function if it needs to be dynamic
  @prop({ unique: true, default: () => "base" })
  public UID?: string;
}

class Child extends Base {
  @prop({ unique: true, default: () => "overwritten" })
  public UID?: string;
}

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

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

(async () => {
  await mongoose.connect(`mongodb://localhost:27017/`, { useNewUrlParser: true, dbName: "verify292", useCreateIndex: true, useUnifiedTopology: true });

  const b = new BaseModel();
  const c = new ChildModel();
  const gc = new GrandChildModel();

  console.log(b.UID);

  console.log(c.UID);

  console.log(gc.UID);

  await mongoose.disconnect();
})();

Note: at first i thought it might be a problem related that GrandChild is empty, which causes some other issues

This problem will be fixed by https://github.com/typegoose/typegoose/pull/243, the pr cannot be merged until https://github.com/Automattic/mongoose/pull/8897 is released in mongoose, because of https://github.com/Automattic/mongoose/issues/8892

TL;DR: #243 would fix it, but would break virtuals

here is how typegoose currently compiles classes, in mongoose terms:

// NodeJS: 14.4.0
// MongoDB: 4.2-bionic (Docker)
import * as mongoose from "mongoose"; // [email protected] @types/[email protected]

function base() {
  return "base";
}

function overwritten() {
  return "overwritten";
}

(async () => {
  await mongoose.connect(`mongodb://localhost:27017/`, { useNewUrlParser: true, dbName: "verify292", useCreateIndex: true, useUnifiedTopology: true });

  const child = new mongoose.Schema({ prop1: { type: String, default: overwritten() } });

  const parent = child.clone();
  parent.add({ prop1: { type: String, default: base() } });

  const grandchild = parent.clone();
  grandchild.add({ something: { type: String } });

  const model1 = mongoose.model("child", child);
  const model2 = mongoose.model("parent", parent);
  const model3 = mongoose.model("grandchild", grandchild);

  console.log(new model1());
  console.log(new model2());
  console.log(new model3());

  await mongoose.disconnect();
})();

Note: it has reasons on why its executed in this specific order at the moment (for more information, follow the linked pr's and issues)

the current status is that this issue cant be fixed without majorly breaking(/changing) other things before mongoose releases 6.0

Marking Issue as stale, will be closed in 7 days if no more activity is seen

Marking Issue as stale, will be closed in 7 days if no more activity is seen

Was this page helpful?
0 / 5 - 0 ratings