Как вызвать пользовательскую ошибку Postgresql и обработать ее в Ecto - PullRequest
0 голосов
/ 02 ноября 2018

Я создал пользовательскую функцию в Postgresql, которая проверяет данные перед вставкой или обновлением и выдает ошибку, если что-то идет не так.

CREATE FUNCTION custom_check() RETURNS TRIGGER AS $$
  BEGIN
    IF <SOME CONDITION> THEN
        RAISE EXCEPTION 'CUSTOM ERROR';
    END IF;
    RETURN NEW;
  END;
  $$ LANGUAGE plpgsql
""")

Когда я использую ограничения в Postgresql, я могу обрабатывать ошибки, возникающие с Ecto.Changeset.check_constraint.

Но я не нашел способа справиться с этой ошибкой, которую я поднимаю, чтобы отразить ее в наборе изменений вместо того, чтобы получить исключение и, вероятно, перехватить его внутри моего кода.

Должен ли я вызывать ошибку по-другому, чтобы Ecto.Changeset.check_constraint справился с ней, или сделать что-то еще?

1 Ответ

0 голосов
/ 12 ноября 2018

Насколько я знаю, нет встроенного механизма для обработки пользовательских ошибок 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 и скрыть реализацию там (вместо предложенного решения), но я считаю, что поддерживать его будет намного сложнее.

...