Skip to content

Commit

Permalink
Simple version of parsing order_by in query structs
Browse files Browse the repository at this point in the history
  • Loading branch information
Nickforall committed Nov 12, 2018
1 parent 6a2058f commit 8411c00
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
32 changes: 32 additions & 0 deletions lib/paginator/ecto/order_by.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
defmodule Paginator.Ecto.OrderBy do
@moduledoc false

# import Ecto.Query

def infer_order_by(queryable) do
queryable
|> get_order_by_expressions()
|> make_cursor_field_list()
end

defp get_order_by_expressions(queryable) do
queryable.order_bys
|> Enum.reduce([], fn x, acc -> x.expr ++ acc end)
end

defp make_cursor_field_list(expressions) do
expressions
|> Enum.map(fn {key, value} ->
# gets the field name atom from the query struct

case value do
# https://github.com/elixir-ecto/ecto/blob/1533413/lib/ecto/query/builder/order_by.ex#L121
{{:., [], [{:&, [], [0]}, field]}, [], []} ->
{field, key}

_ ->
raise "Unsupported `order_by` syntax, could not infer the cursor fields. Please supply `cursor_fields` manually."
end
end)
end
end
48 changes: 48 additions & 0 deletions test/paginator/order_by_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
defmodule Paginator.OrderByTest do
use ExUnit.Case, async: true

alias Paginator.Ecto.OrderBy
import Ecto.Query

defp assert_result(result, list) do
assert(result == list)
end

describe "OrderBy.infer_order_by/1" do
test "parses single order_by with default direction" do
from(p in "payments",
order_by: p.charged_at
)
|> OrderBy.infer_order_by()
|> assert_result(charged_at: :asc)
end

test "parses multiple order_bys with default direction" do
from(p in "payments",
order_by: [p.amount, p.charged_at]
)
|> OrderBy.infer_order_by()
|> assert_result(amount: :asc, charged_at: :asc)
end

test "parses multiple seperate order_bys with a given direction" do
from(p in "payments",
order_by: [desc: p.charged_at],
order_by: [asc: p.amount]
)
|> OrderBy.infer_order_by()
|> assert_result(amount: :asc, charged_at: :desc)
end

test "rejects order_by with a fragment" do
assert_raise RuntimeError,
"Unsupported `order_by` syntax, could not infer the cursor fields. Please supply `cursor_fields` manually.",
fn ->
from(p in "payments",
order_by: fragment("amount")
)
|> OrderBy.infer_order_by()
end
end
end
end

0 comments on commit 8411c00

Please sign in to comment.