Created
December 28, 2021 16:07
-
-
Save moroz/fd107b61cd9e8482169738ca62ce3f50 to your computer and use it in GitHub Desktop.
Lazy preloading Ecto associations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| defmodule MyAppWeb.Api.Middleware.LazyPreload do | |
| @moduledoc """ | |
| Absinthe middleware to preload Ecto associations only if they have | |
| been requested. | |
| """ | |
| require Absinthe.Schema.Notation | |
| defmacro lazy_preload(assoc_name) do | |
| quote do | |
| middleware(unquote(__MODULE__), unquote(assoc_name)) | |
| end | |
| end | |
| @behaviour Absinthe.Middleware | |
| alias MyApp.Repo | |
| def init(_), do: nil | |
| def call(%{source: source} = res, assoc_name) when is_atom(assoc_name) do | |
| value = | |
| case Map.get(source, assoc_name) do | |
| %Ecto.Association.NotLoaded{__cardinality__: :one} -> | |
| Repo.one(Ecto.assoc(source, assoc_name)) | |
| %Ecto.Association.NotLoaded{} -> | |
| Repo.all(Ecto.assoc(source, assoc_name)) | |
| nil -> | |
| nil | |
| %_module{} = struct -> | |
| struct | |
| list when is_list(list) -> | |
| list | |
| end | |
| %{res | value: value, state: :resolved} | |
| end | |
| def call(%{source: source} = res, [{assoc_name, _}] = list) do | |
| preloaded = Repo.preload(source, list) | |
| value = Map.get(preloaded, assoc_name) | |
| %{res | value: value, state: :resolved} | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment