Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

It should be possible to declare a shared @ref only in the base table when using relational polymporphism #2087

Open
1 of 6 tasks
FelixZY opened this issue Jun 9, 2024 · 2 comments

Comments

@FelixZY
Copy link
Contributor

FelixZY commented Jun 9, 2024

Feature description

Note: I'm talking about "derived tables" as in "derived class" from OOP, not as in PostgreSQL table inheritance

I have a Profile type which can concretely be an instance of Individual or Organization. Each profile can also be a member of one or more organizations (OrganizationMember). I therefore wish to define this property on the base table (using @ref and @refVia):

comment ON TABLE dansdata.profiles IS $$
  @name Profile
  @interface mode:relational type:type
  @type individual references:individuals
  @type organization references:organizations
  @ref organizations to:OrganizationMember plural
  @refVia organizations via:(id)->organization_members(member_id)
$$;

However, this does not work. Instead, I must define the property on each of my derived tables as well (Postgraphile is kind enough to throw an error if I don't so at least I won't forget):

comment ON TABLE dansdata.individuals IS $$
  @name Individual
  @ref organizations to:OrganizationMember plural
  @refVia organizations via:profiles;(id)->organization_members(member_id)
$$;

comment ON TABLE dansdata.organizations IS $$
  @name Organization
  @ref organizations to:OrganizationMember plural
  @refVia organizations via:profiles;(id)->organization_members(member_id)
$$;

It would be really nice if Postgraphile was able to infer the relationship based on the base table only. It would reduce code duplication and reduce the risk of bugs.

More complete SQL

CREATE TYPE dansdata.profile_type AS ENUM('organization', 'individual');

CREATE TABLE dansdata.profiles (
  id UUID DEFAULT gen_random_uuid () PRIMARY KEY,
  type profile_type NOT NULL,
  name TEXT NOT NULL
);

comment ON TABLE dansdata.profiles IS $$
  @name Profile
  @interface mode:relational type:type
  @type individual references:individuals
  @type organization references:organizations
  @ref organizations to:OrganizationMember plural
  @refVia organizations via:(id)->organization_members(member_id)
$$;

CREATE TABLE dansdata.individuals (
  id UUID PRIMARY KEY REFERENCES dansdata.profiles (id) ON DELETE cascade
);

comment ON TABLE dansdata.individuals IS $$
  @name Individual
  # These two should not be necessary!
  @ref organizations to:OrganizationMember plural
  @refVia organizations via:profiles;(id)->organization_members(member_id)
$$;

CREATE TABLE dansdata.organizations (
  id UUID PRIMARY KEY REFERENCES dansdata.profiles (id) ON DELETE cascade
);

comment ON TABLE dansdata.organizations IS $$
  @name Organization
  # These two should not be necessary!
  @ref organizations to:OrganizationMember plural
  @refVia organizations via:profiles;(id)->organization_members(member_id)
$$;

CREATE TABLE dansdata.organization_members (
  organization_id UUID REFERENCES dansdata.organizations (id) ON DELETE cascade,
  member_id UUID REFERENCES dansdata.profiles (id) ON DELETE cascade,
  CHECK (organization_id <> member_id),
  title TEXT,
  PRIMARY KEY (organization_id, member_id)
);

comment ON TABLE dansdata.organization_members IS $$
  @name OrganizationMember
$$;

Supporting development

I [tick all that apply]:

  • am interested in building this feature myself
  • am interested in collaborating on building this feature
  • am willing to help testing this feature before it's released
  • am willing to write a test-driven test suite for this feature (before it exists)
  • am a Graphile sponsor ❤️
  • have an active support or consultancy contract with Graphile
@FelixZY
Copy link
Contributor Author

FelixZY commented Jun 9, 2024

The documentation currently describes the from field like this:

from: - the name of the GraphQL type we're applying the reference to when using polymorphism

Based on #1876 and #1874, it seems like a better description might be:

from: - the name of the GraphQL type we're applying the reference to when using single-table (mode:single) polymorphism

@benjie
Copy link
Member

benjie commented Jun 10, 2024

I think what you're asking for is essentially inheritance. Interfaces in GraphQL do not perform inheritance - they just describe the interface that is expected, and it's up to the implementations to then provide fields matching the interface. Currently I'm following the GraphQL pattern. That said, for relational tables, there is effectively inheritance so I can see the value in that; feel free to work on a PR for it (for relational and single table interfaces only).

This is a feature that could be added long after v5.0.0 ships since there's already a solution, so it will be at the very bottom of my TODO list to fix myself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants