Skip to content

Commit

Permalink
Support row level locking in select queries
Browse files Browse the repository at this point in the history
  • Loading branch information
bmuller committed Aug 11, 2023
1 parent e52adcf commit b3e3ded
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 6 deletions.
9 changes: 5 additions & 4 deletions lib/endon.ex
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ defmodule Endon do
## Options
* `:preload` - A list of fields to preload, much like `c:Ecto.Repo.preload/3`
* `:lock` - Row level lock in the select. Currently only `:for_update` is supported.
"""
@spec fetch(integer() | list(integer()), keyword()) ::
{:ok, list(Ecto.Schema.t())} | {:ok, Ecto.Schema.t()} | :error
Expand Down Expand Up @@ -198,8 +198,8 @@ defmodule Endon do
## Options
* `:preload` - A list of fields to preload, much like `c:Ecto.Repo.preload/3`
* `:preload` - A list of fields to preload, much like `c:Ecto.Repo.preload/3`
* `:lock` - Row level lock in the select. Currently only `:for_update` is supported.
"""
@spec find(integer() | list(integer()), keyword()) ::
list(Ecto.Schema.t()) | Ecto.Schema.t()
Expand All @@ -214,7 +214,7 @@ defmodule Endon do
## Options
* `:preload` - A list of fields to preload, much like `c:Ecto.Repo.preload/3`
* `:lock` - Row level lock in the select. Currently only `:for_update` is supported.
"""
@spec find_by(where_conditions(), keyword()) :: Ecto.Schema.t() | nil
def find_by(conditions, opts \\ []),
Expand Down Expand Up @@ -417,6 +417,7 @@ defmodule Endon do
* `:preload` - A list of fields to preload, much like `c:Ecto.Repo.preload/3`
* `:offset` - Number to offset by
* `:limit` - Limit results to the given count
* `:lock` - Row level lock in the select. Currently only `:for_update` is supported.
## Examples
Expand Down
4 changes: 3 additions & 1 deletion lib/endon/helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ defmodule Endon.Helpers do
def where(repo, module, conditions, opts) do
module
|> add_where(conditions)
|> add_opts(opts, [:limit, :order_by, :offset, :preload])
|> add_opts(opts, [:limit, :order_by, :offset, :preload, :lock])
|> repo.all()
end

Expand Down Expand Up @@ -269,6 +269,8 @@ defmodule Endon.Helpers do
defp apply_opt(query, :limit, limit), do: Query.limit(query, ^limit)
defp apply_opt(query, :preload, preload), do: Query.preload(query, ^preload)
defp apply_opt(query, :offset, offset), do: Query.offset(query, ^offset)
# for security reasons, locks must always be literal strings
defp apply_opt(query, :lock, :for_update), do: Query.lock(query, "FOR UPDATE")

defp add_where(query, []), do: query

Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule Endon.MixProject do
use Mix.Project

@source_url "https://github.com/parallel-markets/endon"
@version "2.0.0"
@version "2.0.1"

def project do
[
Expand Down
4 changes: 4 additions & 0 deletions test/endon_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ defmodule EndonTest do
assert UserSingle.where(id: 1) == ["from u0 in UserSingle, where: u0.id == ^1"]
end

test "when using where with a limit" do
assert UserSingle.where([id: 1], lock: :for_update) == ["from u0 in UserSingle, where: u0.id == ^1, lock: \"FOR UPDATE\""]
end

test "when using where with a map" do
assert UserSingle.where(%{id: 1}) == ["from u0 in UserSingle, where: u0.id == ^1"]
end
Expand Down

0 comments on commit b3e3ded

Please sign in to comment.