Skip to content

Add support for Single Table Inheritance when using Entity Schemas #9833

@gabrielkim13

Description

@gabrielkim13

Feature Description

Currently, there is no way to do Single Table Inheritance when splitting the entity definition from its database model by using Entity Schemas.

This feature request proposes a means to add support for this functionality on Entity Schemas.

The Solution

When defining an inheritance tree of entities, such as:

abstract class Base {
    id!: number
    type!: string
    createdAt!: Date
    updatedAt!: Date
}

class A extends Base {
    constructor(public a: boolean) {
        super()
    }
}

class B extends Base {
    constructor(public b: number) {
        super()
    }
}

class C extends Base {
    constructor(public c: string) {
        super()
    }
}

It should be possible to define corresponding Entity Schemas specifying their inheritance relationships:

  • Which one is the parent class and which ones are their children
  • Which column should be used as the discriminator value

The proposed solution is to add a new inheritance option for informing the inheritance pattern to be used, alongside the discriminator column (also, note the use of type: "entity-child" for the concrete entities' schemas):

const BaseSchema = new EntitySchema<Base>({
    target: Base,
    name: "Base",
    columns: {
        id: {
            type: Number,
            primary: true,
            generated: "increment",
        },
        type: {
            type: String,
        },
        createdAt: {
            type: Date,
            createDate: true,
        },
        updatedAt: {
            type: Date,
            updateDate: true,
        },
    },
    // NEW: Inheritance options
    inheritance: {
        pattern: "STI",
        column: "type",
    },
})

const ASchema = new EntitySchema<A>({
    target: A,
    name: "A",
    type: "entity-child",
    columns: {
        ...BaseSchema.options.columns,
        a: {
            type: Boolean,
        },
    },
})

const BSchema = new EntitySchema<B>({
    target: B,
    name: "B",
    type: "entity-child",
    columns: {
        ...BaseSchema.options.columns,
        b: {
            type: Number,
        },
    },
})

const CSchema = new EntitySchema<C>({
    target: C,
    name: "C",
    type: "entity-child",
    columns: {
        ...BaseSchema.options.columns,
        c: {
            type: String,
        },
    },
})

This should keep things cohesive to the current way of implementing STI, with the @TableInheritance and @ChildEntity decorators.

Considered Alternatives

I tried specifying the inheritance relationship through the current extends option, but I figure this property isn't really doing anything. In fact, doing this throws an exception while building the Entity Metadata from the schema:

// ...

const BSchema = new EntitySchema<B>({
    // Throws "TypeError: Cannot read properties of undefined (reading 'ownColumns')"
    extends: "Base",
    target: B,
    name: "B",
    type: "entity-child",
    columns: {
        ...BaseSchema.options.columns,
        b: {
            type: Number,
        },
    },
})

// ...

Additional Context

This is partially related to issue #8415.

Relevant Database Driver(s)

  • aurora-mysql
  • aurora-postgres
  • better-sqlite3
  • cockroachdb
  • cordova
  • expo
  • mongodb
  • mysql
  • nativescript
  • oracle
  • postgres
  • react-native
  • sap
  • spanner
  • sqlite
  • sqlite-abstract
  • sqljs
  • sqlserver

Are you willing to resolve this issue by submitting a Pull Request?

Yes, I have the time, and I know how to start.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions