-
Notifications
You must be signed in to change notification settings - Fork 1
/
cursor_pagination.ex
46 lines (36 loc) · 1.33 KB
/
cursor_pagination.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
defmodule Ecto.CursorPagination do
@moduledoc """
Cursor / Value based pagination using Ecto
http://blog.novatec-gmbh.de/art-pagination-offset-vs-value-based-paging/
"""
import Ecto.Query, only: [limit: 2, where: 3, order_by: 2]
@doc """
Efficiently returns a maximum of `per_page` configured results.
Assumes cursor_ids are integers and incremented as inserted in order.
It returns an Ecto Query that is the combination
of the inputted query and the cursor pagination.
If an unknown or nil direction is inputted,
it returns the original query in the default order.
"""
@spec paginate(Ecto.Query.t, pos_integer, String.t) :: Ecto.Query.t
def paginate(query, last_seen_id, direction)
def paginate(query, last_seen_id, "prev") do
query
|> order_by(desc: ^cursor_id())
|> where([q], field(q, ^cursor_id()) < ^last_seen_id)
|> limit(^per_page())
end
def paginate(query, last_seen_id, "next") do
query
|> order_by(asc: ^cursor_id())
|> where([q], field(q, ^cursor_id()) > ^last_seen_id)
|> limit(^per_page())
end
def paginate(query, _, _) do
query
|> order_by(desc: ^cursor_id())
|> limit(^per_page())
end
defp cursor_id, do: Application.fetch_env!(:ecto_cursor_pagination, :cursor_id)
defp per_page, do: Application.fetch_env!(:ecto_cursor_pagination, :per_page)
end