TL;DR The problem I’m trying to solve is analogous to building an Ecto.Query, say, for posts that includes n
number of latest associated comments for each.
I realize this has been discussed several times already, but I still have not found a clear solution:
- Preloading top comments for posts in Ecto
- How to address the issue with limits on preloaded associations using Ecto?
- Limit the number of preloaded items
As an example, given the following:
defmodule Comment do
schema "comments" do
belongs_to(:post, Post)
end
end
defmodule Post do
schema "posts" do
has_many(:comments, Comment)
end
defmacrop latest_comments(post_id, limit \\ 5) do
quote do
fragment(
"select * from comments
where comments.post_id = ?
order by comments.inserted_at desc nulls last
limit ?",
unquote(post_id),
unquote(limit)
)
end
end
def with_latest_comments(queryable) do
queryable
|> join(:left_lateral, [p], c in latest_comments(p.id))
|> select_merge([p, c], %{comments: c})
end
end
I think this is so close to a solution, but it raises this error:
PostgreSQL does not support selecting all fields from without a schema. Please specify a schema or specify exactly which fields you want to select in query
If I wrap c
with map or struct e.g.:
|> select_merge([p, c], %{comments: struct(c, [:id, :post_id])})
The following error is raised:
it is not possible to return a map/struct subset of a fragment, you must explicitly return the desired individual fields in query
I see this was discussed here #1592 Ecto.QueryError) PostgreSQL requires a schema module when using selector “u0” but none was given.
The following suggestions were mentioned, either of which I think would work great!
We could also support struct(u, [:foo, :bar, :baz], MyModule)
…
or even struct(u, MyModule) if there are all the columns since the module contains the column names
But alas, that issue is from 2016 and has long been closed.
Any other ideas? Am I missing something obvious?
Thanks!