Added support for exclude_types, limit, and min_id in Mastodon
[akkoma] / lib / pleroma / pagination.ex
1 defmodule Pleroma.Pagination do
2 @moduledoc """
3 Implements Mastodon-compatible pagination.
4 """
5
6 import Ecto.Query
7 import Ecto.Changeset
8
9 alias Pleroma.Repo
10
11 @default_limit 20
12
13 def fetch_paginated(query, params) do
14 options = cast_params(params)
15
16 query
17 |> paginate(options)
18 |> Repo.all()
19 |> enforce_order(options)
20 end
21
22 def paginate(query, options) do
23 query
24 |> restrict(:min_id, options)
25 |> restrict(:since_id, options)
26 |> restrict(:max_id, options)
27 |> restrict(:order, options)
28 |> restrict(:limit, options)
29 end
30
31 defp cast_params(params) do
32 param_types = %{
33 min_id: :string,
34 since_id: :string,
35 max_id: :string,
36 limit: :integer
37 }
38
39 changeset = cast({%{}, param_types}, params, Map.keys(param_types))
40 changeset.changes
41 end
42
43 defp restrict(query, :min_id, %{min_id: min_id}) do
44 where(query, [q], q.id > ^min_id)
45 end
46
47 defp restrict(query, :since_id, %{since_id: since_id}) do
48 where(query, [q], q.id > ^since_id)
49 end
50
51 defp restrict(query, :max_id, %{max_id: max_id}) do
52 where(query, [q], q.id < ^max_id)
53 end
54
55 defp restrict(query, :order, %{min_id: _}) do
56 order_by(query, [u], fragment("? asc nulls last", u.id))
57 end
58
59 defp restrict(query, :order, _options) do
60 order_by(query, [u], fragment("? desc nulls last", u.id))
61 end
62
63 defp restrict(query, :limit, options) do
64 limit = Map.get(options, :limit, @default_limit)
65
66 query
67 |> limit(^limit)
68 end
69
70 defp restrict(query, _, _), do: query
71
72 defp enforce_order(result, %{min_id: _}) do
73 result
74 |> Enum.reverse()
75 end
76
77 defp enforce_order(result, _), do: result
78 end