Given the following schemas:
schema "artists" do
has_many :albums, Album
has_many :tracks, through: [:albums, :tracks]
end
schema "albums" do
belongs_to Artist
has_many :tracks, Track
end
schema "tracks" do
belongs_to Album
end
The following preloads all the albums and tracks:
Repo.all(from Artist, preload: [albums: :tracks])
But the following doesn’t preload any albums and tracks:
q = from a in Artist, where: a.name == "foobar"
Repo.all(q, preload: [albums: :tracks])
I know I can achieve the goal by using :join
and assoc/3
when building the query, and ignoring the fact that the Repo.all
method requires two queries instead of one, I’m curious why the conditional query doesn’t work the same way as the non-conditional one. I likely have missed it, but is such “discrepancy” documented anywhere?
Thanks in advance.
Repo.all
does not use preload
as an option. What you see in your first example is Repo.all
with one argument (preload
is part of from
). In the second one you are passing preload
as an option in the second argument, but it gets ignored.
3 Likes
Ah, I see. I have the impression that Elixir libraries always flag invalid option keys but not in this case. In any case, thanks!
The Repo query functions accept arbitrary opts, not only for the adapters but also for extensibility. For example, the multi-tenancy guides use an org_id
option to scope queries. It would not be possible to validate the opts for this reason.
Anyway, as you have probably pieced together, you would want to do this:
q = from a in Artist, where: a.name == "foobar"
Repo.all(from q, preload: [albums: :tracks])
Which is of course equivalent to:
Repo.all(from(q, [{:preload, [...]}]))
1 Like
Ah… that’s interesting. Thanks for sharing this nugget.