Alembic v4.0.0 Alembic.Pagination.Page View Source
A page using paged pagination where the size of pages is fixed.
Link to this section Summary
Functions
The number of pages of size
when there are total_size
resources to be paginated
t
for Alembic.Pagination.t
first
Parses t
out of params
Extracts number
from query
"page[number]"
and and size
from query
"page[size]"
Extracts number
from uri
query
"page[number]"
and size
from uri
query
"page[size]"
t
for Alembic.Pagination.t
last
t
for Alembic.Pagination.t
next
t
for Alembic.Pagination.t
previous
Alembic.Pagination.t
for pages around page
Converts the page
back to params
Converts the page
back to query portion of URI
Link to this section Types
t() :: %Alembic.Pagination.Page{number: pos_integer(), size: pos_integer()}
number
- the 1-based page numbersize
- the size of this page and all pages
Link to this section Functions
count(%{size: pos_integer(), total_size: non_neg_integer()}) :: pos_integer()
The number of pages of size
when there are total_size
resources to be paginated.
If there are no resources (total_size
is 0
), then there will still be 1 page
iex> Alembic.Pagination.Page.count(%{size: 10, total_size: 0})
1
The number of pages is always rounded up since a partial page still needs to be returned
iex> Alembic.Pagination.Page.count(%{size: 10, total_size: 10})
1
iex> Alembic.Pagination.Page.count(%{size: 10, total_size: 1})
1
iex> Alembic.Pagination.Page.count(%{size: 10, total_size: 11})
2
first(t(), %{optional(:count) => pos_integer()}) :: t()
t
for Alembic.Pagination.t
first
There is always a first
t
with number
1
.
iex> Alembic.Pagination.Page.first(
...> %Alembic.Pagination.Page{
...> number: 2,
...> size: 10
...> },
...> %{count: 3}
...> )
%Alembic.Pagination.Page{
number: 1,
size: 10
}
from_params(map()) :: {:ok, t()} | {:ok, :all} | {:ok, nil} | {:error, Alembic.Document.t()}
Parses t
out of params
No pagination
If there is no "page"
key, then there is no pagination.
iex> Alembic.Pagination.Page.from_params(%{})
{:ok, nil}
Pagination
If there is a “page” key with "number"
and "size"
children, then there is pagination.
iex> Alembic.Pagination.Page.from_params(
...> %{
...> "page" => %{
...> "number" => 1,
...> "size" => 2
...> }
...> }
...> )
{:ok, %Alembic.Pagination.Page{number: 1, size: 2}}
In addition to be decoded JSON, the params can also be the raw %{String.t => String.t}
and the quoted integers will
be decoded.
iex> Alembic.Pagination.Page.from_params(
...> %{
...> "page" => %{
...> "number" => "1",
...> "size" => "2"
...> }
...> }
...> )
{:ok, %Alembic.Pagination.Page{number: 1, size: 2}}
Opt-out
Opting out of default pagination can be indicated with a nil
page
iex> Alembic.Pagination.Page.from_params(
...> %{"page" => nil}
...> )
{:ok, :all}
Errors
A page number can’t be given as the "page"
parameter alone because no default page size is assumed.
iex> Alembic.Pagination.Page.from_params(%{"page" => 1})
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/page` type is not object",
meta: %{
"type" => "object"
},
source: %Alembic.Source{
pointer: "/page"
},
status: "422",
title: "Type is wrong"
}
]
}
}
Required parameters
Likewise, the "page"
map can’t have only a "number"
parameter because no default page size is assumed.
iex> Alembic.Pagination.Page.from_params(
...> %{
...> "page" => %{
...> "number" => 1
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/page/size` is missing",
meta: %{
"child" => "size"
},
source: %Alembic.Source{
pointer: "/page"
},
status: "422",
title: "Child missing"
}
]
}
}
The page number is not assumed to be 1 when not given.
iex> Alembic.Pagination.Page.from_params(
...> %{
...> "page" => %{
...> "size" => 10
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/page/number` is missing",
meta: %{
"child" => "number"
},
source: %Alembic.Source{
pointer: "/page"
},
status: "422",
title: "Child missing"
}
]
}
}
Number format
"page"
"number"
must be a positive integer. It is 1-based. The first page is "1"
iex> Alembic.Pagination.Page.from_params(
...> %{
...> "page" => %{
...> "number" => 0,
...> "size" => 10
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/page/number` type is not positive integer",
meta: %{
"type" => "positive integer"
},
source: %Alembic.Source{
pointer: "/page/number"
},
status: "422",
title: "Type is wrong"
}
]
}
}
Size format
"page"
"size"
must be a positive integer.
iex> Alembic.Pagination.Page.from_params(
...> %{
...> "page" => %{
...> "number" => 1,
...> "size" => 0
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/page/size` type is not positive integer",
meta: %{
"type" => "positive integer"
},
source: %Alembic.Source{
pointer: "/page/size"
},
status: "422",
title: "Type is wrong"
}
]
}
}
Extracts number
from query
"page[number]"
and and size
from query
"page[size]"
.
iex> Alembic.Pagination.Page.from_query("page%5Bnumber%5D=2&page%5Bsize%5D=10")
%Alembic.Pagination.Page{number: 2, size: 10}
If query
does not have both "page[number]"
and "page[size]"
then nil
is returned
iex> Alembic.Pagination.Page.from_query("page%5Bnumber%5D=2")
nil
iex> Alembic.Pagination.Page.from_query("page%5Bsize%5D=10")
nil
iex> Alembic.Pagination.Page.from_query("")
nil
Extracts number
from uri
query
"page[number]"
and size
from uri
query
"page[size]"
.
iex> Alembic.Pagination.Page.from_uri(%URI{query: "page%5Bnumber%5D=2&page%5Bsize%5D=10"})
%Alembic.Pagination.Page{number: 2, size: 10}
If a URI.t
query
does not have both "page[number]"
and "page[size]"
then nil
is returned
iex> Alembic.Pagination.Page.from_uri(%URI{query: "page%5Bnumber%5D=2"})
nil
iex> Alembic.Pagination.Page.from_uri(%URI{query: "page%5Bsize%5D=10"})
nil
iex> Alembic.Pagination.Page.from_uri(%URI{query: ""})
nil
If a URI.t
does not have a query then nil
is returned
iex> Alembic.Pagination.Page.from_uri(%URI{query: nil})
nil
t
for Alembic.Pagination.t
last
There is always last
Alembic.Pagination.Page.t
with number
count
.
iex> Alembic.Pagination.Page.last(
...> %Alembic.Pagination.Page{
...> number: 1,
...> size: 10
...> },
...> %{count: 2}
...> )
%Alembic.Pagination.Page{
number: 2,
size: 10
}
t
for Alembic.Pagination.t
next
Single page
When there is only one page, the first page is also the last page, so next
is nil
.
iex> Alembic.Pagination.Page.next(
...> %Alembic.Pagination.Page{
...> number: 1,
...> size: 10
...> },
...> %{count: 1}
...> )
nil
Multiple Pages
When there are multiple pages, the first page has the second page, with number
2
, as its next page.
iex> Alembic.Pagination.Page.next(
...> %Alembic.Pagination.Page{
...> number: 1,
...> size: 10
...> },
...> %{count: 3}
...> )
%Alembic.Pagination.Page{
number: 2,
size: 10
}
Any middle page will also have a next page with number + 1
iex> Alembic.Pagination.Page.next(
...> %Alembic.Pagination.Page{
...> number: 2,
...> size: 10
...> },
...> %{count: 3}
...> )
%Alembic.Pagination.Page{
number: 3,
size: 10
}
The last page is the only page that will have a next page.
iex> Alembic.Pagination.Page.next(
...> %Alembic.Pagination.Page{
...> number: 3,
...> size: 10
...> },
...> %{count: 3}
...> )
nil
previous(t(), %{optional(:count) => pos_integer()}) :: t() | nil
t
for Alembic.Pagination.t
previous
.
Single page
When there is only one page, the last page is also the first page, so previous page is nil
.
iex> Alembic.Pagination.Page.previous(
...> %Alembic.Pagination.Page{
...> number: 1,
...> size: 10
...> },
...> %{count: 1}
...> )
nil
Multiple Pages
When there are multiple pages, the first page has no previous page, so it is nil
.
iex> Alembic.Pagination.Page.previous(
...> %Alembic.Pagination.Page{
...> number: 1,
...> size: 10
...> },
...> %{count: 3}
...> )
nil
Any middle page will have the previous page with number - 1
.
iex> Alembic.Pagination.Page.previous(
...> %Alembic.Pagination.Page{
...> number: 2,
...> size: 10
...> },
...> %{count: 3}
...> )
%Alembic.Pagination.Page{
number: 1,
size: 10
}
The last page will also have previous page the same as a middle page.
iex> Alembic.Pagination.Page.previous(
...> %Alembic.Pagination.Page{
...> number: 3,
...> size: 10
...> },
...> %{count: 3}
...> )
%Alembic.Pagination.Page{
number: 2,
size: 10
}
to_pagination(t(), %{total_size: non_neg_integer()}) :: {:ok, Alembic.Pagination.t()} | {:error, Alembic.Document.t()}
Alembic.Pagination.t
for pages around page
.
Single Page
When there is only one page, first
and last
will be set to a t
, but next
or previous
will be nil
.
iex> Alembic.Pagination.Page.to_pagination(
...> %Alembic.Pagination.Page{number: 1, size: 10},
...> %{total_size: 5}
...> )
{
:ok,
%Alembic.Pagination{
first: %Alembic.Pagination.Page{
number: 1,
size: 10
},
last: %Alembic.Pagination.Page{
number: 1,
size: 10
},
total_size: 5
}
}
No entries
If total_size
is 0
, then there will still be 1 page, but it will be empty
iex> Alembic.Pagination.Page.to_pagination(
...> %Alembic.Pagination.Page{number: 1, size: 10},
...> %{total_size: 0}
...> )
{
:ok,
%Alembic.Pagination{
first: %Alembic.Pagination.Page{
number: 1,
size: 10
},
last: %Alembic.Pagination.Page{
number: 1,
size: 10
},
total_size: 0
}
}
Multiple Pages
When there are multiple pages, every page will have first
and last
set to a t
.
On the first page, the next
field will set, but not the previous
field.
iex> Alembic.Pagination.Page.to_pagination(
...> %Alembic.Pagination.Page{number: 1, size: 10},
...> %{total_size: 25}
...> )
{
:ok,
%Alembic.Pagination{
first: %Alembic.Pagination.Page{
number: 1,
size: 10
},
last: %Alembic.Pagination.Page{
number: 3,
size: 10
},
next: %Alembic.Pagination.Page{
number: 2,
size: 10
},
total_size: 25
}
}
On any middle page, both the next
and previous
fields will be set.
iex> Alembic.Pagination.Page.to_pagination(
...> %Alembic.Pagination.Page{number: 2, size: 10},
...> %{total_size: 25}
...> )
{
:ok,
%Alembic.Pagination{
first: %Alembic.Pagination.Page{
number: 1,
size: 10
},
last: %Alembic.Pagination.Page{
number: 3,
size: 10
},
next: %Alembic.Pagination.Page{
number: 3,
size: 10
},
previous: %Alembic.Pagination.Page{
number: 1,
size: 10
},
total_size: 25
}
}
On the last page, the previous
field will be set, but not the next
field.
iex> Alembic.Pagination.Page.to_pagination(
...> %Alembic.Pagination.Page{number: 3, size: 10},
...> %{total_size: 25}
...> )
{
:ok,
%Alembic.Pagination{
first: %Alembic.Pagination.Page{
number: 1,
size: 10
},
last: %Alembic.Pagination.Page{
number: 3,
size: 10
},
previous: %Alembic.Pagination.Page{
number: 2,
size: 10
},
total_size: 25
}
}
Out-of-range
If a page number is too high an error will be returned.
iex> Alembic.Pagination.Page.to_pagination(
...> %Alembic.Pagination.Page{number: 2, size: 10},
...> %{total_size: 0}
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "Page number (2) must be between 1 and the page count (1)",
meta: %{
"count" => 1,
"number" => 2
},
source: %Alembic.Source{
pointer: "/page/number"
},
status: "422",
title: "Page number must be between 1 and the page count"
}
]
}
}
iex> Alembic.Pagination.Page.to_pagination(
...> %Alembic.Pagination.Page{number: 4, size: 10},
...> %{total_size: 15}
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "Page number (4) must be between 1 and the page count (2)",
meta: %{
"count" => 2,
"number" => 4
},
source: %Alembic.Source{
pointer: "/page/number"
},
status: "422",
title: "Page number must be between 1 and the page count"
}
]
}
}
Converts the page
back to params.
An Alembic.Pagination.Page.t
is converted to JSON.
iex> Alembic.Pagination.Page.to_params(%Alembic.Pagination.Page{number: 2, size: 10})
%{
"page" => %{
"number" => 2,
"size" => 10
}
}
The special value :all
, which indicates that pagination should be disabled and “all” pages should be returned at
once goes back to a nil
"page"
iex> Alembic.Pagination.Page.to_params(:all)
%{
"page" => nil
}
A nil
page on the other hand, has no params at all
iex> Alembic.Pagination.Page.to_params(nil)
%{}
Converts the page
back to query portion of URI
iex> Alembic.Pagination.Page.to_query(%Alembic.Pagination.Page{number: 2, size: 10})
"page%5Bnumber%5D=2&page%5Bsize%5D=10"