I am using sequelize but ran into the problem of it not supporting model inheritance.
I would suggest implementing an InheritsFrom association, that would be basically the same as the BelongsTo association. Though, when persisting a new object, sequelize would chain-create all subclass objects and persist them first. It would also allow an object to share the getters/setters of its superclass instances.
module.exports = (function() {
var InheritsFrom = function(source, target, options) {
this.associationType = 'InheritsFrom'
this.source = source
this.target = target
this.options = options
this.isSingleAssociation = true
this.isSelfAssociation = false
this.as = this.options.as
I figured I could add the InheritsFrom and Superclasses options to the dao-factory.js,
Also, I would add InheritsFromInstance and SuperClassInstance in the dao.js
var DAOFactory = function(name, attributes, options) {
this.options = Utils._.extend({
timestamps: true,
...
inheritsFrom : null
superClasses : {}
}, options || {})
Calling the dao get from a inherited dao would look for the key, and if it was not found, look for the key in the sub dao, until it finds the correct getter. Also, if a getter/setter was called from a superclass dao, it would find the last inherited dao, and start to find the key from there.
DAO.prototype.get = function (key) {
if (key) {
if (this._customGetters[key]) {
return this._customGetters[key].call(this, key)
}
return this.dataValues[key]
}
if (this._hasCustomGetters) {
var values = {}
, key
for (key in this._customGetters) {
if (this._customGetters.hasOwnProperty(key)) {
values[key] = this.get(key)
}
}
for (key in this.dataValues) {
if (!values.hasOwnProperty(key) && this.dataValues.hasOwnProperty(key)) {
values[key] = this.dataValues[key]
}
}
return values
}
//Here, check if the superclass has the get methods
return this.dataValues
}
I think I have to add some _customGetters and _customSetters in the dao-factory.js, but could somebody help me out and point me where in the codebase should I add such functionality? There is very few comments in there!
Please comment !
I like the idea! :+1:
I like the idea, but i need some clarification.
If i understand it correctly, you want to be able to extend, not just the model, but the data it holds in a seperate table, right?
So if B.inheritsFrom(A) - It doesn't just extend attributes, class and instance methods and create a seperate entity - B will actually use A's dataset/table?
That would be extremely complex to develop, although very interesting.
It "should" be the same entity, but I think it would be easier for it not to be.
I looked for a ORM that does this already, but found none in no language. ActiveRecords only support single table inheritance, dumping all the fields in a single table.
There is three types of "inheritance mappings"
For this enhancement :
I think the models should be separate entities. It should only navigate through the inheritance tree up and downstream, each node being a distinct sequelize entity, through the inheritsFrom and isSuperClassedBy properties. I'm not sure what would happen if a method or a field was redefined. I would rather "simulate" inheritance by adding the isSuperclassedBy and classInheritsFrom properties, instead of extending the model (ala Backbone). For sure it would be prettier, but... anyways.
Let's dive into an example :
B.inheritsFrom(A)
B.name
A.age
If I call B.getName(), i should receive A.getName()
When it becomes interesting :
C.inheritsFrom(B).inheritsFrom(A) and D.inheritsFrom(B).inheritsFrom(A)
The main problem in this structure is : navigating up and downstream. It poses two problems in sequelize :
First, A doesn't have any information about what type of leaf class it really superClasses. I suggest adding Class.type whenever a class superclasses at least two classes, for easily navigating upstream (instead of having to iterate through each possible children classes and find its own id in the foreign key). In the case of a C object being instantiated, B.Type = C. (B superclasses C and D, so it needs to know which type it is, and A only superClasses one Class, B, so it already knows where to look for its superclasses instances). I would also add A.leafClass so that A already knows what type of leaf it has.
Second problem, getters and setters. They should be asynchronous! If I want to access a property of a super instance, I need first to get that instance (which is asynchronous, unless it is eagerly loaed).
Let say C.getAge() // a normal getter, in all its glory! But! C.age doesn't exist! In reality, we want A.age !
Oh and for creating a C object, you only need to attach BeforeCreate hooks to the parents classes so it does :
C. BeforeCreate
B.BeforeCreate
A.BeforeCreate
A.Create
B.Create (with A_id = A.id)
C.Create (with B_id = B.id)
For eagerly loaded inheritance instances :
// C table
C.id as C_id,
C.Pet as C_Pet,
C.B_id as C_B_id
// B table
B.id as B_id, //C_B_id and B_id are the same
B.name as B_name,
B.A_id as B_A_id
// A table
A.id as A_id //B_A_id and A_id are the same
A.age as A_age
from C
inner join B
on B.id = C.B_id
inner join A
on A.id = B.A_id
where //...
Would be way easier for it to be the same entity. I.e. extends just means a model with attributes, instance/class methods, associations inherited. And then work like it's own model.
You're surely right, I haven't analyzed the codebase thoroughly. What about the async/eagerly loaded getters and setters?
async getters and setters pose a big issue in then having to wait for async setters in save() etc.
Honestly i don't see feel like this should make it into core, it will add a lot of complexity, this would be ideal as a plugin - But need to hear from the others.
Thoughts @sdepold, @durango, @janmeier?
What i mean is doing this kind of virtual table inheritance where B can get data from (and set) table A etc, would be very complex.
But would definitely be willing to discuss this further, it would need a serious spec first atleast.
What parts of the code do you think this enhancement would affect most?
Hmm, i suppose it would primarily be the setting and getting of values and associations.
But the async setting of values has an impact on updateAttributes and save() at the least. And it means we have to support both sync and async cases.
For async getters and setters : #965
A thought about this :
If sequelize created Views for these inherited concrete leaf classes, containing all the info from the base classes, the getters would not have to be async. For setters, since inserting in a view is handled differently in different db engines, INSTEAD triggers could be written.
Edit : In fact, stocked procedures would be easier than views for both update, insert, delete and find operations.
I've forked the repo and started working on a possible workaround, with no need for async getters / setters.
https://github.com/ludydoo/sequelize/commit/327086f8a1265cac16b43503fd50b2d342036c32
Would love to hear comments about that !
Regarding #965, everyone agreed that async setters and getters were a bad idea.
And what do you think about stocked procedures for insert/delete/update of models that would be inherited?
Or just plain MySQL queries that would :
Stocked procedures? Not familiar with them.
Using the prefetching mechanism to retrieve data from parent/super classes would probably be ideal.
I'm still not totally sure about this feature request, it doesn't seem right for core. But still not ruling it out, can you show me any other ORM's that have implemented a similar feature?
Doctrine supports it, ActiveRecord only supports Single Table Inheritance
I'd be happy to help!
I'll go through the ORMs, i'm liking this idea more and more. And it will work together well with the ability to save associations from the main object which we are planning to do.
By doing association saving via main object we would support most of this, i guess the primary thing we have to do is instead of having nested attributes from the inherited classes they would be on the main class.
We need to consider the API too, perhaps .inheritsFrom is not the best way to define this. If we do something like Model.extends() one should probably be able to define how the extend is done, if it just extends methods or if it's expected to work with a parent table.
I would like to get @janmeier's thoughts on this.
What do you mean by saving associations from the main object?
Something like:
User.belongsTo(Group);
User.create({
name: 'Foobar',
group: {
name: 'Yolo'
}
}, {
include: [Group]
});
Which would then create both a user, and a group and attach them obviously :)
I see!
And what would be the different use cases of
Model.extends(AnotherModel, {options})
I mean, since models in sequelize are always synced, what kind of methods and properties of AnotherModel could Model inherit, apart of persisted attributes? Virtual getters and setters?
Could inherit class methods and instance methods primarily i guess.
Well the original inheritance we though about was just going to attributes, classMethods and instanceMethods and perhaps relationsships. But that would create a completely new table.
Here we should probably design an API where you can decide to use a parent table, decide to use one table, decide not to inherit attributes at all, etc.
Kind of a mixin of another model?
Yes I think it would be nice to be able to define inheritance types (only methods, attributes, etc. and maybe single table inheritance / concrete class inheritance / table per class inheritance)
Yea i suppose it would be more of a mixin :)
Is there a branch of the repo where this extend method is in development ?
Not yet, it's only in the "planning in our heads" phase :)
I'm afraid I can't fork this branch
No i imagine you can't :)
Do you think it would be a better idea to handle this inheritance functionality in the DaoFactory? I mean to wrap the accessor methods (update, insert, delete, find, findall...) with some condition for testing the presence / type of inheritance of a Dao, that would build a different sql query depending on the presence and type of inheritance defined in the Model definition. Like :
DaoFactory.find = function(){
if (this.isSimpleModel) {
// process normally
} else {
// process inherited
}
}
That, or to create some separate class (like the association classes + mixin) that would handle these accessor methods (update, insert, delete...), and override the DaoFactory's definitions? Like :
var TablePerClassInheritance = (function(){
var TablePerClassInheritance() = function(){
//initialization
}
TablePerClassInheritance.find = function(){
// Code for inherited find...
}
})();
DaoFactory.prototype.extends = function(SuperModel, InheritanceType){
// Code for inheriting the superclass class and instance methods
// Code for inheriting the super class attributes
Utils._.extend(this.prototype, TablePerClassInheritance)
}
AModel = sequelize.define('Model', {})
AModel.extends(AnotherModel, sequelize.TablePerClassInheritance)
I mean, the accessor methods will behave differently if the Model is a simple type (not extending any other Model), or an inherited type (extending another model).
For a simple Model, the find method emits a sql
SELECT * FROM TABLE_NAME WHERE...
and inherited models will have to execute a sql
SELECT * FROM tableName INNER JOIN otherTable WHERE otherTable.tableNameId = tableName.id AND ...
I wondered where the code that would recognize the type of the Model (simple or inherited or whatever) should be put in a separate class, let's say InheritanceManager in que QueryInterface or in the QueryGenerator ? Where would you think would be the best place to put this, in order to work well with the where conditions (used in Model.find({where : blabla}) and Model.create({name : blibli}) and ...
I've started testing out the inheritance implementation directly in the abstract/query-generator
It's working out pretty nicely. Been able to fetch "parent" class fields. I didn't test anything yet except a basic findAll(), which returned a model containing its parent dataValues and its own. Basically it recursively creates a query with INNER JOINS on all parent tables, outputting it as if it was it's own data.
Must say the selectQuery method is quite heavy (700 lines!!)
I'll be testing this more tomorrow.
@mickhansen may you explain to me what is the purpose of options.includeand subQueries in the selectQuery method?
https://github.com/sequelize/sequelize/blob/master/lib/dialects/abstract/query-generator.js#L464
@ludydoo That is the logic for building nested prefetching including ordering and filtering on nested tables - And figuring out which tables to include in the subquery etc, it's complicated stuff.
@ludydoo selectQuery is a fucking beast, and i think it's cleaner than before my refactor. But it handles everything regarding prefetching, and thats a lot of logic.
@ludydoo I'm thinking something like hasParents then convertParentsIntoIncludes type of thing for find and findAll, since we want to support both parent tables and associations.
@ludydoo Do you have IRC? Some of this might be easier via IM
What's the server?
irc.freenode.net#sequelizejs
alright!
Please see https://github.com/sequelize/sequelize/wiki/Suggestion-for-Inheritance-API for possible api spec
@ludydoo i'll take a look at it this weekend if i get the chance, just got some last minute work in.
In your "Bigger Example" - Would Party/User and Party/Organization then share id's, or would it be polymorphic?
What examples do you connect with what inheritance models in Doctrine? I kindof understand the 3 different types of Doctrine, where MappedSuperClass inheritance is obviously the easiest one since it's purely code
Single Table Inheritance would require polymorphic association support first, or atleast it wouldn't really make sense not to do that first.
Pure code inheritance and single table inheritance i'd say we could do without too much pain. But the class table inheritance one is tricky. Can you try and explain to me how the tables are mapped together? Are their foreign keys between all the tables?
For example :
Party.id
Person.id
Person.partyId //--> foreign key on party.id
Organization.id
Organization.partyId //--> foreign key on party.id
Single table inheritance would be :
Parties.id
Parties.type //--> discriminator (Organization / Party / ...)
Parties.org_name //-> only for orbs
Parties.first_name //--> only for person
Parties.last_name //--> only for person
For table per class inheritance, could add a discriminator column to reduce the number of queries one has to perform. For example, persons.findAll() would return a hash
organizations : {
[0] ...
[1] ...
persons : {
[0] ...
}
}
By adding a discriminator column, the query wouldn't have to iterate through each "sub" table in order to find the corresponding "partyId". It would already know in which table to look. If the discriminator is "Person", then the data lies in the "Persons" table
Yes, there would be foreign keys between all tables. From the child to the parent, in order to maintain data integrity.
In a sense, this is a "Composition" association. Meaning that a Person is composed of a Party, or an Organization is also composed of a Party. The class "BigPerson" would be composed of a Person that would be composed of a Party, etc.
Class Table Inheritance (or table per class inheritance) is the hard one. I see us being able to do the other two reasonable simply.
Is CTI a big need for you?
Yes it would be, since it is way easier to maintain and scale.
Scale how? Seems CTI would be overall worse performance.
Yes, I agree. CTI offer the worse performance in term of request speed.
Though, "worse" performance is relative : processing time is certainly longer as there are going to be a number of joins (depending on the depth of the inheritance schema). Though, four, five, even six joins are perfectly acceptable in current rdbms. I would think the difference is in terms of milliseconds,.
Though, I still think it is the most scalable, due to the fact that in STI (single table inheritance) or CCI (concrete class inheritance), in the case of a complex inheritance schema, there are going to be MANY unused fields (nulled fields). The database will grow very large, very fast. CTI is leaner for sure in terms of data volume.
I think STI or CCI are perfect for simple data models, and little volume. Though, CTI is more suited to both large volume and complex data models. Sadly, current dbms either partly support or do not support table inheritance at all.
I am porting an application the the web in the next years. It uses Firebird as db. It contains something like 150 tables with migrations, and should be used by 400 users simultaneously. I would not like to see it in STI nor CCI for sure. I will be using mirror databases for SELECT operations. I'm not sure the JOINS required by CTI will be the bottleneck... But man, STI or CCI for that kind of application, I think it is just wrong!
Hmm, from my experience JOINS add a lot of query overhead, much more than a few ms. But some of that is also the additional parsing required by Sequelize.
I'd love to support CTI, it's just not a quick one to do :)
Yeah I understand. One of the core contributors of Sequelize pointed me to the ruby's axiom library : https://github.com/dkubb/axiom. It basically uses relational algebra to parse valid sql queries. I'm thinking of porting that to javascript, would make that kind of operation way easier.
seems Node-ORM has implemented something similar extendsTo
Also I posted a question about How do I implement a MySQL inheritance relations with a Node.js database ORM (like sequelizejs)?, any good suggestion?
@neekey i've thought about implementing some simple code-side inheritance (i.e. not postgres style table inheritance), it shouldn't be too tricky actually :)
@mickhansen @ludydoo is this already in core sequelize or is it available as a plugin ?
@skvsree Not available in core, per my last comment.
@mickhansen looking forward to this feature :+1:
:+1: this would be really useful for me too!
Is there any hope for object inheritance mapping become a feature soon ?
+1 Hope to see landing soon.
Will allow to define common attributes for models.
Some progress on this issue?
@csrinaldi No progress so far, other than the discussions here - we still need a more formal spec and a descision about which of the proposed solutions to implement.
You are welcome to weigh in with your comments about which method you prefer
:+1: Would be great!
+1
+1
+1
+1
Coming from PHP/Doctrine and am evaluating sequelize for use with GraphQL. Class Table Inheritance is one of the items I'm currently using and thought maybe it might help to give a use-case to promote it's importance.
I'm making a web game in which there are lots of future events happening: Troop Movements, Buildings, Units Training, Researches etc. I've got a cron/queue-worker which goes through these events and processes them in order of them completing.
/**
* @ORM\Table(name="game_events")
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="event", type="integer")
* @ORM\DiscriminatorMap({
* 1 = "Movement",
* 2 = "BuildingQueue"
* })
* @ORM\Entity
*/
abstract class GameEvent {
/** @ORM\GeneratedValue(strategy="AUTO") */
private $id;
/** @ORM\Column(name="start_time", type="datetime", nullable=false) */
private $startTime;
/** @ORM\Column(name="end_time", type="datetime", nullable=true) */
private $endTime;
}
/**
* @ORM\Table(name="building_queue")
* @ORM\Entity
*/
class BuildingQueue extends GameEvent
{
/** @ORM\OneToOne(targetEntity="Building", inversedBy="buildingQueue") */
private $building;
}
/**
* @ORM\Table(name="movements")
* @ORM\Entity
*/
class Movement extends GameEvent
{
/** @ORM\ManyToOne(targetEntity="MapSquare") */
private $mapSquare;
}
This creates a DB structure like:
game_events
+----+---------------------+---------------------+-------+
| id | start_time | end_time | event |
+----+---------------------+---------------------+-------+
| 11 | 2016-03-22 21:24:38 | 2016-03-22 21:25:34 | 1 |
| 12 | 2016-03-22 22:35:06 | 2016-03-22 22:23:32 | 2 |
+----+---------------------+---------------------+-------+
movements
+----+---------------+
| id | map_square_id |
+----+---------------+
| 11 | 68874 |
+----+---------------+
building_queue
+----+---------------+
| id | building_id |
+----+---------------+
| 12 | 22 |
+----+---------------+
So this means my queue-worker can process game-events in correct order:
$gameEvents = $gameEventRepository->findAll(); // [ Movement, BuildingQueue ]
And within the ORM they're regarded as separate entities: $building->getBuildingQueue()
Is this any closer to inception? hasn't been an update for a year. Maybe this could be achieved with TypeScript classes and decorators?
@intellix No one has worked on this as far as i know.
I've been working on a quick and dirty plugin to mimic table-per-class inheritance, in order to get me where I'm going. On my journey, I noticed that each model attribute specifies the model from which it originated, which as far as I can tell never differs from the model that declared the attribute in the first place.
For example, if I inspect user.attributes where user is a model, I may receive the following result:
{
first_name: {
type: {
options: [Object],
_binary: undefined,
_length: 255
},
allowNull: false,
Model: user,
fieldName: 'first_name',
_modelAttribute: true,
field: 'first_name'
}
}
Note the Model: user attribute. The way I see it, if we declare that a model inherits from another model, we could merely append the parent model fields to the child model, as they would ideally retain that Model: <model> attribute. As a result, through the entire process of building the query, we would know which models were involved.
So now that we understand which models are used in generating our query, we need only distinguish the types of inheritance:
Single Table Inheritance: The quickest win I can think of in order to get this working is to apply the parent attributes to the child, and then set the child's table to that of the parent. This results in a select statement devoid of joins or other trickery, that pulls data from the table specified on the parent, and dumps that data into the child directly.
Table Per Concrete Class: When building the query, we need to peek at that Model: <model> attribute on each field. If there are attributes from two or more tables, we need to check our inheritance type attribute/indicator and if it's set to "table per class hierarchy", then we need to group the fields by owning model, join on those models, and pull the data in accordingly. Again, all the data gets dumped into the child model.
Arbitrary Schema Design: For those cases where we end up storing data in separate tables where the tables do not necessarily correspond 1:1 with a model, we should provide the ability to specify which table an attribute comes from. The result would be roughly the same as the implementation for "Table Per Concrete Class", but would allow the developer to alter the source table for an attribute.
In terms of configuration, I have two proposals:
1) Handle this with configuration properties. For example:
sequelize.define('client', { ...attributes... }, {
inheritsFrom: sequelize.model('user'),
inheritanceType: 'table-per-class'
}
2) Handle this in the same way we handle relations:
var Client = sequelize.define('client', { ...attributes... });
Client.inheritsFrom(sequelize.model('User'), {
inheritanceType: 'single-table'
})
I expect that 'single table' and 'table per concrete class' inheritance types probably meet the needs of most folks looking to use this library. I can definitely see this working well, but obviously at this point I'm just an interloper. If this rough concept seems reasonable, I'm game for attempting implementation. I don't have a great deal of time at the moment, but it's something I need myself anyway. Thanks for your consideration.
As we are going for classes in Sequelize 4 imo two models that inherit from each other should actually inherit from each other, like
class Base extends Sequelize.Model {}
Base.init(...)
class Derived extends Base {}
Derived.init(...)
Upon the init() call this could be detected by walking the prototype chain until we reach Sequelize.Model.
What's important here is that we ensure a deep inheritance: Normally the model would inherit all properties, but the properties themselves not (attributes/options would just get overwritten). So what we have to do is something like
init(attributes, options) {
this.attributes = Object.assign(Object.create(this.attributes), attributes)
}
which would make attributes inherit all properties from it's parent model aswell.
Guess I should have figured that this wouldn't be backported. I'm on 3.x right now, so I was mostly speaking based on what I know of that. Haven't the foggiest clue about 4.x. Either way, I'm afraid that if I can't get inheritance working to some degree for my current project, I'll have to move on, which is disappointing. This thread has been around for two and a half years.
@thomas-p-wilson Do you need to inherit attributes or everything including associations and methods?
@thomas-p-wilson
I'll have to move on, which is disappointing.
It is disappointing that you may have to update to get new features?
This thread has been around for two and a half years.
Because noone found it important enough to take the time to implement it 馃槓
Go easy there. Never said I didn't want to update. I'm fine with updating, but I'll not be updating to a pre-release in a production environment. At any rate, unless I'm mistaken, the inheritance functionality doesn't exist in 4.x at the moment.
And yes, nobody found it important enough to implement, I get that. I'm just surprised that nobody has bothered with any sort of inheritance in the two years this thread has been around. Makes me wonder if folks have been jumping ship for some other solution that offers it. I'm willing to give of my time in order to attempt an implementation, but I can't update to 4.x in the application I'm working on, ergo it'll be spare time work for me.
@mickhansen Attribute inheritance would be sufficient. I can get away without association and method inheritance
@thomas-p-wilson yes, nothing is implemented so far in v4, besides that models are actual classes and can inherit on a very basic javascript level. Is your concern supporting actual table inheritance with INHERITS FROM or do you just want inheritance for your models?
I'm not overly concerned with INHERITS FROM support at present. Obviously it'd be nice, but it makes the most sense to first achieve inheritance support across all our supported datastores, no?
That would be pretty easy if we get the Javascript-level inheritance support working. Wherever the library references attributes etc. It would just prototypically inherit from the parent's attributes.
Yep. Thinking I'll pull 4.x down tonight or tomorrow evening and muck about with it a bit.
I believe there's an issue with cloning attributes that probably makes it unworkable currently, but otherwise attribute sharing would be easy in userland.
Yeah I mucked about with attribute cloning in 3.x, but didn't go too far with it after realizing I'd have to change a whole bunch of stuff.
I'll get familiar with 4.x over the next couple days and noodle on the matter some more.
@mickhansen what attribute cloning?
@thomas-p-wilson v4 really hasn't changed much besides that everything is ES6 and Model and Instance are one class.
@felixfbecker If you attempt to reuse an attribute definition and use a deep clone or similar it will fail.
const mySharedAttributes = {
firstName: Sequelize.STRING
};
sequelize.define('User', {
..._.deepClone(mySharedAttributes)
});
sequelize.define('Guest', {
..._.deepClone(mySharedAttributes)
});
IIRC this fails because type definitions end up behaving incorrectly.
@mickhansen This is because Sequelize.STRING is a function, and you cannot clone it (or it wouldn't make sense to do so). But what do you think about my idea of adding to code to init() that makes attributes and options prototypically inherit from the parent model?
I've been fighting for an elegant solution to this in Sequelize and, after many hours, haven't come up with a good solution aside from manually mapping tons of relations and attributes. I'm not sure why, but it unfortunately seems that the only library which supports generalization hierarchies is node-orm2 (https://github.com/dresende/node-orm2/wiki/extendsTo); unfortunately, it's not very widely adopted yet so that's a risky dependency to take on. I'll keep looking, but it'd be really awesome if Sequelize supported this - other ORMs, like SQLAlchemy, provide some working version of it (linked earlier in the thread).
It would be great to support the correct classifications if it is implemented as well - specifically, disjoint and overlapping hierarchies. I haven't found a library that does this, but it's common in RDBMS literature
I take part of my comment back about node-orm2 - I misread it, that's actually still a hasOne association under the hood, not an inheritance hierarchy.
@ewyler I wrote a plugin for sequelize a year ago that is pretty straight forward, we've been using it since. It maintains all syntax, the only catch is the constructors are slightly different from traditional sequelize.
Yeah, INHERITS FROM is an interesting postgres feature but unfortunately not a real generalization hierarchy - and you lose constraints in child tables.
Maybe supported by: https://github.com/SpoonX/wetland
But not sure :) It's based on Doctrine so possibily
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If this is still an issue, just leave a comment 馃檪
Must-have feature from my point of view
@mickhansen Any progress regarding single table inheritance??
@jawadakram20 I'm no longer an active maintainer on this project
Why was this closed? Seems like a valid request
@johncade It's not closed
@johncade It is closed and they referred me here and they have not worked on it as well. Its been years and discussion is longer but of no use I guess.
I've not read all this discussion but I think it's a must-have feature, at least when using PostgreSQL.
I've coded a custom multi-table inheritance that may be appropriate for a library, but the API is ugly and I'd pretty well guarantee I haven't covered all the scenarios it should cover. Having a sanctioned & approved solution would be greatly greatly appreciated
REF #5757, #5970, #1679
My workaround is very simple but it worked for me:
ALTER TABLE setting the inheritance within a single transaction:'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.sequelize.transaction((transaction) => {
return queryInterface.createTable('eventRecurrenceRecords', {
// .. All fiields from parent (recurrenceRecords)
// Plus this one
eventId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'events',
key: 'id'
},
onUpdate: 'cascade',
onDelete: 'cascade'
}
}, {
transaction
})
// This is the magic
.then(() => queryInterface.sequelize.query(`
ALTER TABLE "eventRecurrenceRecords"
INHERIT "recurrenceRecords"
`, { transaction }));
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('eventRecurrenceRecords');
}
};
https://www.postgresql.org/docs/current/static/sql-altertable.html:
INHERIT parent_table
This form adds the target table as a new child of the specified parent table. Subsequently, queries against the parent will include records of the target table. To be added as a child, the target table must already contain all the same columns as the parent (it could have additional columns, too). The columns must have matching data types, and if they have NOT NULL constraints in the parent then they must also have NOT NULL constraints in the child.
There must also be matching child-table constraints for all CHECK constraints of the parent, except those marked non-inheritable (that is, created with ALTER TABLE ... ADD CONSTRAINT ... NO INHERIT) in the parent, which are ignored; all child-table constraints matched must not be marked non-inheritable. Currently UNIQUE, PRIMARY KEY, and FOREIGN KEY constraints are not considered, but this might change in the future.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If this is still an issue, just leave a comment 馃檪
This is still an issue. A big one!
I recommend to implement this feature in the future.
Most helpful comment
Must-have feature from my point of view