Skip to content

Make the :preload_order option in Ecto.Schema.has_many/3 not take precedence over custom preload queries - #4675

Merged
josevalim merged 2 commits into
elixir-ecto:masterfrom
DefactoSoftware:master
Oct 23, 2025
Merged

josevalim merged 2 commits into
elixir-ecto:masterfrom
DefactoSoftware:master

Conversation

@tarzan

@tarzan tarzan commented Oct 23, 2025

Copy link
Copy Markdown
Contributor

fixes #4535

Sorry about the whitespace changes - mix formatter automatically runs in my editor, do I need to revert those changes?

Key Changes:

Core Implementation (lib/ecto/repo/preloader.ex)

Added a new clause to the add_preload_order/2 function that checks if the query already has order_by clauses:

defp add_preload_order([], query), do: query

defp add_preload_order(_order, %{order_bys: [_|_]} = query) do
  # Skip applying preload_order when query already has custom order_by clauses
  query
end

This ensures that when a custom query with its own ordering is provided, the :preload_order is not applied, allowing the custom order to take precedence.

Documentation Updates (lib/ecto/schema.ex)

Updated the documentation for :preload_order in both has_many/3 and many_to_many/3 to clarify the new behavior:

  • Added a note explaining that custom query order_by clauses take precedence over :preload_order
  • This applies to both association types

Test Coverage (integration_test/cases/preload.exs)

Added a comprehensive test case (custom query order_by overrides preload_order) that verifies:

  • Without a custom query, :preload_order is applied (ascending order by text)
  • With a custom query having order_by, the custom order takes precedence (descending order by text)

Changelog (CHANGELOG.md)

Added an entry documenting this enhancement for the next release.

@josevalim

Copy link
Copy Markdown
Member

The integration tests are failing, can you please take a look?

     +integration-test *failed* |   1) test custom query order_by overrides preload_order (Ecto.Integration.PreloadTest)
     +integration-test *failed* |      /src/ecto/integration_test/cases/preload.exs:698
     +integration-test *failed* |      ** (ArgumentError) schema Ecto.Integration.Post does not have association or embed :force
     +integration-test *failed* |      code: post = TestRepo.preload(post, ordered_comments: query, force: true)
     +integration-test *failed* |      stacktrace:
     +integration-test *failed* |        (elixir 1.17.3) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
     +integration-test *failed* |        /src/ecto/integration_test/cases/preload.exs:711: (test)

@warmwaffles

Copy link
Copy Markdown
Member

Are the formatting changes necessary to shim into this pr?

@josevalim

Copy link
Copy Markdown
Member

@tarzan I have formatted those files on main, so you can rebase and it should keep the PR tiny!

@tarzan

tarzan commented Oct 23, 2025

Copy link
Copy Markdown
Contributor Author

The integration tests are failing, can you please take a look?

     +integration-test *failed* |   1) test custom query order_by overrides preload_order (Ecto.Integration.PreloadTest)
     +integration-test *failed* |      /src/ecto/integration_test/cases/preload.exs:698
     +integration-test *failed* |      ** (ArgumentError) schema Ecto.Integration.Post does not have association or embed :force
     +integration-test *failed* |      code: post = TestRepo.preload(post, ordered_comments: query, force: true)
     +integration-test *failed* |      stacktrace:
     +integration-test *failed* |        (elixir 1.17.3) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
     +integration-test *failed* |        /src/ecto/integration_test/cases/preload.exs:711: (test)

This should be fixed now.

I rebased the code as well.

Can you re-run the workflow?

@josevalim
josevalim merged commit 54a10ee into elixir-ecto:master Oct 23, 2025
7 checks passed
@josevalim

Copy link
Copy Markdown
Member

💚 💙 💜 💛 ❤️

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.

Schema preload_order cannot be overriden by passing ordered query

3 participants