Как условно сократить набор изменений с помощью операторов Enum, а не If - PullRequest
0 голосов
/ 08 февраля 2019

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

У меня есть ощущение, что есть функция Enum (например, Reduce), которая делает это таким образом, который является идиоматически более эликсиром, но ничего из того, что я придумала, не является более производительным, чем тонна уродливых. Еслизаявления.

 def encrypt(changeset) do
    if changeset.changes["address"] do
      {:ok, encrypted_address} = EncryptedField.dump(changeset.changes.address, key_id)
      changeset
      |> put_change(:address, encrypted_address)
    end
    if changeset.changes["dob"] do
      {:ok, encrypted_dob} = EncryptedField.dump(changeset.changes.dob, key_id)
      changeset
      |> put_change(:address, encrypted_dob)
    end
    if changeset.changes["email"] do
      {:ok, encrypted_email} = EncryptedField.dump(changeset.changes.email, key_id)
      changeset
      |> put_change(:email, encrypted_email)
    end
   ...
 end

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Согласитесь с ответом Алексея.

Еще один паттерн в эликсире заключается в том, что если у вас есть серия проверок перед запуском выражения, вы можете использовать with.

Код Алексея с использованием with будет выглядеть примерно так:

def encrypt(changeset) do
  ~w[address dob email] |> Enum.reduce(changeset, fn field ->
    with \
      true <- Map.has_key?(changeset.changes, field),
      {:ok, encrypted} <- EncryptedField.dump(changeset.changes[field], key_id)
    do
      put_change(changeset, field, encrypted)
    else
      _ -> changeset
    end
  end)
end

Здесь, если EncryptedField.dump возвращает :error, вместо набора исключений, если вы делаете * 1012, возвращается набор изменений*.

PS: также рекомендуем использовать Map.has_key?

0 голосов
/ 08 февраля 2019

Все, что вам нужно, это перебирать поля, условно обновляя набор изменений:

def encrypt(changeset) do
  Enum.reduce(~w[address dob email]a, changeset, fn field, changeset ->
    if changeset.changes[field] do
      {:ok, encrypted} =
        EncryptedField.dump(changeset.changes[field], key_id)
      put_change(changeset, field, encrypted)
    else
      changeset # unlike your implementation this works
    end
  end)
end

Другим способом было бы Enum.filter/2 полей в первую очередь:

def encrypt(changeset) do
  ~w[address dob email]a
  |> Enum.filter(&changeset.changes[&1])
  |> Enum.reduce(changeset, fn field, changeset ->
    {:ok, encrypted} =
      EncryptedField.dump(changeset.changes[field], key_id)
    put_change(changeset, field, encrypted)
  end)
end

Sidenote: в соответствии с руководящими указаниями основной команды, трубы должны использоваться, если в цепи много звеньев.


Ответ на второй ответ:

Идиоматический код с использованием with будет:

def encrypt(changeset) do
  ~w[address dob email] |> Enum.reduce(changeset, fn field ->
    with %{^field => value} <- changeset.changes,
          {:ok, encrypted} <- EncryptedField.dump(value, key_id)
    do
      put_change(changeset, field, encrypted)
    else
      _ -> changeset
    end
  end)
end
...