Merge branch 'bugfix/pleroma-email-naming' into 'develop'
[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 params =
40 Enum.reduce(params, %{}, fn
41 {key, _value}, acc when is_atom(key) -> Map.drop(acc, [key])
42 {key, value}, acc -> Map.put(acc, key, value)
43 end)
44
45 changeset = cast({%{}, param_types}, params, Map.keys(param_types))
46 changeset.changes
47 end
48
49 defp restrict(query, :min_id, %{min_id: min_id}) do
50 where(query, [q], q.id > ^min_id)
51 end
52
53 defp restrict(query, :since_id, %{since_id: since_id}) do
54 where(query, [q], q.id > ^since_id)
55 end
56
57 defp restrict(query, :max_id, %{max_id: max_id}) do
58 where(query, [q], q.id < ^max_id)
59 end
60
61 defp restrict(query, :order, %{min_id: _}) do
62 order_by(query, [u], fragment("? asc nulls last", u.id))
63 end
64
65 defp restrict(query, :order, _options) do
66 order_by(query, [u], fragment("? desc nulls last", u.id))
67 end
68
69 defp restrict(query, :limit, options) do
70 limit = Map.get(options, :limit, @default_limit)
71
72 query
73 |> limit(^limit)
74 end
75
76 defp restrict(query, _, _), do: query
77
78 defp enforce_order(result, %{min_id: _}) do
79 result
80 |> Enum.reverse()
81 end
82
83 defp enforce_order(result, _), do: result
84 end