# Filterable
[![Build Status](https://travis-ci.org/omohokcoj/filterable.svg?branch=master)](https://travis-ci.org/omohokcoj/filterable)
[![Code Climate](https://codeclimate.com/github/omohokcoj/filterable/badges/gpa.svg)](https://codeclimate.com/github/omohokcoj/filterable)
[![Coverage Status](https://coveralls.io/repos/github/omohokcoj/filterable/badge.svg?branch=master)](https://coveralls.io/github/omohokcoj/filterable?branch=master)
[![Inline docs](http://inch-ci.org/github/omohokcoj/filterable.svg?branch=master)](http://inch-ci.org/github/omohokcoj/filterable)
Filterable allows to map incoming query parameters to filter functions.
The goal is to provide minimal and easy to use DSL for building filters using pure Elixir.
Filterable doesn't depend on external libraries or frameworks and can be used both in Phoenix and pure Elixir projects.
Inspired by [has_scope](https://github.com/plataformatec/has_scope).
## Installation
Add `filterable` to your mix.exs.
```elixir
{:filterable, "~> 0.4.0"}
```
## Usage
#### Phoenix controller
```elixir
defmodule MyApp.PostController do
use MyApp.Web, :controller
use Filterable.Phoenix.Controller
filterable do
filter author(query, value, _conn) do
query |> where(author_name: ^value)
end
end
# /posts?author=Tom
def index(conn, params) do
with {:ok, query, filter_values} <- apply_filters(Post, conn),
posts <- Repo.all(query),
do: render(conn, "index.json", posts: posts, meta: filter_values)
end
end
```
If you prefere to handle errors using exceptions then use `apply_filters!`:
```elixir
def index(conn, params) do
{query, filter_values} = apply_filters!(Post, conn)
render(conn, "index.json", posts: Repo.all(posts), meta: filter_values)
end
```
#### Phoenix model
```elixir
defmodule MyApp.Post do
use MyApp.Web, :model
use Filterable.Phoenix.Model
filterable do
filter author(query, value, _conn) do
query |> where(author_name: ^value)
end
end
schema "posts" do
...
end
end
# /posts?author=Tom
def index(conn, params, conn) do
with {:ok, query, filter_values} <- Post.apply_filters(conn),
posts <- Repo.all(query),
do: render(conn, "index.json", posts: posts, meta: filter_values)
end
```
## Defining filters
*TODO*
## Common usage
```elixir
defmodule RepoFilters do
use Filterable.DSL
filter name(list, value) do
list |> Enum.filter(& &1.name == value)
end
filter stars(list, value) do
list |> Enum.filter(& &1.stars >= value)
end
end
repos = [%{name: "phoenix", stars: 8565}, %{name: "ecto", start: 2349}]
{:ok, result, filter_values} = RepoFilters.apply_filters(repos, %{name: "phoenix", stars: 8000})
```
## TODO:
- [X] Coverage 100%
- [ ] Update README
- [ ] Documentation
- [X] Improve tests
## Contribution
Feel free to send your PR with proposals, improvements or corrections!