Skip to content

fix: report the primary key in the combination fieldset - #2836

Merged
zachdaniel merged 2 commits into
ash-project:mainfrom
matt-beanland:fix/ets-combination-requires-primary-key
Aug 4, 2026
Merged

fix: report the primary key in the combination fieldset#2836
zachdaniel merged 2 commits into
ash-project:mainfrom
matt-beanland:fix/ets-combination-requires-primary-key

Conversation

@matt-beanland

@matt-beanland matt-beanland commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Contributor checklist

Leave anything that you believe does not apply unchecked.

  • I accept the AI Policy, or AI was not used in the creation of this PR.
  • Bug fixes include regression tests
  • Chores
  • Documentation changes
  • Features include unit/acceptance tests
  • Refactoring
  • Update dependencies

Closes #2835

Summary

Reworked based on guidance from review of #2835

Now the primary key is always selected, so the fix is to make the combination fieldset say so.

Cause

select/3 already adds the primary key and the always-selected attributes to every select
(lib/ash/query/query.ex:1702-1705), and each combination part is built through it. But the
fieldset was built from the raw select: on the combination, not from the query select/3
produced, so it under-reported what the parts select. For a part with select: [:region]:

raw combination.select [:region]
what select/3 makes of it [:id, :region]
combination_fieldset [:region]

The change

Derive the fieldset through select/3, so it cannot disagree with the queries that function
builds. Always-selected attributes are now reported too, for the same reason.

Nothing in a data layer changes. Ash.DataLayer.Ets keys its dedupe off the built query's select
rather than the fieldset, which is why it kept records distinct already.

Commits

  1. test: pin that a union of narrowly selected parts keeps records distinct Passes as is.
  2. fix: derive the fieldset through select/3, and assert the primary key is in it.

Two records that agree on every field a combination selects are still two
records, because they differ on the primary key and `select/3` always selects
it. Nothing pinned that, so a change to how the combination fieldset is derived
could start collapsing them.

Passes against unmodified code.
`select/3` always selects the primary key and any always-selected attributes,
so every combination query has them regardless of what its `select:` asked for.
The fieldset handed to the data layer was built from that raw `select:` instead,
so it under-reported what the parts actually select.

Derive it through `select/3`, which is what builds the part queries, so the two
cannot disagree.

The fieldset is what a data layer uses to decide which fields the combination
makes available. Under-reporting the primary key tells it a field is absent from
a query that does select it — in `ash_sql` that reaches `maybe_subquery_upgrade`,
which treats any reference outside the fieldset as requiring a join.
@matt-beanland
matt-beanland force-pushed the fix/ets-combination-requires-primary-key branch from 62de026 to 5046bb8 Compare August 4, 2026 15:39
@matt-beanland matt-beanland changed the title feat: refuse an ETS combination whose select omits the primary key fix: report the primary key in the combination fieldset Aug 4, 2026
@zachdaniel
zachdaniel merged commit 7f977ef into ash-project:main Aug 4, 2026
51 checks passed
@zachdaniel

Copy link
Copy Markdown
Contributor

🚀 Thank you for your contribution! 🚀

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.

Combinations report a fieldset without the primary key, though every part selects it

2 participants