sequelize / sequelize-typescript

Decorators and some other features for sequelize
MIT License
2.79k stars 280 forks source link

Is it possible to implement class-table inheritance? #46

Open slavafomin opened 7 years ago

slavafomin commented 7 years ago

Hello!

Thank you for your hard work, this module looks very promising.

However, do you mind if I ask? Maybe you are familiar with this problem. Is it possible to implement class-table inheritance with Sequelize and this module?

Thank you.

RobinBuschmann commented 7 years ago

Hey @slavafomin,

unfortunately this is not possible. But sounds very interesting and challenging. And I think this could be implemented in sequelize-typscript. If you don't mind, you could share your thoughts and ideas(?) about it. How should this feature work in sequelize-typescript from your point of view?

Thank you too :)

slavafomin commented 7 years ago

Thank you for getting back to me.

The idea is pretty straightforward, here's the simplified example:

-- Base Table
CREATE TABLE persons (
  id    serial  PRIMARY KEY,
  name  text
);

-- Derived Table
CREATE TABLE students (
  id       integer  PRIMARY KEY REFERENCES persons,
  faculty  text
);

-- Derived Table
CREATE TABLE professors (
  id      integer  PRIMARY KEY REFERENCES persons,
  degree  text
);
@TableInheritance({
  type: 'class-table', // type of inheritance
  discriminatorColumnName: 'type'
})
class Person {
  name: string;
}

@DerivedTable()
class Student extends Person {
  faculty: string;
}

@DerivedTable()
class Professor extends Person {
  degree: string;
}
// Returns both students and professors with given name:
Person.find({ name: 'John' }).then(persons => {
  for (const person of persons) {
    if (person instanceOf Student) {
      // We've got student called John
    }
    if (person instanceOf Professor) {
      // We've got professor called John
    }
  }
});
RobinBuschmann commented 7 years ago

Hey @slavafomin, thanks for your suggestions. I investigated this a little bit deeper and came to the conclusion that an implementation for single table inheritance in sequelize-typscript wouldn’t be an issue. Multi table inheritance aka class table inheritance on the other side should be implemented in sequelize, not in sequelize-typescript. I did not find anything in the first place regarding multi table inheritance in sequelize. But here is a discussion about it: https://github.com/sequelize/sequelize/issues/1243

One problem with multi table inheritance - which I can currently think of - is, that bulk creations would be very difficult. Since there are two tables for one entity (e.g. Student in your example), you won’t get the primary keys of the first table (Person in your example) of each entry in a bulk creation, which are necessary for the second table(Student). Or ones need to insert all base data separately, which would be not very performant.

Regarding your examples: I think the base class should not care about its child classes and therefore not decide in which way it is extended (single or multi table inheritance). So that @Table annotation would be fine for Person. @DerivedTable should hold the information whether it is a single or multi table inheritance. Did I miss something with my approach?

slavafomin commented 7 years ago

Regarding your examples: I think the base class should not care about its child classes and therefore not decide in which way it is extended (single or multi table inheritance). So that @Table annotation would be fine for Person. @DerivedTable should hold the information whether it is a single or multi table inheritance. Did I miss something with my approach?

No, actually this makes sense. The example was primarily taken from TypeORM implementation, which we currently use in our project.

RobinBuschmann commented 7 years ago

Does TypeORM support bulk creations of models using multi table inheritance?

slavafomin commented 7 years ago

The problem is that TypeORM has a lot of issues at the moment and inheritance is one of it's biggest problems for us, it's not reliable and considered experimental. That's why I've asked this question in the first place )

candycrunch commented 6 years ago

Any updates on this ?

RobinBuschmann commented 6 years ago

@kokominaj Not yet, sry. But any PRs are welcome :)

killerall commented 5 years ago

Hello,

We can do something like that?

You have multiple interfaces with their own properties, but in the database they are stored in the same table.

export interface IBase {

@Column({primaryKey: true})
    id: number; 

    @Column
    description: string;

}
import {Table, Column, Model, HasMany} from 'sequelize-typescript';

@Table
export class Person extends Model<Person> implements IBase{

    @Column
    name: string;

}