@doc """
Preload the associations in a database result.
It accepts the following types of result:
- `{:ok, struct}` where `struct` is an ecto schema
- `{:error, changeset}` where `changeset` is a changeset
This function is optimized to process the results of operations such as
`c:Repo.insert/1` and `c:Repo.update/1`.
"""
def preload_in_result({:ok, struct}, repo, preloads) do
{:ok, repo.preload(struct, preloads)}
end
def preload_in_result({:error, changeset}, repo, preloads) do
{:error, preload_in_changeset(changeset, repo, preloads)}
end
@doc """
Preload the associations in a changeset
"""
def preload_in_changeset(changeset, repo, preloads) do
preload_in_changeset_helper(changeset, repo, preloads)
end
defp preload_in_changeset_helper(%Ecto.Changeset{} = changeset, repo, preloads) do
# Preloading the data is very easy, because the data
# is usually a struct already
new_data = repo.preload(changeset.data, preloads)
# Handling changes is harder.
# We'll have to create a fake changeset.
schema = changeset.data.__meta__.schema
changes = changeset.changes
# Create a "fake" struct so that we can preload the assocs.
changes_struct = struct(schema, changes)
changes_preloaded = repo.preload(changes_struct, preloads)
preloaded_assocs = Map.take(changes_preloaded, preloads)
merged_changes = Map.merge(changes, preloaded_assocs)
# Update the data and the changesets
%{changeset | data: new_data, changes: merged_changes}
end
defp preload_in_changeset_helper(list_of_changesets, repo, preloads)
when is_list(list_of_changesets) do
Enum.map(list_of_changesets, fn changeset ->
preload_in_changeset_helper(changeset, repo, preloads)
end)
end
as