elixir - 如何将条件管道添加到管道中?

问题描述 投票:0回答:4

我在 Elixir 中有一个小管道,它是关于改变

ecto
模型状态:

model
|> cast(params, ~w(something), ~w())
|> conditional
|> Repo.update

问题是我有

conditional
管道,有时可能为零,所以在为零的情况下它应该什么都不做并且可以工作(我认为它将是
fn(x) -> x end

所以,我的问题是:“我该怎么做”?

elixir ecto
4个回答
25
投票
model
|> cast(params, ~w(something), ~w())
|> maybe_do_something(conditional)
|> Repo.update

defp maybe_do_something(changeset, nil), do: changeset

defp maybe_do_something(changeset, func) do
  # Do something with changeset
end

不确定我是否正确回答了你的问题,但也许这就是你正在寻找的。


9
投票

管道非常适合不会失败的操作,并且所有管道都将始终被携带。如果你想停止管道,你不能。你必须编写这样的函数:

maybe_repo_update(nil), do: nil
maybe_repo_update(data), do: Repo.update(data)

为了解决这个问题,Elixir 1.2 中有一种新的特殊形式,称为

with
。它可以在出现不匹配的情况时停止管道:

with changeset <- cast(model, params, ~w(something), ~w())
  {:ok, changeset} <- conditional_operation(changeset)
  {:ok, model} <- Repo.insert(changeset)

这将确保如果条件操作返回

{:ok, changeset}
以外的内容,它不会尝试运行最后一个存储库插入。在 Elixir 1.3 中,您还可以使用
else
部分。

但是对于变更集,更常见的是使用@JustMichael建议的解决方案:

def conditional(changeset) do
  if something_to_do do
    transform(changeset)
  else
    changeset
  end
end

此解决方案将始终运行

Repo.update
部分。


2
投票

我是 Elixir 新手,所以请不要太严厉:)。

为什么不使用匿名函数来达到此目的?

model
|> cast(params, ~w(something), ~w())
|> (fn(n) -> conditional && n |> Repo.update || n end).()

0
投票

2021 年,Elixir v1.12 推出then/2

借助此功能,我们现在可以轻松地将条件管道插入管道中。

考虑以下代码:

x = ... # true or false

obj
|> foo()
|> bar()

如果您只想在变量

baz/1
的值为
foo/1
时在
bar/1
x
之间运行
true
,您可以重写如下:

x = ... # true or false

obj
|> foo()
|> then(fn obj ->
  if x, do: baz(obj), else: obj
end)
|> bar()

谈到您的案例,您可以写以下内容:

model
|> cast(params, ~w(something), ~w())
|> then(fn changeset ->
  conditional(changeset) || changeset
end)
|> Repo.update

或者更简洁地说:

model
|> cast(params, ~w(something), ~w())
|> then(& conditional(&1) || &1)
|> Repo.update
© www.soinside.com 2019 - 2024. All rights reserved.