Created
April 28, 2019 12:39
-
-
Save sultaniman/696270fbdf71721c8f45abd867682ce8 to your computer and use it in GitHub Desktop.
Ecto helpers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Idp.EctoHelpers do | |
alias Ecto.Changeset | |
@doc """ | |
Transform `%Ecto.Changeset{}` errors to a map | |
containing field name as a key on which validation | |
error happened and it's formatted message. | |
For example: | |
``` | |
%{ | |
"title": "title length should be at least 8 characters" | |
... | |
} | |
``` | |
""" | |
def to_api_errors(%Changeset{} = changeset) do | |
changeset | |
|> format_errors() | |
|> concat_errors() | |
end | |
@doc """ | |
Wrap context actions with Ecto. | |
If action succeeds then the result tuple returned. | |
If changeset errors happen then all errors transformed | |
into convenient form of list of maps with fields on | |
which validations failed. | |
Else `unknown` error returned. | |
""" | |
def action_wrapped(fun) do | |
case fun.() do | |
{:ok, result} -> | |
{:ok, result} | |
{:error, changeset = %Changeset{}} -> | |
{ | |
:error, | |
%{ | |
message: "Changeset errors occurred", | |
code: :schema_errors, | |
errors: to_api_errors(changeset) | |
} | |
} | |
# Case for our standard errors in `IdpWeb.Schema.Errors` | |
{:error, %{code: _}} = error -> | |
error | |
{:error, _} -> | |
{ | |
:error, | |
%{ | |
message: "Oops! Unknown error", | |
code: :oops | |
} | |
} | |
end | |
end | |
# Extract and interpolate all errors from | |
# `Changeset.errors` and return a map. | |
defp format_errors(%Changeset{} = changeset) do | |
Changeset.traverse_errors(changeset, fn {msg, opts} -> | |
Enum.reduce(opts, msg, fn {key, value}, formatted_msg -> | |
formatted_msg |> String.replace("%{#{key}}", to_string(value)) | |
end) | |
end) | |
end | |
# Get all errors from `format_errors/1` and | |
# join their messages into a single string | |
# separated by "," | |
defp concat_errors(errors) do | |
Enum.reduce(errors, errors, fn {key, value}, map -> | |
map |> Map.put(key, Enum.join(value, ", ")) | |
end) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment