如何使用 Ecto 添加互斥约束?
How can I add a mutual exclusion constraint with Ecto?
我有一个包含两个字段的架构,a
和 b
,我希望其中一个字段是必需的。也就是说,如果提供 a
,则不应提供 b
,反之亦然。
有没有办法用 Ecto 变更集验证优雅地表示这一点?像这样:
schema "foo" do
field(:a, :string)
field(:b, :string)
field(:c, :string)
timestamps()
end
def changeset(transaction, attrs) do
transaction
|> cast(attrs, [:a, :b, :c])
|> validate_required([:c])
|> validate_mutual_exclusion([:a, :b])
end
defp validate_mutual_exclusion(changeset, fields) do
# What goes here?
end
您可以计算存在的字段数并检查它是否等于 1:
defp validate_mutual_exclusion(changeset, fields) do
present = Enum.count(fields, fn field -> present?(get_field(changeset, field)) end)
case present do
1 -> changeset # ok
_ ->
# add an error to each field
Enum.reduce(fields, changeset, fn field, changeset ->
add_error(changeset, field, "exactly one of these must be present: #{inspect(fields)}")
end)
end
end
present?
只是检查值是 ""
还是 nil
:
def present?(nil), do: false
def present?(""), do: false
def present?(_), do: true
我有一个包含两个字段的架构,a
和 b
,我希望其中一个字段是必需的。也就是说,如果提供 a
,则不应提供 b
,反之亦然。
有没有办法用 Ecto 变更集验证优雅地表示这一点?像这样:
schema "foo" do
field(:a, :string)
field(:b, :string)
field(:c, :string)
timestamps()
end
def changeset(transaction, attrs) do
transaction
|> cast(attrs, [:a, :b, :c])
|> validate_required([:c])
|> validate_mutual_exclusion([:a, :b])
end
defp validate_mutual_exclusion(changeset, fields) do
# What goes here?
end
您可以计算存在的字段数并检查它是否等于 1:
defp validate_mutual_exclusion(changeset, fields) do
present = Enum.count(fields, fn field -> present?(get_field(changeset, field)) end)
case present do
1 -> changeset # ok
_ ->
# add an error to each field
Enum.reduce(fields, changeset, fn field, changeset ->
add_error(changeset, field, "exactly one of these must be present: #{inspect(fields)}")
end)
end
end
present?
只是检查值是 ""
还是 nil
:
def present?(nil), do: false
def present?(""), do: false
def present?(_), do: true