README.md

# QueryElf

> A helper to build the most common database queries for [Ecto](https://hexdocs.pm/ecto/Ecto.html).

## Installation

Install from [Hex.pm](https://hex.pm/packages/query_elf):

```elixir
def deps do
  [{:query_elf, "~> 0.2.0"}]
end
```

## Documentation

API documentation is available at [https://hexdocs.pm/query_elf](https://hexdocs.pm/query_elf/api-reference.html)

## Usage

QueryElf helps to build and extend the common database queries for Ecto. It provides an elegant way of building complex Ecto queries using query composition. While it supports search, sort and paginate operations, it also allows extending the query builder using custom plugins. Production systems at Up Learn are powered by QueryElf.

Here's a simple example:

```elixir
defmodule MyQueryBuilder do
  use QueryElf,
    schema: MySchema,
    searchable_fields: [:id, :name],
    sortable_fields: [:id :name]

  def filter(:my_extra_filter, value, _query) do
    dynamic([s], s.some_field - ^value == 0)
  end
end

MyQueryBuilder.build_query(id__in: [1, 2, 3], my_extra_filter: 10)
```

More examples:

```elixir
  defmodule TestSchema do
    use Ecto.Schema

    embedded_schema do
      field :my_int, :integer
      field :my_string, :string
      field :my_bool, :boolean
      field :my_date, :date
    end
  end

  defmodule QB do
    use QueryElf,
      schema: TestSchema,
      searchable_fields: ~w[id my_int my_string my_bool my_date]a,
      sortable_fields: ~w[my_int my_bool]a
  end

  # Ordering on fields
  QB.build_query([],
    order: [%{field: :my_int, direction: :asc}, %{field: :my_bool, direction: :desc}]
  )

  # Shorthand expression for ordering example mentioned above
  QB.build_query([],
    order: [asc: :my_int, desc: :my_bool]
  )

  # Filtering on ID field
  QB.build_query(id__neq: 1)
  QB.build_query(id__in: [1, 2])

  # Filtering on integer field
  QB.build_query(my_int__gt: 1)
  QB.build_query(my_int__lte: 1)

  # Filtering on string field
  QB.build_query(my_string__starts_with: "a")
  QB.build_query(my_string__contains: "a")

  # Creating complex query using composition
  QB.build_query(
    _or: [
      my_bool: false,
      _and: [my_int: 1, id: "a"],
      _and: [my_int: 2, id: "b"]
    ]
  )

  # Creating reusable joins
  "table"
  |> reusable_join(:left, [t1], t2 in "other_table", on: t1.id == t2.id, as: :other_a)
  |> reusable_join(:left, [t1], t2 in "other_table", on: t1.id == t2.id, as: :other_b)
```

## Running tests

Clone the repo and fetch its dependencies:

```bash
git clone https://gitlab.com/up-learn-uk/query-elf.git
cd query-elf
mix deps.get
mix test
```

## Contributing

We appreciate any contribution to QueryElf. Check our [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) and [CONTRIBUTING.md](CONTRIBUTING.md) guides for more information. We usually keep a list of features and bugs [in the issue tracker](https://gitlab.com/up-learn-uk/query-elf/issues).

## Copyright and License

Copyright (c) 2020 Up Learn.

Query Elf source code is released under Apache License 2.0.

Check [LICENSE](LICENSE) file for more information.