Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infer sort_direction from query #48

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion lib/paginator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ defmodule Paginator do
* `:maximum_limit` - Sets a maximum cap for `:limit`. This option can be useful when `:limit`
is set dynamically (e.g from a URL param set by a user) but you still want to
enfore a maximum. Defaults to `500`.
* `:sort_direction` - The direction used for sorting. Defaults to `:asc`.
* `:total_count_limit` - Running count queries on tables with a large number
of records is expensive so it is capped by default. Can be set to `:infinity`
in order to count all the records. Defaults to `10,000`.
Expand Down
2 changes: 0 additions & 2 deletions lib/paginator/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ defmodule Paginator.Config do
:total_count_primary_key_field,
:limit,
:maximum_limit,
:sort_direction,
:total_count_limit
]

Expand All @@ -35,7 +34,6 @@ defmodule Paginator.Config do
include_total_count: opts[:include_total_count] || false,
total_count_primary_key_field: opts[:total_count_primary_key_field] || @default_total_count_primary_key_field,
limit: limit(opts),
sort_direction: opts[:sort_direction] || :asc,
total_count_limit: opts[:total_count_limit] || @default_total_count_limit
}
end
Expand Down
81 changes: 28 additions & 53 deletions lib/paginator/ecto/query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defmodule Paginator.Ecto.Query do
paginate(queryable, Config.new(opts))
end

defp filter_values(query, cursor_fields, values, operator) do
defp filter_values(query, cursor_fields, values, ordering) do
sorts =
cursor_fields
|> Enum.zip(values)
Expand All @@ -29,6 +29,8 @@ defmodule Paginator.Ecto.Query do
|> Enum.reduce(true, fn {{column, value}, i}, dynamic_sorts ->
dynamic = true

operator = operator(query, column, ordering)

dynamic =
case operator do
:lt ->
Expand Down Expand Up @@ -57,82 +59,38 @@ defmodule Paginator.Ecto.Query do

defp maybe_where(query, %Config{
after_values: nil,
before_values: nil,
sort_direction: :asc
before_values: nil
}) do
query
end

defp maybe_where(query, %Config{
after_values: after_values,
before: nil,
cursor_fields: cursor_fields,
sort_direction: :asc
cursor_fields: cursor_fields
}) do
query
|> filter_values(cursor_fields, after_values, :gt)
|> filter_values(cursor_fields, after_values, :forwards)
end

defp maybe_where(query, %Config{
after_values: nil,
before_values: before_values,
cursor_fields: cursor_fields,
sort_direction: :asc
cursor_fields: cursor_fields
}) do
query
|> filter_values(cursor_fields, before_values, :lt)
|> filter_values(cursor_fields, before_values, :backwards)
|> reverse_order_bys()
end

defp maybe_where(query, %Config{
after_values: after_values,
before_values: before_values,
cursor_fields: cursor_fields,
sort_direction: :asc
cursor_fields: cursor_fields
}) do
query
|> filter_values(cursor_fields, after_values, :gt)
|> filter_values(cursor_fields, before_values, :lt)
end

defp maybe_where(query, %Config{
after: nil,
before: nil,
sort_direction: :desc
}) do
query
end

defp maybe_where(query, %Config{
after_values: after_values,
before: nil,
cursor_fields: cursor_fields,
sort_direction: :desc
}) do
query
|> filter_values(cursor_fields, after_values, :lt)
end

defp maybe_where(query, %Config{
after: nil,
before_values: before_values,
cursor_fields: cursor_fields,
sort_direction: :desc
}) do
query
|> filter_values(cursor_fields, before_values, :gt)
|> reverse_order_bys()
end

defp maybe_where(query, %Config{
after_values: after_values,
before_values: before_values,
cursor_fields: cursor_fields,
sort_direction: :desc
}) do
query
|> filter_values(cursor_fields, after_values, :lt)
|> filter_values(cursor_fields, before_values, :gt)
|> filter_values(cursor_fields, after_values, :forwards)
|> filter_values(cursor_fields, before_values, :backwards)
end

#  In order to return the correct pagination cursors, we need to fetch one more
Expand Down Expand Up @@ -160,4 +118,21 @@ defmodule Paginator.Ecto.Query do
end
end)
end

defp operator(query, field, ordering) do
Enum.reduce(query.order_bys, :gt, fn ob, default ->
%Ecto.Query.QueryExpr{expr: expr} = ob
Enum.reduce_while(expr, default, fn
{direction, {{_, _, [_, ^field]}, _, _}}, _ ->
{:halt, get_opertator(ordering, direction)}
_, default ->
{:cont, default}
end)
end)
end

defp get_opertator(:forwards, :asc), do: :gt
defp get_opertator(:forwards, :desc), do: :lt
defp get_opertator(:backwards, :asc), do: :lt
defp get_opertator(:backwards, :desc), do: :gt
end
Loading