Disons que j'ai un module pour l'utilisateur et il a 2 fonctions qui acceptent un changeset et ajouter des modifications, comme celui-ci ->La réduction de plusieurs chainable update_all appels en une seule instruction UPDATE
defmodule MyApp.User do
def confirm(changeset_or_struct) do
changeset_or_struct
|> Ecto.Changeset.change(confirmed: true, confirmed_at: Timex.now())
end
def update_session(changeset_or_struct, ip_address) do
changeset_or_struct
|> Ecto.Changeset.change(session_token: "token", ip_address: ip_address)
end
end
Alors si je dois appliquer ces deux changements à un utilisateur spécifique et de les enregistrer, je peux facilement enchaîner les appels de fonction comme celle-ci
some_user
|> User.confirm()
|> User.update_session("ip_address")
|> Repo.update!()
il est tout bon. Maintenant, disons que pour une raison quelconque, j'ai besoin de confirmer et de mettre à jour la session pour un grand nombre d'utilisateurs en même temps d'une manière atomique. Évidemment, obtenir tous ces utilisateurs, les verrouiller et ensuite les mettre à jour un par un dans une transaction n'est pas une très bonne option, donc nous devons utiliser la fonction update_all
pour envoyer une seule instruction UPDATE
.
donc ce que nous avons besoin est ce ->
User
|> Repo.update_all([set: confirmed: true, confirmed_at: Timex.now(), session_token: "token", ip_address: "ip_address"])
Mais appeler ce code à l'extérieur du module User
ne semble pas être une bonne idée parce que je veux que le module User
de savoir comment gérer la confirmation et mises à jour de sessions. Donc la prochaine décision évidente est de créer une fonction dans le module User
et de mettre ce code là mais le problème est qu'il n'est pas flexible car ces deux actions (confirmation et mise à jour de session) sont couplées maintenant. Mais nous pouvons tout casser en 2 fonctions
def confirm_many(query) do
query
|> Repo.update_all([set: confirmed: true, confirmed_at: Timex.now()])
end
def update_session_many(query, ip_address) do
query
|> Repo.update_all([set: session_token: "token", ip_address: ip_address])
end
Et même si maintenant ils ne sont pas accouplées maintenant, mais ni ils sont chainable si bien que je peux utiliser ces deux séparément, très probablement, je vais finir avec un morceau laid de code et un tas de UPDATE
déclarations quand il pourrait facilement être réduit à un seul. Alors maintenant la question:
Comment ferais-je cela? Existe-t-il un moyen d'enchaîner un tas de mises à jour indépendantes qui pourraient éventuellement être réduites à un seul appel update_all
?
Ainsi, la ligne de fond est que je voudrais être en mesure de faire quelque chose comme ceci:
User
|> where([u], u.id in bunch_of_ids)
|> User.confirm_many()
|> User.update_session_many("ip_address")
|> Repo.update_all()