Skip to content

fix(graphile-build-pg): add computed fields to polymorphic interfaces - #3216

Open
dilame wants to merge 2 commits into
graphile:mainfrom
dilame:fix/relational-polymorphism-computed-fields
Open

dilame wants to merge 2 commits into
graphile:mainfrom
dilame:fix/relational-polymorphism-computed-fields

Conversation

@dilame

@dilame dilame commented Oct 15, 2026

Copy link
Copy Markdown

Addresses #1951.

A function that takes a polymorphic table's row (a computed column) is not added to the table's interface, for mode:single and mode:relational. For mode:relational it is not added to the implementations either, since the function takes the root's row type, not an implementation's. PgCustomTypeFieldPlugin has // TODO: remove this and fix issue where computed columns are not added to polymorphic types and // TODO: factor in where computed column is added to mode:relational base (shared) table.

Visible in the existing polymorphic test schema: single_table_items_meaning_of_life is on the single-table implementations but not on SingleTableItem; relational_items_meaning_of_life is on no type.

{ allRelationalItems { nodes { __typename meaningOfLife } } }
# Cannot query field "meaningOfLife" on type "RelationalItem".
{ allRelationalPosts { nodes { meaningOfLife } } }
# Cannot query field "meaningOfLife" on type "RelationalPost".

Change (PgCustomTypeFieldPlugin)

  • modFields no longer returns early for single / relational interfaces (union interfaces still do).
  • The computed sources of an implementation include those of the relational roots it implements, found through codec.extensions.relationalInterfaceCodecName (set by PgPolymorphismPlugin), at any depth.
  • On an implementation, the field's plan first follows the relation(s) from the implementation's row to the owning root's row, only when they differ; otherwise the plan is unchanged, so no existing computed-column plan changes.

Performance: on a relational implementation the function is evaluated from the root row reached by a relation. Non-polymorphic tables are unchanged.

#3066 (@applyToType for computed columns) touches the same file; the two are complementary and one will need a rebase.

Commits

  1. test(graphile-build-pg): adds polymorphic.relational_items_type_label(relational_items) to the fixture, __tests__/queries/polymorphic/computed-fields.test.graphql with snapshots (fields read through the relational interface, a relational implementation and the single-table interface; values checked against the root row), and the expected updates of four schema snapshots (meaningOfLife and typeLabel on both interfaces and on the five relational implementations). On main:
    ● expect(errors).toBeFalsy()
      Invalid operation document: Cannot query field "meaningOfLife" on type "RelationalItem".
    ● prints a schema for polymorphic
      - Expected  - 13
      + Received  +  0
    Test Suites: 5 failed, 5 total
    Tests: 16 failed, 16 total
    
  2. fix(graphile-build-pg): the change above + changeset. Test Suites: 5 passed, 5 total; Tests: 16 passed, 16 total.

Verification

Run on this branch against PostgreSQL 17 (UTF8): postgraphile/postgraphile full jest: 236 passed, 236 total, 804 passed, 804 total; yarn test:schema-exports: passes; EXPORT_SCHEMA=typeDefs jest __tests__/queries __tests__/mutations: 730 passed, 730 total; EXPORT_SCHEMA=graphql-js jest __tests__/queries/polymorphic __tests__/queries/refs: 163 passed, 163 total; graphile-build-pg yarn test: passes. prettier --check and eslint on the changed files: clean. Baseline on main with the same setup: 235 suites / 792 tests, typeDefs 718, graphql-js 151, all passing.

Add a `relational_items_type_label` function to the `polymorphic`
fixture and a query test that reads computed fields through the
relational interface, a relational implementation and the single-table
interface. Update the schema snapshots with the expected fields. On
main the fields do not exist on these types.
Computed fields (functions that accept a table's row) were not added to the
interface of a polymorphic table (`mode:single` or `mode:relational`), only
to its implementations - and for `mode:relational` not even to those, since
the function accepts the root's row type rather than an implementation's.
See the removed TODO about computed columns on polymorphic types.

Add them to the interface, and for `mode:relational` also to each
implementation: its plan follows the relation(s) from the implementation's
row to the root's row, which the function accepts.
@changeset-bot

changeset-bot Bot commented Oct 15, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 845dbe7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
graphile-build-pg Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

This branch has not been deployed

No deployments
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

Successfully merging this pull request may close these issues.

1 participant