adding for update to a read action

I have an after_action block that performs a select using a read action. I'd like to turn that select into a "SELECT FOR UPDATE" - is that possible?
22 Replies
rohan
rohanOP2y ago
Nm! The answer was to use modify_query on the read transaction and then use Ecto.Query.lock("FOR UPDATE")
ZachDaniel
ZachDaniel2y ago
You can use Ash.Query.lock(query, :for_update)
rohan
rohanOP2y ago
sorry I might be being slow here, but how do I use this within a read action block eg.
read :get_processed_by_index do
# NOTE(rohan): We need FOR UPDATE so we are sure that it's not about to be marked as processed after we read it
modify_query {Scribble.Scribe.AudioFile, :add_for_no_key_update, []}
transaction? true


end
read :get_processed_by_index do
# NOTE(rohan): We need FOR UPDATE so we are sure that it's not about to be marked as processed after we read it
modify_query {Scribble.Scribe.AudioFile, :add_for_no_key_update, []}
transaction? true


end
ZachDaniel
ZachDaniel2y ago
You can use a preparation
read :get_processed_by_index do
# NOTE(rohan): We need FOR UPDATE so we are sure that it's not about to be marked as processed after we read it
# modify_query {Scribble.Scribe.AudioFile, :add_for_no_key_update, []}
prepare fn query, _ -> Ash.Query.lock(query, :for_update) end
transaction? true
end
read :get_processed_by_index do
# NOTE(rohan): We need FOR UPDATE so we are sure that it's not about to be marked as processed after we read it
# modify_query {Scribble.Scribe.AudioFile, :add_for_no_key_update, []}
prepare fn query, _ -> Ash.Query.lock(query, :for_update) end
transaction? true
end
preparations are just like changes from create/update/destroy actions you can attach lifecycle hooks and things like that there
rohan
rohanOP2y ago
got it!
ZachDaniel
ZachDaniel2y ago
question: do you have an update action that youare passing this to? like get_processed_by_index -> update_it()? the thing you're doing isn't actually going to do what you want TBH
rohan
rohanOP2y ago
not quite - it is part of an action that's going to do an update, but to a different row
ZachDaniel
ZachDaniel2y ago
Ah, okay the main thing is that if you just call this action on its own, the transaction? true will end but if its called inside another transaction then it will do what you want
rohan
rohanOP2y ago
yup - this is in an after action block
ZachDaniel
ZachDaniel2y ago
👍
rohan
rohanOP2y ago
i probably didn't need the transaction? true but it felt right to put it there 🙂 ash doesn't currently support FOR NO KEY UPDATE right? is there a way to pass that in or would that require an ash PR
ZachDaniel
ZachDaniel2y ago
IIRC if you pass a string it will use it directly in the data layer
rohan
rohanOP2y ago
oh perfect!
ZachDaniel
ZachDaniel2y ago
you can do this to protect yourself in the future:
prepare fn query, _ ->
Ash.Query.before_action(query, fn query ->
if Ash.DataLayer.in_transaction?(query.resource) do
Ash.Query.add_error(query, "must be in a transaction")
else
query
end
end)
end
prepare fn query, _ ->
Ash.Query.before_action(query, fn query ->
if Ash.DataLayer.in_transaction?(query.resource) do
Ash.Query.add_error(query, "must be in a transaction")
else
query
end
end)
end
rohan
rohanOP2y ago
is there a similar thing for change get_and_lock("FOR NO KEY UPDATE")
ZachDaniel
ZachDaniel2y ago
I believe so, yeah and then I'd remove the transaction? true just adds some protection that an action meant to set up something specific isn't called in a context where its not actually helping
rohan
rohanOP2y ago
got it! thank you!
ZachDaniel
ZachDaniel2y ago
👍 my pleasure
rohan
rohanOP2y ago
prepare fn query, _ -> Ash.Query.lock(query, "FOR NO KEY UPDATE") end
prepare fn query, _ -> Ash.Query.lock(query, "FOR NO KEY UPDATE") end
results in:
** (Ash.Error.Invalid) Input Invalid

* Data layer for Scribble.Scribe.AudioFile does not support lock: "FOR NO KEY UPDATE"
(ash 2.10.1) lib/ash/api/api.ex:2123: Ash.Api.unwrap_or_raise!/3
** (Ash.Error.Invalid) Input Invalid

* Data layer for Scribble.Scribe.AudioFile does not support lock: "FOR NO KEY UPDATE"
(ash 2.10.1) lib/ash/api/api.ex:2123: Ash.Api.unwrap_or_raise!/3
(i'm using postgres)
ZachDaniel
ZachDaniel2y ago
Hmm....what is your ash_postgres version?
iex(1)> AshPostgres.DataLayer.can?(nil, {:lock, "FOR NO KEY UPDATE"})
true
iex(1)> AshPostgres.DataLayer.can?(nil, {:lock, "FOR NO KEY UPDATE"})
true
rohan
rohanOP2y ago
i was pointing at the main branch - but forcing an update now that was it - ty!
ZachDaniel
ZachDaniel2y ago
👍

Did you find this page helpful?