Ограничения
Как показано в этом вопросе SO , для удовлетворения ограничений 1 и 2 вы можете использовать что-то вроде:
create constraint(:table, :valid_pair, check: "
(
( CASE WHEN column_a IS NULL THEN 0 ELSE 1 END
+ CASE WHEN column_b IS NULL THEN 0 ELSE 1 END
+ CASE WHEN column_c IS NULL THEN 0 ELSE 1 END
+ CASE WHEN column_d IS NULL THEN 0 ELSE 3 END
+ CASE WHEN column_e IS NULL THEN 0 ELSE 3 END
+ CASE WHEN column_f IS NULL THEN 0 ELSE 3 END
) = 4
)")
Есть некоторая двусмысленность с ограничением 3, вы имеете в виду, что только один раз могут column_a
и column_f
быть вместе, или что их значения должны быть уникальными?
Для [column_a, column_b, column_c, column_d, column_e, column_f]
: оба эти транзакции действительны или только одна?
[1, NULL, NULL, NULL, NULL, NULL, 1]
[1, NULL, NULL, NULL, NULL, NULL, 2]
Если последнее, то:
create unique_index(:table, [:column_a, :column_b, :column_c, :column_d, :column_e, :column_f], name: :unique_pairing)
Changesets
Для ограничений 1 и 2 я бы сделал две пользовательские проверки, которые подсчитывают количество ненулевых значений из каждого подмножества столбцов. Эти проверки выполняются до попадания в базу данных. Хорошая запись: Больше пользовательских проверок для Ecto Changesets
changeset
...
|> validate_column_sets([column_a, column_b, column_c], :column_set_a)
|> validate_column_sets([column_d, column_e, column_f], :column_set_b)
defp validate_column_sets(changeset, fields, key) do
case changeset.valid? do
true ->
case Enum.count(fields, fn field -> get_field(changeset, field) != nil end) do
1 -> changeset
_ -> add_error(changeset, key, "Only one column in this set can be nil")
_ ->
changeset
end
end
Для ограничения 3 вы можете упростить задачу и использовать unique_constraint/3
с произвольным столбцом. См. Обсуждение здесь: Ecto Changeset unique_constraint/3
для кластерного индекса
|> unique_constraint(:column_a, name: :letters_unique_index)
Надеюсь, что вы попадете на правильный путь!