Ostap Maliuvanchuk
Ostap Maliuvanchuk

Reputation: 1175

Lock row "FOR UPDATE OF" specific table using Ecto/Elixir

I would like to acquire a lock using FOR UPDATE OF table_name. In comparison to FOR UPDATE, FOR UPDATE OF only locks the row in the specified table and the joined rows are not blocked. However, when I try to do it with Ecto using the following snippet it fails.

query =
  Call
  |> join_other_tables() # custom methods
  |> Query.lock("FOR UPDATE OF calls")

The reason is Ecto uses an alias for calls, for example, c0, which means that I also have to use the alias in the lock expression to get it working.

query =
  Call
  |> join_other_tables() # custom methods
  |> Query.lock("FOR UPDATE OF c0")

Using the alias does not look like a proper way to do it. Is there any other way to get it working?

Upvotes: 2

Views: 1547

Answers (2)

IrishDubGuy
IrishDubGuy

Reputation: 1103

Note it looks like you can now use a fragment to interpolate the table name in, see https://github.com/elixir-ecto/ecto_sql/pull/189. So the solution from Aleksei should now work:

from c in Call,
  join: ..., # custom methods
  lock: fragment("FOR UPDATE OF ?", c)

Upvotes: 2

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

As of Ecto v3 there is no way to pass the parameterized value to Query.lock. It accepts binaries only.

[Named bindings] won’t work either because Ecto internally generates aliases as it wants.


The following approach would be the nearest one, but it does not work either because Ecto.Query.lock/2 does not allow interpolation.

Use Ecto.Query.API.fragment, that has an interpolation ability, with the keyword query syntax. Somewhat like:

from c in Call,
  join: ..., # custom methods
  lock: fragment("FOR UPDATE OF ?", c)

Upvotes: 3

Related Questions