One thing to consider here is that ecto allows you to attach the preload to the query itself. So instead of doing:
Repo.paginate(query) |> Repo.preload(:user) You can do: query |> Ecto.Query.preload(:user) |> Repo.paginate() and everything will work correctly. Yes, this does not solve all the cases, but should cover the vast majority. Michał. On 21 May 2019, 19:15 +0200, Benjamin Milde <[email protected]>, wrote: > Take for example https://github.com/drewolson/scrivener_ecto > > With a current version of ecto you can happily do this: > > ``` > Repo.all(query) |> Repo.preload(:user) > Repo.one(query) |> Repo.preload(:user) > ``` > > but not this: > > ``` > Repo.paginate(query) |> Repo.preload(:user) > ``` > > Given that doing some work on results of db calls is quite common I tend to > end up with lot's of functions pattern matching if results are > `%Scrivener.Page{}`, a list or an element. Say you also use > https://github.com/duffelhq/paginator for infinite scrolling pages you might > end up with yet another "collection" type struct, which implements Enumerable > so displaying items in views is super easy, but with no simple solution on > how to handle preloads or mappings. > > I've also tried using `Map.update!(elements, :key_of_items, function)` to > normalize stuff down to handling lists for those places using pagination, but > now I'm wrapping a lot of computation in those updates. > > It's also not just mapping, but I might also e.g. want to intersperse items > with separators or zip some additional data into the resultset and still not > lose the pagination information attached to those entries. > > My naive approach was that I can already use Collectable to fill items back > into lists as well as those pagination structs, but while for list and maps > it's easy to use `Enum.into([])` or `Enum.into(%{})` it's not as easy to get > a hold of an empty version of one of those pagination structs. > > I'm not super into all the theoretic types in functional programming. I think > I understand what a functor is, but I'm also not super certain I understand > what you're pointing at. > > Am Dienstag, 21. Mai 2019 18:36:54 UTC+2 schrieb José Valim: > > > All the pagination libs I know for ecto return structs with additional > > > metadata besides the actual results of the db query. Currently one needs > > > to build around those structs specifically to be able to do preloads or > > > other mapping operations or one would loose the metadata. > > > > Can you please provide an example? I am just trying to full understand the > > problem. :) > > > > > Having a `SomeProtocol.empty` protocol we could still use everything > > > provided by Enum (even with it returning a list), but have a way to > > > replace items in the container with the new modified ones > > > > Wouldn't a functor be better suited then? > > > > > > José Valim > > www.plataformatec.com.br > > Skype: jv.ptec > > Founder and Director of R&D > > > > > > > On Tue, May 21, 2019 at 6:34 PM Benjamin Milde <[email protected]> > > > wrote: > > > > All the pagination libs I know for ecto return structs with additional > > > > metadata besides the actual results of the db query. Currently one > > > > needs to build around those structs specifically to be able to do > > > > preloads or other mapping operations or one would loose the metadata. > > > > Having a `SomeProtocol.empty` protocol we could still use everything > > > > provided by Enum (even with it returning a list), but have a way to > > > > replace items in the container with the new modified ones without > > > > manually pattern matching between single results, lists of results or > > > > structs returned because one happens to be using pagination. Monadic > > > > collection types basically don't do it much differently. Extract the > > > > subject out of the container, do computation and replace the old value > > > > when done. I'd imagine `Enumerable` and the potential `SomeProtocol` > > > > would solve a lot of usecases, where people usually ask for Enum to > > > > retain the outer collection type. > > > > > > > > Am Dienstag, 21. Mai 2019 18:14:49 UTC+2 schrieb José Valim: > > > > > My concern is that Collectable.empty cannot be implemented by all > > > > > structs. For example, what does it mean to call empty() on a > > > > > IO.stream? Perhaps it would make sense as a separate protocol? > > > > > > > > > > Also, can you please expand on how Repo.preload could use > > > > > Scrivener.Page in detail? Thanks! > > > > > > > > > > > > > > > José Valim > > > > > www.plataformatec.com.br > > > > > Skype: jv.ptec > > > > > Founder and Director of R&D > > > > > > > > > > > > > > > > On Tue, May 21, 2019 at 5:46 PM Benjamin Milde > > > > > > <[email protected]> wrote: > > > > > > > I've had quite often needs for doing some computation (mapping) > > > > > > > on ecto result, but having a flexible function similar to > > > > > > > `Repo.preload` currently needs a whole bunch of boilerplate in > > > > > > > terms of differenciating collections from single items and > > > > > > > especially returning the same type afterwards (e.g. keep it a > > > > > > > collection or single item). I know that Enumerable and > > > > > > > Collectable were split consciously, but it would be great to have > > > > > > > something like `Collectable.empty/1`, so one could do some work > > > > > > > using `Enum` functions and in the end do: `Enum.into(changed, > > > > > > > Collectable.empty(initial))` and it would empty the collectable > > > > > > > and fill it up again using the changed data. This way the > > > > > > > `Repo.preload` could e.g. additionally support custom enumerable > > > > > > > and collectable collections as first argument like e.g. > > > > > > > `%Scrivener.Page{}`. > > > > > > > -- > > > > > > > You received this message because you are subscribed to the > > > > > > > Google Groups "elixir-lang-core" group. > > > > > > > To unsubscribe from this group and stop receiving emails from it, > > > > > > > send an email to [email protected]. > > > > > > > To view this discussion on the web visit > > > > > > > https://groups.google.com/d/msgid/elixir-lang-core/19c24b83-fc2a-4af3-950e-eba7f767db14%40googlegroups.com. > > > > > > > For more options, visit https://groups.google.com/d/optout. > > > > -- > > > > You received this message because you are subscribed to the Google > > > > Groups "elixir-lang-core" group. > > > > To unsubscribe from this group and stop receiving emails from it, send > > > > an email to [email protected]. > > > > To view this discussion on the web visit > > > > https://groups.google.com/d/msgid/elixir-lang-core/1498525e-30fd-4cde-92a0-4b2e01cdbdf3%40googlegroups.com. > > > > For more options, visit https://groups.google.com/d/optout. > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/5dff9895-1921-4794-89b9-d4ff45578880%40googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/52f1de58-9b8e-49ef-98b3-e0b477dd08ae%40Spark. For more options, visit https://groups.google.com/d/optout.
