Support preloading associations in embedded schemas from the parent schema#3967
Support preloading associations in embedded schemas from the parent schema#3967greg-rychlewski merged 17 commits intoelixir-ecto:masterfrom
Conversation
produces teh same error message
Also extends tests a little bit to make sure some general preload patterns are met
|
Added all requested changes. Offtopic: I am listening to the Thinking Elixir Podcast and learning some interesting tidbits from the Elixir Review conversations @josevalim 😁 |
|
edit: nm I was being a newb. this is how it works for regular assocs too |
Co-authored-by: Greg Rychlewski <greg.rychlewski@gmail.com>
|
@greg-rychlewski is this good to you? :) |
|
oh not yet sorry. they are still working on batching the |
|
had to leave this on hold for a while, taking more stabs at it every now and then though |
|
yep this is proving difficult with the given requirements so it will take awhile longer but I think I'm on the right path, the thing is I need to wire the Sorry if that doesn't make sense, it is WIP |
|
How come From what I can tell the only missing part is mimicking this part of all = preload_each(Enum.reverse(loaded_structs, fetch_structs), repo_name, preloads, tuplet)
entry = {:assoc, assoc, assoc_map(assoc.cardinality, Enum.reverse(loaded_ids, fetch_ids), all)}
[entry | preload_assocs(assocs, queries, repo_name, tuplet)]
|
|
Something like this: defp preload_embeds(structs, [], _repo_name, _tuplet), do: structs
defp preload_embeds(structs, [embed | embeds], repo_name, tuplet) do
{%{field: field}, sub_preloads} = embed
embeds = Enum.map(structs, &Map.get(&1, field)) |> preload_each(repo_name, sub_preloads, tuplet)
structs = Enum.zip(structs, embeds) |> Enum.map(fn {struct, embed} -> Map.put(struct, field, embed) end)
preload_embeds(structs, embeds, repo_name, tuplet)
endSorry not optimized or tested but this is the gist of what I was thinking. You will also have to keep track of how many embedded structs there are per parent struct in case of edit: Or maybe even nicer, to be the same as assocs, for struct <- structs do
struct = Enum.reduce assocs, struct, &load_assoc/2
struct = Enum.reduce throughs, struct, &load_through/2
struct = Enum.reduce embeds, struct, &load_embed/2
struct
endI don't think parent has to have a primary key in case it only has embeds and no direct assocs. So |
|
this line in Right? Because you were telling me how |
|
I might not have explained myself properly. What I meant was that you extract the embeds from the parent structs and then pass just the list of embeds into |
Don't worry, it's probably on me.
Sort of, current implementation is more similar to this:
It is exactly that, passing the embeds themselves into So, if you don't mind, can we come back to the previous comment again? You mentioned that current implementation ties up more DB connections than needed:
How does this happen? Lets say we have Should it instead call |
Yeah this is exactly what I was trying to propose here: #3967 (comment). So you call |
|
Ah, perfect! Thanks 😁 I misunderstood at first and thought all embeds had to be loaded on the same connection as the other assocs. Oops! |
|
Hi! I think I got it (crossing fingers), one thing I did not have to do is deal with any Other than that I believe this is now calling |
By calling `prealod_each` once per unique `Ecto.Embedded` in `structs`.
|
Do you have any tips for debugging elixir? I have been print-debugging every time I run the integration tests but it feels so clunky, I know |
Make the list of embeds more uneven
|
Thanks @Sleepful this is looking great. I just had 2 smalls suggestions for the unit test and one suggestion to refactor
It looks like this was my confusion. I assumed
Sorry I'm pretty newb/lazy about tooling and don't really do anything special. But @josevalim might have some more information about this. |
Per Code Review: - Iterates less times over `structs` - Handles `nil` case for embeds_one - Removes async_stream, db connection strategy more consistent (and less hungry) Co-authored-by: Greg Rychlewski <greg.rychlewski@gmail.com>
Per code review: - Scramble test data a little bit - Remove unnecesary TestRepo.insert! statements Co-authored-by: Greg Rychlewski <greg.rychlewski@gmail.com>
Unsure if this is possible but types may be tricky: https://hexdocs.pm/ecto/Ecto.Query.API.html#json_extract_path/2-warning-return-types
Like so: Repo.preload([struct, nil, struct]) Co-authored-by: Greg Rychlewski <greg.rychlewski@gmail.com>
|
Thanks @Sleepful, great work!. |
|
Awesome job @Sleepful with the code and @greg-rychlewski with the reviews! ❤️ |
Implements enhancement #3890
Re-submission of #3965
Might add more tests later