Skip to content
Open
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
3 changes: 3 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
## next
* Don't require postgrex as a runtime dependency

## v0.10.0 (2023-03-01)
* Add support for `per_page` param
* Add `.formatter.exs` file and format the project
* Bump PhoenixHTML from 2.10.4 to 3.3.1
* Bump required Elixir version from 1.2 to 1.4

## v0.4.0 (2016-10-01)
* Bugfix handle list in query params

Expand All @@ -21,4 +27,4 @@
* Update deps
* Buxfix minor
## v0.0.1 (2016-03-10)
* Initial Release
* Initial Release
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

Pagination for Ecto and Phoenix.

This is a fork of the original [Kerosene](https://github.com/elixirdrops/kerosene), which seems to have been abandoned :(

Another good fork to consider - [Dissolver](https://github.com/MorphicPro/dissolver)... or any of the other pagination libraries that came up since Kerosene was created!

## Installation

Expand All @@ -10,25 +13,25 @@ The package is [available in Hex](https://hex.pm/packages/kerosene), the package
Add kerosene to your list of dependencies in `mix.exs`:
```elixir
def deps do
[{:kerosene, "~> 0.9.0"}]
[{:kerosene, "~> 0.10.0"}]
end
```

Add Kerosene to your `repo.ex`:
```elixir
defmodule MyApp.Repo do
use Ecto.Repo,
otp_app: :testapp,
use Ecto.Repo,
otp_app: :my_app,
adapter: Ecto.Adapters.Postgres
use Kerosene, per_page: 2
end
```

## Usage
Start paginating your queries
Start paginating your queries
```elixir
def index(conn, params) do
{products, kerosene} =
{products, kerosene} =
Product
|> Product.with_lowest_price
|> Repo.paginate(params)
Expand All @@ -37,7 +40,7 @@ def index(conn, params) do
end
```

Add view helpers to your view
Add view helpers to your view
```elixir
defmodule MyApp.ProductView do
use MyApp.Web, :view
Expand All @@ -50,7 +53,7 @@ Generate the links using the view helpers
<%= paginate @conn, @kerosene %>
```

Kerosene provides a [list ](https://hexdocs.pm/kerosene/Kerosene.HTML.html#__using__/1) of themes for pagination. By default it uses bootstrap. To use some other, add to config/config.exs:
Kerosene provides a [list](https://hexdocs.pm/kerosene/Kerosene.HTML.html#__using__/1) of themes for pagination. By default it uses bootstrap. To use some other, add to config/config.exs:
```elixir
config :kerosene,
theme: :foundation
Expand Down Expand Up @@ -87,7 +90,7 @@ end
You can also send in options to paginate helper look at the docs for more details.

## Contributing

Please do send pull requests and bug reports, positive feedback is always welcome.


Expand Down
5 changes: 2 additions & 3 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ use Mix.Config
# Configuration from the imported file will override the ones defined
# here (which is why it is important to import them last).
#
import_config "#{Mix.env}.exs"
import_config "#{Mix.env()}.exs"

config :kerosene, :html,
theme: :bootstrap
config :kerosene, :html, theme: :bootstrap
2 changes: 1 addition & 1 deletion config/prod.exs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
use Mix.Config
use Mix.Config
27 changes: 13 additions & 14 deletions config/test.exs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use Mix.Config

config :kerosene, ecto_repos: [Kerosene.Repo]

config :kerosene, Kerosene.Repo,
username: "postgres",
password: "postgres",
database: "kerosene_dev",
hostname: "localhost",
pool: Ecto.Adapters.SQL.Sandbox

# shut up only log errors
config :logger, :console,
level: :error
use Mix.Config

config :kerosene, ecto_repos: [Kerosene.Repo]

config :kerosene, Kerosene.Repo,
username: "postgres",
password: "postgres",
database: "kerosene_dev",
hostname: "localhost",
pool: Ecto.Adapters.SQL.Sandbox

# shut up only log errors
config :logger, :console, level: :error
61 changes: 46 additions & 15 deletions lib/kerosene.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
defmodule Kerosene do
defstruct items: [], per_page: 0, max_page: 0, page: 0, total_pages: 0, total_count: 0, params: []
defstruct items: [],
per_page: 0,
max_page: 0,
page: 0,
total_pages: 0,
total_count: 0,
params: []

import Ecto.Query

@per_page 10
Expand All @@ -13,8 +20,7 @@ defmodule Kerosene do
defmacro __using__(opts \\ []) do
quote do
def paginate(query, params \\ %{}, options \\ []) do
Kerosene.paginate( __MODULE__, query, params,
Keyword.merge(unquote(opts), options))
Kerosene.paginate(__MODULE__, query, params, Keyword.merge(unquote(opts), options))
end
end
end
Expand All @@ -31,7 +37,7 @@ defmodule Kerosene do
page = get_page(opts, total_pages)
offset = get_offset(total_count, page, per_page)

kerosene = %Kerosene {
kerosene = %Kerosene{
per_page: per_page,
page: page,
total_pages: total_pages,
Expand All @@ -44,18 +50,22 @@ defmodule Kerosene do
end

defp get_items(repo, query, nil, _), do: repo.all(query)

defp get_items(repo, query, limit, offset) do
query
|> limit(^limit)
|> offset(^offset)
|> repo.all
end

defp get_offset(_total_pages, _page, nil), do: 0

defp get_offset(total_pages, page, per_page) do
page = case page > total_pages do
true -> total_pages
_ -> page
end
page =
case page > total_pages do
true -> total_pages
_ -> page
end

case page > 0 do
true -> (page - 1) * per_page
Expand All @@ -76,11 +86,12 @@ defmodule Kerosene do
total_pages || 0
end

defp total_count(query = %{group_bys: [_|_]}), do: total_row_count(query)
defp total_count(query = %{group_bys: [_ | _]}), do: total_row_count(query)
defp total_count(query = %{from: %{source: {_, nil}}}), do: total_row_count(query)

defp total_count(query) do
primary_key = get_primary_key(query)

query
|> exclude(:select)
|> select([i], count(field(i, ^primary_key), :distinct))
Expand All @@ -93,17 +104,19 @@ defmodule Kerosene do
end

def get_primary_key(query) do
new_query = case is_map(query) do
true -> query.from.source |> elem(1)
_ -> query
end
new_query =
case is_map(query) do
true -> query.from.source |> elem(1)
_ -> query
end

new_query
|> apply(:__schema__, [:primary_key])
|> hd
end

def get_total_pages(_, nil), do: 1

def get_total_pages(count, per_page) do
Float.ceil(count / per_page) |> trunc()
end
Expand All @@ -117,11 +130,27 @@ defmodule Kerosene do

defp build_options(opts, params) do
page = Map.get(params, "page", @page) |> to_integer()
per_page = default_per_page(opts) |> to_integer()
per_page = get_per_page(params, opts)
max_page = Keyword.get(opts, :max_page, default_max_page())
Keyword.merge(opts, [page: page, per_page: per_page, params: params, max_page: max_page])
Keyword.merge(opts, page: page, per_page: per_page, params: params, max_page: max_page)
end

defp get_per_page(%{"per_page" => "all"}, _opts), do: nil

defp get_per_page(%{"per_page" => per_page}, opts)
when is_integer(per_page) or is_binary(per_page) do
per_page =
if to_integer(per_page) > 0 do
per_page
else
default_per_page(opts)
end

to_integer(per_page)
end

defp get_per_page(_params, opts), do: opts |> default_per_page() |> to_integer()

defp default_per_page(opts) do
case Keyword.get(opts, :per_page) do
nil -> Application.get_env(:kerosene, :per_page, @per_page)
Expand All @@ -134,11 +163,13 @@ defmodule Kerosene do
end

def to_integer(i) when is_integer(i), do: abs(i)

def to_integer(i) when is_binary(i) do
case Integer.parse(i) do
{n, _} -> n
_ -> 0
end
end

def to_integer(_), do: @page
end
Loading