-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow many_to_many
to order preloads by join table
#4219
Allow many_to_many
to order preloads by join table
#4219
Conversation
What about adding |
That sounds like a good option to me. Do you think we should raise if both Maybe this is overkill, but given ^ do you think we should considering giving users the option to order across the tables with |
How hard would it be to check the columns and, if missing, we assume it is from join? |
It would be contained to a relatively small place. Just this function: https://github.com/elixir-ecto/ecto/blob/master/lib/ecto/repo/preloader.ex#L318 defp preload_order(assoc, query, related_field) do
custom_order_by = Enum.map(assoc.preload_order, fn
{direction, field} ->
{direction, related_key_to_field(query, {0, field})}
field ->
{:asc, related_key_to_field(query, {0, field})}
end)
[{:asc, related_field} | custom_order_by]
end You have the assoc so you can check if it is many to many. And you have the query so you can get the from source. Then I think you'd just need to use the reflection functions to see if the field exist. Like checking if the type is The one issue I can see though is you wouldn't be able to distinguish if both tables had the same column name. |
Yeah, i am not sure what is the best API. :( |
Would it be bad to have pseudo-bindings. For instance:
|
I would avoid adding them at compile-time. Maybe we could allow preload_order as a MFA and in there you should have access to both? |
Sorry if I'm misunderstanding, were you mentioning compile-time due to generating dependencies between modules? If so, what I meant was to have "dummy" bindings. Something like this is supplied by the user:
where I was trying to think of how to use a function too. Though I think we'd have to give them access to modify the entire query rather than generate just the new |
Sorry, what I meant is that extracting a macro expression from an option will be tricky and confusing, especially because none of the other options have macro-like behaviour.
Gah, good point. I guess the best API so far is the one you proposed as |
Yeah let's wait :). |
I was trying to get something like this to work: preload_order: fn -> dynamic([join, assoc], assoc.field) end But couldn't get it to work. I always get compiler errors either about dynamic not existing or the binding not existing. Sorry to bug you but I'm hitting my limits a bit =). Do you know if this is a definite no-no or if there should be something that can make it work? |
I am almost sure it has to be written using MFAs (which is why we use MFAs everywhere). |
I think the MFA works pretty nicely. WDYT of this change? |
Thanks for the discussion/feedback. I finished the changes we talked about . Some callouts:
|
I agree it is not necessary. It is fine to depend on the keyword one for these cases. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added some minor nits, overall it looks great!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one minor nit to do less work inside the quote and ship it!
This was inspired by this comment: #3509 (comment).
It seems useful to be able to order by the join table, especially if you are adding metadata to the relationship.
The proposal here was the best one I could think of. It feels a little awkward having two options but the other ideas I thought of didn't seem too great:
preload_order
seems a bit messy.