Skip to content

Commit

Permalink
Add Ecto.Multi.exists?/4 (#4063)
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-rychlewski committed Dec 19, 2022
1 parent afc3cd9 commit 4576ddf
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 2 deletions.
41 changes: 39 additions & 2 deletions lib/ecto/multi.ex
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ defmodule Ecto.Multi do
@spec one(
t,
name,
queryable :: Ecto.Queryable.t | (any -> Ecto.Queryable.t),
queryable :: Ecto.Queryable.t | fun(Ecto.Queryable.t),
opts :: Keyword.t
) :: t
def one(multi, name, queryable_or_fun, opts \\ [])
Expand Down Expand Up @@ -445,7 +445,7 @@ defmodule Ecto.Multi do
@spec all(
t,
name,
queryable :: Ecto.Queryable.t | (any -> Ecto.Queryable.t),
queryable :: Ecto.Queryable.t | fun(Ecto.Queryable.t),
opts :: Keyword.t
) :: t
def all(multi, name, queryable_or_fun, opts \\ [])
Expand All @@ -458,6 +458,37 @@ defmodule Ecto.Multi do
run(multi, name, operation_fun({:all, fn _ -> queryable end}, opts))
end

@doc """
Checks if there exists an entry matching the given query and stores a boolean in the multi.
Accepts the same arguments and options as `c:Ecto.Repo.exists?/2`.
## Example
Ecto.Multi.new()
|> Ecto.Multi.exists?(:post, Post)
|> MyApp.Repo.transaction()
Ecto.Multi.new()
|> Ecto.Multi.exists?(:post, fn _changes -> Post end)
|> MyApp.Repo.transaction()
"""
@spec exists?(
t,
name,
queryable :: Ecto.Queryable.t | fun(Ecto.Queryable.t),
opts :: Keyword.t
) :: t
def exists?(multi, name, queryable_or_fun, opts \\ [])

def exists?(multi, name, fun, opts) when is_function(fun, 1) do
run(multi, name, operation_fun({:exists?, fun}, opts))
end

def exists?(multi, name, queryable, opts) do
run(multi, name, operation_fun({:exists?, fn _ -> queryable end}, opts))
end

defp add_changeset(multi, action, name, changeset, opts) when is_list(opts) do
add_operation(multi, name, {:changeset, put_action(changeset, action), opts})
end
Expand Down Expand Up @@ -870,6 +901,12 @@ defmodule Ecto.Multi do
end
end

defp operation_fun({:exists?, fun}, opts) do
fn repo, changes ->
{:ok, repo.exists?(fun.(changes), opts)}
end
end

defp operation_fun({operation, fun}, opts) do
fn repo, changes ->
apply(repo, operation, [fun.(changes), opts])
Expand Down
20 changes: 20 additions & 0 deletions test/ecto/multi_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,26 @@ defmodule Ecto.MultiTest do
assert [{:comments, {:run, _fun}}] = multi.operations
end

test "exists? queryable" do
multi =
Multi.new()
|> Multi.exists?(:comment, Comment)

assert multi.names == MapSet.new([:comment])
assert [{:comment, {:run, _fun}}] = multi.operations
end

test "exists? fun" do
fun = fn _changes -> Comment end

multi =
Multi.new()
|> Multi.exists?(:comment, fun)

assert multi.names == MapSet.new([:comment])
assert [{:comment, {:run, _fun}}] = multi.operations
end

test "error" do
multi =
Multi.new()
Expand Down

0 comments on commit 4576ddf

Please sign in to comment.