你好,我收到一个值,这个值不能是负的,只能是正的,如果它是负的,我想返回一个自定义错误,如果它是负的,继续到管道。
我现在有这个:
def call(%{"id" => id, "value" => value}, operation) do
Multi.new()
|> Multi.run(:account, fn repo, _changes -> get_account(repo, id) end)
|> Multi.run(:update_balance, fn repo, %{account: account} ->
update_balance(repo, account, value, operation)
end)
end
defp update_balance(repo, account, value, operation) do
account
|> operation(value, operation)
|> update_account(repo, account)
end
defp operation(%Account{balance: balance}, value, operation) do
value
|> Decimal.cast()
|> handle_cast(balance, operation)
end
defp handle_cast({:ok, value}, balance, :deposit), do: Decimal.add(balance, value)
defp handle_cast({:ok, value}, balance, :withdraw), do: Decimal.sub(balance, value)
defp handle_cast(:error, _balance, _operation), do: {:error, "Invalid operation!"}
虽然@sbacarob的答案是完全正确的,但为了方便起见,我还是把这个贴出来。
Decimal
是一个普通结构体,因此可以使用它的内部结构来处理带有保护的负结构。这将适用于Elixir≥1.11和OTP≥23的现代版本。
defguard is_decimal_positive(value)
when is_map(value) and
value.__struct__ == Decimal and
value.sign == 1
参见Kernel.defguard/1
。并使用
defp operation(%Account{balance: balance}, value, operation) do
value
|> Decimal.cast()
|> handle_cast(balance, operation)
end
defp handle_cast({:ok, value}, balance, _)
when is_decimal_positive(value),
do: Decimal.add(balance, value)
defp handle_cast(_error, _balance, _),
do: {:error, "Number must be positive decimal"}
正如我在上一条评论中提到的, 幸运的是, 这样,如果它是负数,它将从Decimal
是一个不同的"类型",它大于整数。Decimal
提供了gt?
,lt?
和compare
函数,您可以使用它们将Decimal
s与整数进行比较。为了尽可能少地修改代码,一个比较干净的解决方案是在handle_cast
之前添加一个小的额外函数,并为handle_cast
添加另一个定义。像这样:defp operation(%Account{balance: balance}, value, operation) do
value
|> Decimal.cast()
|> maybe_positive?()
|> handle_cast(balance, operation)
end
defp maybe_positive?({:ok, value}) do
case Decimal.compare?(value, 0) do
:lt -> {:error, :negative_number}
:gt -> {:ok, value}
end
end
defp maybe_positive?(error), do: error
defp handle_cast({:error, :negative_number}, _balance, _operation) do
{:error, "Number must be positive"}
end
defp handle_cast({:ok, value}, balance, :deposit), do: Decimal.add(balance, value)
...
handle_cast
中通过{:error, :negative_number}
的情况,如果它是正数或cast
由于某种原因失败,它将通过您已经拥有的其他handle_cast
验证