Skip to content

feat(graphile-settings): enable many-to-many relations by default#854

Closed
pyramation wants to merge 2 commits into
mainfrom
devin/1773980121-improve-m2m-relation-naming
Closed

feat(graphile-settings): enable many-to-many relations by default#854
pyramation wants to merge 2 commits into
mainfrom
devin/1773980121-improve-m2m-relation-naming

Conversation

@pyramation
Copy link
Copy Markdown
Contributor

Summary

Flips the many-to-many preset from opt-in (@behavior +manyToMany required per junction table) to enabled by default (upstream @graphile-contrib/pg-many-to-many default behavior).

The ManyToManyOptInPlugin previously injected -manyToMany into the inferred behavior phase, suppressing m2m fields unless explicitly opted in. That entityBehavior override is now removed, making the plugin a no-op passthrough. The upstream plugin's default (m2m enabled) takes effect.

Combined with the existing _manyToManyRelation inflector in custom-inflector.ts, this produces clean relation names like event.contacts instead of event.contactEventsByEventId, with automatic fallback to verbose names on conflict.

Export names (ManyToManyOptInPlugin, ManyToManyOptInPreset) are preserved for backwards compatibility.

Review & Testing Checklist for Human

  • Schema snapshot test will breakgraphql/server-test/__tests__/schema-snapshot.test.ts uses toMatchSnapshot() and the snapshot was NOT regenerated in this PR. New m2m fields will be added to every junction table in the test schema (post_tags). Run the test with --updateSnapshot and verify the new fields look correct.
  • Verify upstream default — this PR assumes @graphile-contrib/pg-many-to-many enables m2m by default when no behavior override is present. Confirm this matches the installed version's actual behavior.
  • Breaking change for existing consumers — any project using ConstructivePreset will see new m2m connection fields appear on types with junction tables. Verify this is acceptable for all downstream projects, or consider a migration/versioning strategy.
  • Test with a real schema — spin up a PostGraphile server with the ConstructivePreset against a database with junction tables and confirm the generated schema has clean m2m field names (e.g., contacts not contactEventsByEventId).

Notes

  • The plugin name ManyToManyOptInPlugin is now semantically misleading since it no longer enforces opt-in. Consider renaming in a follow-up if that causes confusion.
  • Opt-out is available per junction table via COMMENT ON TABLE ... IS E'@behavior -manyToMany'.

Link to Devin session: https://app.devin.ai/sessions/5c8c35d8c2f3473dbc021b96fe2768c1
Requested by: @pyramation

Junction tables (e.g. contact_events, deal_contacts) now automatically
generate clean shortcut fields that skip the junction table:

  event.contacts          (instead of event.contactEventsByEventId)
  contact.deals           (instead of contact.dealContactsByContactId)

The InflektPlugin's _manyToManyRelation inflector picks short names
(pluralized target table) and falls back to verbose defaults only when
there is a naming conflict (direct relation to same target, or multiple
m2m paths to the same target).

To opt out for a specific junction table:
  COMMENT ON TABLE post_tags IS E'@behavior -manyToMany';

BREAKING CHANGE: many-to-many fields are now generated by default.
Previously required @behavior +manyToMany on each junction table.
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

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