README.md

# Scrivener.List [![Build Status](https://travis-ci.org/stephenmoloney/scrivener_list.svg)](https://travis-ci.org/stephenmoloney/scrivener_list) [![Hex Version](http://img.shields.io/hexpm/v/scrivener_list.svg?style=flat)](https://hex.pm/packages/scrivener_list) [![Hex docs](http://img.shields.io/badge/hex.pm-docs-green.svg?style=flat)](https://hexdocs.pm/scrivener_list)

[Scrivener.List](https://hex.pm/packages/scrivener_list) is a Scrivener compatible extension that
allows the pagination of a list of elements.

## Features 

  1. Scrivener.List extends the protocol `Scrivener.Paginater.paginate/2` from the [scrivener](https://github.com/drewolson/scrivener) library.
  2. Scrivener.List also extends the function `MyApp.Repo.paginate/2` from the [scrivener_ecto](https://github.com/drewolson/scrivener_ecto) library.
    
Using the second feature is entirely optional. It is provided as a convenience where the [scrivener_ecto](https://github.com/drewolson/scrivener_ecto) 
library is also being used in the project and gives access to the pre-configured `MyApp.Repo` module.


## Usage

## 1. Usage without a Repo module 


### Function 

```Scrivener.paginate(list, config)```

### Arguments

- ```list```: A list of elements to be paginated
- ```config```: A configuration object with the pagination details. Can be in any of the following formats:
     - ```%{page: page_number, page_size: page_size}``` (map)
     - ```[page: page_number, page_size: page_size]``` (Keyword.t)
     - ```%Scrivener.Config{page_number: page_number, page_size: page_size}``` (Scrivener.Config.t)

`max_page_size` **cannot** be configured with method 1.

### Examples

```elixir
def index(conn, params) do
  config = maybe_put_default_config(params)

  ["C#", "C++", "Clojure", "Elixir", "Erlang", "Go", "JAVA", "JavaScript", "Lisp",
    "PHP", "Perl", "Python", "Ruby", "Rust", "SQL"]
  |> Enum.map(&(&1 <> "  " <> "language"))
  |> Scrivener.paginate(config)

  render conn, :index,
    people: page.entries,
    page_number: page.page_number,
    page_size: page.page_size,
    total_pages: page.total_pages,
    total_entries: page.total_entries
end

defp maybe_put_default_config(%{page: page_number, page_size: page_size} = params), do: params
defp maybe_put_default_config(_params), do: %Scrivener.Config{page_number: 1, page_size: 10}
```


```elixir  
list = ["C#", "C++", "Clojure", "Elixir", "Erlang", "Go", "JAVA", "JavaScript", "Lisp",
        "PHP", "Perl", "Python", "Ruby", "Rust", "SQL"]
        
MyApp.Repo.paginate(list, %Scrivener.Config{page_number: 1, page_size: 4}) # %Scrivener.Config{}
MyApp.Repo..paginate(list, page: 1, page_size: 4) # keyword list
MyApp.Repo.paginate(%{page: 1, page_size: 4}) # map
MyApp.Repo.paginate(%{page: 1}) # map with only page number (page_size defaults to 10)
```


## 2. Usage with a Repo module

Usage without a Repo is entirely optional and is added to `Scrivener.List` for convenience. 
Firstly, see [Scrivener.Ecto](https://github.com/drewolson/scrivener_ecto) and configure the `MyApp.Repo` module.

### Example Repo configuration

```elixir
defmodule MyApp.Repo do
  use Ecto.Repo, otp_app: :my_app
  use Scrivener, page_size: 10, max_page_size: 100
end
```

### Function 

```MyApp.Repo.paginate(list, config)```

### Arguments

- ```list```: A list of elements to be paginated
- ```config```: A configuration object with the pagination details. Can be in any of the following formats:
     - ```%{page: page_number, page_size: page_size}``` (map)
     - ```[page: page_number, page_size: page_size]``` (Keyword.t)
     - ```%Scrivener.Config{page_number: page_number, page_size: page_size}``` (Scrivener.Config.t)

`max_page_size` **can** be configured with method 1. See [Scrivener.Ecto](https://github.com/drewolson/scrivener_ecto).

### Example

Example based on [scrivener_ecto](https://github.com/drewolson/scrivener_ecto) readme.


```elixir
def index(conn, params) do
  %{age: age, name: name} = params["search"] 
  
  page = MyApp.Person
  |> where([p], p.age > ^age)
  |> order_by([p], desc: p.age)
  |> preload(:friends)
  |> MyApp.Repo.all()
  |> Enum.filter(fn(person) -> person.data.friend.name = name end)
  |> MyApp.Repo.paginate(params)

  render conn, :index,
    people: page.entries,
    page_number: page.page_number,
    page_size: page.page_size,
    total_pages: page.total_pages,
    total_entries: page.total_entries
end
```


## Installation

Add [scrivener_list](https://hex.pm/packages/scrivener_list) to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:scrivener_list, "~> 1.0"}
  ]
end
```


## Tests

```shell
mix test
```


## Acknowledgements

Thanks to [Drew Olson](https://github.com/drewolson) for helping with this, particularly the introduction of the [protocol](http://blog.drewolson.org/extensible-design-with-protocols/).


## Licence

MIT