fix: sort a ranked union in ETS, not only a ranked union_all - #2828
Merged
zachdaniel merged 2 commits intoAug 3, 2026
Conversation
`combinations` documents ranking parts with a calculation and sorting the combined result by it. Nothing pinned that the sort actually happens. Add the three-part shape the docs describe — one record reached by three parts that each rank it differently — parameterised on the combination type so the same helper can be pointed at other types. Passes as-is for `union_all`; it characterises today's behaviour.
`maybe_not_distinct?` told `Ash.Actions.Sort.runtime_sort/3` whether a
combination fold could return the same primary key twice, and it was set for
`union_all` alone. A `union` does it too: the equality basis is the
combination fieldset, so parts carrying different combination calculations
keep both copies — deliberately, and that is exactly the ranked shape the
combinations guide documents.
Without the flag, `runtime_sort/3` loads sort keys in batches, which cannot
resolve two records sharing a primary key into two records. The key was
mis-assigned and the sort silently did nothing: three parts ranking one
record 1, 2, 3 and sorted descending came back `[1, 2, 3]` under `union` and
`[3, 2, 1]` under `union_all`.
Widen the condition to any part carrying combination calculations.
Note the calculations are a map, not a list, so the emptiness test has to be
`Enum.empty?/1` — comparing against `[]` is true for `%{}` and would force
every combination query onto the unbatched path.
Contributor
|
🚀 Thank you for your contribution! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Contributor checklist
Leave anything that you believe does not apply unchecked.
Summary
Fixes #2827 .
Sorting by a combination calculation did nothing when the parts were joined with
union. Thesame query with
union_allsorted correctly. One record, reached by three parts ranking it1/2/3, sorted descending:
That is the ranked shape the combinations guide documents. Repro in the issue.
Cause
run_query/3inlib/ash/data_layer/ets/ets.extellsAsh.Actions.Sort.runtime_sort/3whetherthe fold can return the same primary key twice:
runtime_sort/3usesmaybe_not_distinct?when choosing how to load the sort key — batched, or one record at a time. The batched branch cannot resolve two records sharing a primary key into two records, so the keyis mis-assigned and the sort silently does nothing.
The condition is too narrow.
union_allis not the only way to get a repeated primary key: for aunionthe equality basis is the combination fieldset, so parts carrying different combinationcalculations keep both copies.
Now widening to any part carrying combination calculations:
Ash.Query.Combination'scalculationsdefaults to%{}, so the emptiness test has to beEnum.empty?/1. Comparing against[]istruefor%{}, which would set the flag for everycombination query and put them all on the unbatched path.
Commits
test:pin the ranked three-part shape from the guide, asserted forunion_all- passes as-is.fix:widen the condition, and assert the same result forunion.