Насколько я знаю, нет встроенного механизма для обработки пользовательских ошибок PostgreSQL. Однако вы можете сделать это на уровне хранилища.
Чтобы сделать это, вы должны вызвать ошибки в PostgreSQL, используя ERRCODE
, например:
RAISE '[message for logs]' USING ERRCODE = 'integrity_constraint_violation';
, а затем обработать их в приложении:
defmodule Core.Repo do
use Ecto.Repo, otp_app: :core
defoverridable insert: 2
def insert(changeset, opts) do
super(changeset, opts)
rescue
exception in Postgrex.Error ->
handle_postgrex_exception(exception, __STACKTRACE__, changeset)
end
# ... other functions
defp handle_postgrex_exception(exception, stacktrace, changeset \\ nil)
defp handle_postgrex_exception(%{postgres: %{code: :integrity_constraint_violation}}, _, nil) do
{:error, :integrity_constraint_violation}
end
defp handle_postgrex_exception(
%{postgres: %{code: :integrity_constraint_violation}},
_,
changeset
) do
{:error, %{changeset | valid?: false}}
end
defp handle_postgrex_exception(exception, stacktrace, _) do
reraise(exception, stacktrace)
end
end
Обратите внимание на ответ {:error, %{changeset | valid?: false}}
. Это означает, что в этот момент не будет никаких полезных сообщений для отображения.
PS Возможно, вы могли бы написать несколько макросов для переопределения функций Ecto и скрыть реализацию там (вместо предложенного решения), но я считаю, что поддерживать его будет намного сложнее.