Skip to content

Commit 4ebb59a

Browse files
committed
feat: impl callback query/2
1 parent 2fa6df6 commit 4ebb59a

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

lib/swiss_schema.ex

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,21 @@ defmodule SwissSchema do
373373
opts :: Keyword.t()
374374
) :: Ecto.Schema.t()
375375

376+
@doc """
377+
Allow complex queries to be made over the data store.
378+
379+
`c:query/2` accepts a function to intercept the query and modify as needed.
380+
381+
## Examples
382+
383+
iex> import Ecto.Query, only: [where: 2]
384+
iex> User.query(fn query -> query |> where([u], u.name == "John Lennon") end)
385+
{:ok, [%User{name: "John Lennon"}]}
386+
"""
387+
@doc group: "SwissSchema API"
388+
@callback query(hook :: (Ecto.Query.t() -> Ecto.Query.t()), opts :: Keyword.t()) ::
389+
{:ok, list(map())}
390+
376391
@doc """
377392
Returns a lazy enumerable that emits all entries from the data store.
378393
@@ -443,6 +458,7 @@ defmodule SwissSchema do
443458
end
444459

445460
quote do
461+
import Ecto.Query, only: [from: 1, select: 3]
446462
@behaviour SwissSchema
447463

448464
@_swiss_schema %{
@@ -611,6 +627,20 @@ defmodule SwissSchema do
611627
insert_or_update!.(changeset, opts)
612628
end
613629

630+
@impl SwissSchema
631+
def query(hook, opts \\ [])
632+
when is_function(hook, 1) do
633+
repo = Keyword.get(opts, :repo, unquote(repo))
634+
all = Function.capture(repo, :all, 1)
635+
636+
query =
637+
from(s in __MODULE__)
638+
|> select([s], s)
639+
|> then(hook)
640+
641+
{:ok, all.(query)}
642+
end
643+
614644
@deprecated "Use Ecto.Repo's stream/2 instead"
615645
@impl SwissSchema
616646
def stream(opts \\ []) do

test/swiss_schema_test.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ defmodule SwissSchemaTest do
133133
assert function_exported?(SwissSchemaTest.User, :get_by!, 2)
134134
end
135135

136+
test "define query/1" do
137+
assert function_exported?(SwissSchemaTest.User, :query, 1)
138+
end
139+
136140
test "define stream/0" do
137141
assert function_exported?(SwissSchemaTest.User, :stream, 0)
138142
end
@@ -574,6 +578,22 @@ defmodule SwissSchemaTest do
574578
end
575579
end
576580

581+
describe "query/1" do
582+
setup do: Enum.each(1..3, fn i -> user_mock(lucky_number: i) |> Repo.insert!() end)
583+
584+
test "accept a function to customize the query" do
585+
assert {:ok, [%User{}, %User{}, %User{}]} = User.query(fn q -> q end)
586+
end
587+
588+
test "accepts a custom Ecto repo thru :repo opt" do
589+
1..3
590+
|> Enum.map(fn _ -> user_mock() |> Map.drop([:__struct__, :__meta__, :id]) end)
591+
|> then(&Repo2.insert_all(User, &1))
592+
593+
assert {:ok, [%User{}, %User{}, %User{}]} = User.query(fn q -> q end, repo: Repo2)
594+
end
595+
end
596+
577597
describe "update_all/2" do
578598
setup do: Enum.each(1..5, fn i -> user_mock(lucky_number: i) |> Repo.insert!() end)
579599

0 commit comments

Comments
 (0)