question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

feature: Polymorphic Relations

See original GitHub issue

Feature Request: Polymorphic Relations

The ability to create polymorphic one-to-one, one-to-many, and many-to-many relationships in Hasura. This would necessitate Hasura generating appropriate union or interface graphql types for the polymorphic association (or some way for the user to create these types).

  • an example of a polymorphic association is a contact list which contains both person and organization subscribers.

Polymorphic associations have a number of advantages over regular associations which cannot be currently achieved:

  1. The ability to cascade deletion of a polymorphic association (or restrict updates, etc).
  2. The ability to provide the appropriate domain model in your graphql schema (using union or interface types).

Some examples which could benefit from polymorphic associations:

  1. A database has Person, Organization, and Event records which are each associated with an Address record. The address record has a standard shape, so it might make sense to model the data with people, organizations, events, and addresses tables.
    • Currently, you might add an address_id column to the people, organizations, and events tables which acts as a foreign key to an address record. However, this does not allow you to automatically delete the address associated with a Person, Organization, or Event.
      • To automatically delete the address associated with a person when the person is deleted, you can manually create a postgres trigger on the people table. It would be nice if Hasura supplied an option to create this trigger for you.
    • Alternatively, you could add person_addresses, organization_addresses, and event_addresses tables instead of a single addresses table. However this denormalizes your database schema and unnecessarily complicates the generated graphql schema.
  2. A database has ContactList records which have a many-to-many association with both Person and Organization records.
    • Currently, this must be modeled using organization_subscription and person_subscription join tables. If a graphql client wants to be able to pull the first 10 subscribers of a contact list in alphabetical order, you must create a custom sql view. Problematically, the graphql associated with this custom SQL view cannot return an interface/union type of organization and person records. This can be worked around by returning an artificial subscription object with person and organization properties which would contain either a person or organization. However jumping through these hoops is not ideal.

Possible implementations

As an example, Rails’ Active Record supports polymorphic associations by utilizing an additional type column for associations. The type column contains the name of the table, while the standard foreign key column contains the id of the table row.

  • In our first example above, the addresses table might model its polymorphic association using owner_id and owner_type columns. The owner_type column would contain the table of the address owner (either people, organizations, or events) while the owner_id column would contain the row id of the address owner.

A major problem with the Active Record solution is that its logic is handled outside of the database in the ruby application. Active Record does not utilize a foreign key constraint for polymorphic associations because postgres can’t handle that scenerio. i.e. the Hasura graphql-engine server would be handling the logic, checking for the existance of foreign records, etc. This strategy would likely run into major problems around concurrency and would be a major change for hasura, which seems to delegate as much logic as possible to the database.

Doing a bit of research, I’ve found a few helpful stackoverflow answers on how to handle polymorphic associations within the database:

The major takeaway is that postgres/sql does not formally support polymorphic associations. Given that polymorphic associations are a very common part of many data models though, and given that polymorphic associations are a widely used aspect of graphql, it seems worthwhile to find a way of supporting them within Hasura.

Since there doesn’t appear to be an “official” way to support polymorphic associations, Hasura would need to take an opinionated route here (which, personally, I think is fine). The super-table / sub-table approach described in this Stackoverflow answer seems like a good solution: https://stackoverflow.com/a/4970646/5490505.

A super-table / sub-table approach would allow for describing both graphql interface types and union types (an interface type would be described by the super-table. A union type would also be described by the super table, but the super-table wouldn’t contain any information other than id). Hasura would take care of joining the tables and presenting a single record to the graphql client. Hasura would also take care of handling mutations as if only a single table were being updated. Unfortunately, a super/sub table approach still wouldn’t allow for cascade deletion of a polymorphic association (perhaps automatically generating postgres triggers could help with this).

Related: #1167

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:96
  • Comments:12 (2 by maintainers)

github_iconTop GitHub Comments

13reactions
ragnorccommented, Sep 8, 2019

Any updates on that?

3reactions
zlanichcommented, Sep 1, 2020

@cllns Yes, and while that is “slightly” better than creating separate tables (from an organization perspective), it still requires you to create a relationship view for every object type. It’s still quite clumsy, particularly when coming from a Laravel world where you don’t need to do this. You just specify a morph-map that transforms the active record classes into slugs like “model-name”, then it handles the rest for you. I’m really hoping for proper support for polymorphic relations at some point 😦

Read more comments on GitHub >

github_iconTop Results From Across the Web

Understanding Polymorphic Relationships - DevDojo
Before explaining polymorphism, let's do a quick review of the three common relationships: One-to-One; One-to-Many; Many-to-Many. One-to-One.
Read more >
Polymorphic relationships in Laravel and their use cases
A one-to-one polymorphic relationship is a situation where one model can belong to more than one type of model but on only one...
Read more >
Re-Introducing Eloquent's Polymorphic Relationships - SitePoint
A polymorphic relationship is where a model can belong to more than one other model on a single association. To clarify this, let's...
Read more >
Polymorphic relations | LoopBack Documentation
LoopBack supports polymorphic relations in which a model can belong to more than one other model, on a single association. For example, you...
Read more >
Polymorphic relations. When creating relation, ability to have ...
Polymorphic relations. When creating relation, ability to have many Types from which to choose, and not just one Type · Ideas & Features....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found