Hi all, I’ve encountered a situation I’m having trouble implementing elegantly using Ecto. I have three tables in my schema which comprise one supertype and two subtypes. The supertype is a Plan which can be either a Match Plan or a Fixed Plan, not both.
Supertype: Plan
schema "plan" do
belongs_to: :frequency, Frequency
has_one: :match_plan, MatchPlan
has_one: :fixed_plan, FixedPlan
end
Subtypes: MatchPlan, FixedPlan
# Unique index on :percentage and :limit (DATABASE CONSTRAINT)
schema "match_plan" do
belongs_to :plan, Plan
:percentage, :decimal
:limit, :decimal
end
# Unique index on :amount (DATABASE CONSTRAINT)
schema "fixed_plan" do
belongs_to :plan, Plan
:amount, :decimal
end
My challenge is creating a plan that I pair with a user to create a UserPlan. But I need to accommodate the constraint on the subtypes when creating a plan. I don’t see how this can be done without two Ecto.Multis:
# First Multi
def create_user_plan(user, params) do
Multi.new()
|> Multi.run(:plan, &maybe_insert_plan(&1, params))
|> Multi.run(:user_plan, &insert_user_plan(&1, user))
|> Repo.transaction()
end
def maybe_insert_plan(params) do
case insert_plan(params) do
{:ok, %{plan: plan}} ->
{:ok, plan}
{:error, _, _, _} ->
{:ok, lookup_plan(params)}
end
end
# Second Multi
def insert_plan(params) do
Multi.new()
|> Multi.run(:frequency, &get_frequency(&1, params))
|> Muti.run(:plan, &insert_plan/1)
|> Multi.run(:plan_subtype, &insert_plan_subtype(&1, params)) # This is the function that will raise the unique constraint error
|> Repo.transaction()
end
Is there are more idiomatic way to handle situations like these?