# `Cardbox.Query`
[🔗](https://github.com/hattoriai/cardbox/blob/v0.1.0/lib/cardbox/query.ex#L1)

Which records of a collection, in which order: a filter (conditions, in
groups of `and` and `or`), sorts, and a search.

A query has a wire format of plain maps and lists, which a saved view
keeps, a URL carries and an agent writes:

    %{
      "filter" => %{
        "and" => [
          %{"field" => "status", "op" => "in_group", "value" => ["todo", "doing"]},
          %{"or" => [
            %{"field" => "owner", "op" => "eq", "value" => "me"},
            %{"field" => "owner", "op" => "is_empty"}
          ]}
        ]
      },
      "sort" => [%{"field" => "due", "dir" => "asc"}],
      "search" => "invoice"
    }

`parse/3` reads it against a collection's fields: each field named by key
or by name, each operator one its type has, each value read for its type
(a choice's name becomes its id). An error says where it is and what to
write instead, for a person or an agent to correct. The conditions are
`Cardbox.Filter`'s and the sorts `Cardbox.Sort`'s.

`search` finds records with the words in a text field, or in the name of
a chosen choice, without case.

## Limits

Groups nest four deep, with at most 100 conditions in all and 10 sorts;
a search is at most 200 characters.

# `filter`

```elixir
@type filter() :: Cardbox.Filter.t() | {:and, [filter()]} | {:or, [filter()]} | nil
```

# `t`

```elixir
@type t() :: %Cardbox.Query{
  filter: filter(),
  search: String.t() | nil,
  sorts: [Cardbox.Sort.t()]
}
```

# `fields`

```elixir
@spec fields(t()) :: [String.t()]
```

The keys of the fields a query names, in its filter and its sorts.

# `parse`

```elixir
@spec parse(map() | t() | nil, Cardbox.Collection.t(), keyword()) ::
  {:ok, t()} | {:error, String.t()}
```

Reads a query of the wire format against the collection.

With `lenient: true`, a condition or a sort that does not check is left
out instead of failing the query: a saved view whose field was deleted
still opens, with what of it still holds.

# `to_wire`

```elixir
@spec to_wire(t()) :: map()
```

The query in the wire format.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
