Hi all,
I’m wondering what the likelihood of acceptance would be for a PR that adds runtime dynamic support to Ecto.Query.preload.
## Context
Right now, preload can accept a keyword list referencing join bindings, allowing a single query to fetch the source resource and the preloaded resource.
from x in SomeSchema,
join: y on assoc(x, :some_assoc),
where: x.value > y.value,
preload: [some_assoc: y]
Even more clever things can be done using lateral joins to, for instance, limit the number of preloaded resources per record.
Additionally, these preloads can nest.
from x in SomeSchema,
join: y on assoc(x, :some_assoc),
join: z on assoc(y, :other_assoc),
where: …,
preload: [some_assoc: {y, other_assoc: z}]
## Problem
It is not appear to be possible to dynamically specify the associations to be preloaded at runtime. To be clear, you cannot do:
from …,
preload: ^some_preloads
where some_preloads references a binding established by an earlier join clause. This is because preload does not accept a dynamic that is able to reference arbitrary bindings.
This makes it difficult to create composable queries with arbitrary preloads without the use of macros, and even that has some limitations.
## Proposal and Discussion
I’d love to see some way to specify a fully dynamic argument to preload. I believe this could be accomplished using the existing dynamic.
preloads = [
foo: {
dynamic([foo: f], f),
bar: dynamic([bar: b], b)
}
]
from …,
preload: ^preloads
I believe Ecto.Query.Builder.Update might be something of a template for this, as update allows for dynamics in this way. Consider this example from the docs:
updates = [
set: [average: dynamic([p], p.sum / p.count)]
]
from query, update: ^updates
Update handles this by differentiating between compile and runtime values (