How to raise custom Postgresql error and handle it in Ecto

耗尽温柔 提交于 2020-01-24 22:52:27

问题


I created a custom function in Postgresql that checks data before insert or update and raises error if something goes wrong.

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

When I'm using constraints in Postgresql, I can handle errors raised with Ecto.Changeset.check_constraint.

But I didn't find a way to handle this error I'm raising, to reflect it in changeset instead of getting an exception and probably catching it inside my code.

Should I raise error differently for Ecto.Changeset.check_constraint to handle it, or do differently something else?


回答1:


As far as I know, there is no built-in mechanism for handling custom PostgreSQL's errors. However, you can do it at the repository level.

To do that, you have to raise errors in the PostgreSQL using ERRCODE like:

RAISE '[message for logs]' USING ERRCODE = 'integrity_constraint_violation';

and then handle them in the application:

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

Note the {:error, %{changeset | valid?: false}} response. It means that at that point, there won't be any useful message to display.

PS you could probably write some macros to override Ecto's functions and hide the implementation there (instead of the proposed solution) but I believe it would be much harder to maintain.



来源:https://stackoverflow.com/questions/53122256/how-to-raise-custom-postgresql-error-and-handle-it-in-ecto

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!