assoc vs. ids: should contexts reach into other contexts?
stevegrossi opened this issue Β· comments
assoc
def list_habits(%Account{} = account) do
account
|> assoc(:habits)
|> Repo.all()
end
- Requires
import Ecto, only: [assoc: 2]
- π Pattern-matching (optional, but ideal) requires reference to another context's schema,
Accounts.Account
ids
def list_habits(account_id) when is_integer(account_id) do
account
|> where(account_id: ^account_id)
|> Repo.all()
end
- Requires
import Ecto.Query
- π A tiny bit more efficient, since we only need the ID from the database, not the full record
- π Requires duplicating (potentially complex, with joins) relationship logic
In-Context associations?
Inspired by this forum post.
def list_habits(account_id) when is_integer(account_id) do
%Habits.Account{id: account_id} # not Accounts.Account
|> assoc(:habits)
|> Repo.all()
end
# which requires
defmodule Habits.Habits.Account do
use Ecto.Schema
schema "accounts" do
has_many(:habits, Habit)
end
end
- π Avoids potential duplication of the account <-> habits association logic within this context
- π
Habits.Account
could be anything, potentially more context-specific likeHabits.Owner
- π A tiny bit more efficient, since we only need the ID from the database, not the full record
- π Another file?
I'm very curious about the "In-Context associations?" option, which seems to fulfill the promise of bounded contexts (though I know Phoenix contexts aren't explicitly an implementation of DDD's bounded context pattern). In that direction, it would be interesting to have a rule that no context may reference modules within another context. I like that idea in theory, I'm just curious how it would play out in practice.
This post details an interesting approach similar to "In-Context associations", but instead of only passing IDs between contexts, you can also pass _map_s (but not structs, which are domain-specific) between contexts.