# `Flop.Filter`
[🔗](https://github.com/woylie/flop/blob/0.26.4/lib/flop/filter.ex#L1)

Defines a filter.

# `op`

```elixir
@type op() ::
  :==
  | :!=
  | :=~
  | :empty
  | :not_empty
  | :&lt;=
  | :&lt;
  | :&gt;=
  | :&gt;
  | :in
  | :not_in
  | :contains
  | :not_contains
  | :like
  | :not_like
  | :like_and
  | :like_or
  | :ilike
  | :not_ilike
  | :ilike_and
  | :ilike_or
  | :starts_with
  | :ends_with
```

Represents valid filter operators.

| Operator        | Value               | WHERE clause                                            |
| :-------------- | :------------------ | ------------------------------------------------------- |
| `:==`           | `"Salicaceae"`      | `WHERE column = 'Salicaceae'`                           |
| `:!=`           | `"Salicaceae"`      | `WHERE column != 'Salicaceae'`                          |
| `:=~`           | `"cyth"`            | `WHERE column ILIKE '%cyth%'`                           |
| `:empty`        | `true`              | `WHERE (column IS NULL) = true`                         |
| `:empty`        | `false`             | `WHERE (column IS NULL) = false`                        |
| `:not_empty`    | `true`              | `WHERE (column IS NOT NULL) = true`                     |
| `:not_empty`    | `false`             | `WHERE (column IS NOT NULL) = false`                    |
| `:<=`           | `10`                | `WHERE column <= 10`                                    |
| `:<`            | `10`                | `WHERE column < 10`                                     |
| `:>=`           | `10`                | `WHERE column >= 10`                                    |
| `:>`            | `10`                | `WHERE column > 10`                                     |
| `:in`           | `["pear", "plum"]`  | `WHERE column = ANY('pear', 'plum')`                    |
| `:not_in`       | `["pear", "plum"]`  | `WHERE column = NOT IN('pear', 'plum')`                 |
| `:contains`     | `"pear"`            | `WHERE 'pear' = ANY(column)`                            |
| `:not_contains` | `"pear"`            | `WHERE 'pear' = NOT IN(column)`                         |
| `:like`         | `"cyth"`            | `WHERE column LIKE '%cyth%'`                            |
| `:not_like`     | `"cyth"`            | `WHERE column NOT LIKE '%cyth%'`                        |
| `:like_and`     | `["Rubi", "Rosa"]`  | `WHERE column LIKE '%Rubi%' AND column LIKE '%Rosa%'`   |
| `:like_and`     | `"Rubi Rosa"`       | `WHERE column LIKE '%Rubi%' AND column LIKE '%Rosa%'`   |
| `:like_or`      | `["Rubi", "Rosa"]`  | `WHERE column LIKE '%Rubi%' OR column LIKE '%Rosa%'`    |
| `:like_or`      | `"Rubi Rosa"`       | `WHERE column LIKE '%Rubi%' OR column LIKE '%Rosa%'`    |
| `:ilike`        | `"cyth"`            | `WHERE column ILIKE '%cyth%'`                           |
| `:not_ilike`    | `"cyth"`            | `WHERE column NOT ILIKE '%cyth%'`                       |
| `:ilike_and`    | `["Rubi", "Rosa"]`  | `WHERE column ILIKE '%Rubi%' AND column ILIKE '%Rosa%'` |
| `:ilike_and`    | `"Rubi Rosa"`       | `WHERE column ILIKE '%Rubi%' AND column ILIKE '%Rosa%'` |
| `:ilike_or`     | `["Rubi", "Rosa"]`  | `WHERE column ILIKE '%Rubi%' OR column ILIKE '%Rosa%'`  |
| `:ilike_or`     | `"Rubi Rosa"`       | `WHERE column ILIKE '%Rubi%' OR column ILIKE '%Rosa%'`  |
| `:starts_with`  | `"Gia"`             | `WHERE column ILIKE 'Gia%'`                             |
| `:ends_with`    | `"Hoang"`           | `WHERE column ILIKE '%Hoang'`                           |

The filter operators `:empty` and `:not_empty` will regard empty arrays as
empty values if the field is known to be an array field.

The filter operators `:ilike_and`, `:ilike_or`, `:like_and` and `:like_or`
accept both strings and list of strings.

- If the filter value is a string, it will be split at whitespace characters
  and the segments are combined with `and` or `or`.
- If a list of strings is passed, the individual strings are not split, and
  the list items are combined with `and` or `or`.

# `t`

```elixir
@type t() :: %Flop.Filter{field: atom() | String.t(), op: op(), value: any()}
```

Represents filter query parameters.

### Fields

- `field`: The field the filter is applied to. The allowed fields can be
  restricted by deriving `Flop.Schema` in your Ecto schema.
- `op`: The filter operator.
- `value`: The comparison value of the filter.

# `allowed_operators`

```elixir
@spec allowed_operators(Flop.FieldInfo.t() | Flop.Schema.ecto_type() | nil) :: [op()]
```

Returns the allowed operators for the given Ecto type.

If the given value is not a native Ecto type, a list with all operators is
returned.

    iex> allowed_operators(:integer)
    [:==, :!=, :empty, :not_empty, :<=, :<, :>=, :>, :in, :not_in]

# `allowed_operators`

```elixir
@spec allowed_operators(atom(), atom()) :: [op()]
```

Returns the allowed operators for the given schema module and field.

For regular Ecto schema fields, the type is derived via schema reflection.

If the given schema module derives `Flop.Schema`, the type of join and
custom fields is determined via the `ecto_type` option. Compound files are
always handled as string fields, minus unsupported operators.

If the type cannot be determined or if the type is not a native Ecto type, a
list with all operators is returned.

    iex> allowed_operators(Pet, :age)
    [:==, :!=, :empty, :not_empty, :<=, :<, :>=, :>, :in, :not_in]

# `delete`
*since 0.19.0* 

```elixir
@spec delete([t()] | [map()] | map(), atom()) :: [t()] | [map()]
```

Deletes the filters for the given field from a list of filters.

## Examples

### Flop.Filter struct

    iex> delete(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8}
    ...>   ],
    ...>   :name
    ...> )
    [%Flop.Filter{field: :age, op: :>, value: 8}]

    iex> delete(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    [%Flop.Filter{field: :age, op: :>, value: 8}]

    iex> delete([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :age)
    [%Flop.Filter{field: :name, op: :==, value: "Joe"}]

### Map with atom keys

    iex> delete(
    ...>   [
    ...>     %{field: :name, op: :==, value: "Joe"},
    ...>     %{field: :age, op: :>, value: 8}
    ...>   ],
    ...>   :name
    ...> )
    [%{field: :age, op: :>, value: 8}]

### Map with string keys

    iex> delete(
    ...>   [
    ...>     %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     %{"field" => "age", "op" => ">", "value" => "8"}
    ...>   ],
    ...>   :name
    ...> )
    [%{"field" => "age", "op" => ">", "value" => "8"}]

### Indexed map

Filters passed as an indexed map will be converted to a list, even if no
matching filter exists.

    iex> delete(
    ...>   %{
    ...>     0 => %{field: "name", op: "==", value: "Joe"},
    ...>     1 => %{field: "age", op: ">", value: "8"}
    ...>   },
    ...>   :name
    ...> )
    [%{field: "age", op: ">", value: "8"}]

    iex> delete(
    ...>   %{
    ...>     "0" => %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     "1" => %{"field" => "age", "op" => ">", "value" => "8"}
    ...>   },
    ...>   :name
    ...> )
    [%{"field" => "age", "op" => ">", "value" => "8"}]

# `delete_first`
*since 0.19.0* 

```elixir
@spec delete_first([t()] | [map()] | map(), atom()) :: [t()] | [map()]
```

Deletes the first filter in list of filters for the given field.

## Examples

### Flop.Filter struct

    iex> delete_first(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    [
      %Flop.Filter{field: :age, op: :>, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ]

    iex> delete_first([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :age)
    [%Flop.Filter{field: :name, op: :==, value: "Joe"}]

### Map with atom keys

    iex> delete_first(
    ...>   [
    ...>     %{field: :name, op: :==, value: "Joe"},
    ...>     %{field: :age, op: :>, value: 8},
    ...>     %{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    [
      %{field: :age, op: :>, value: 8},
      %{field: :name, op: :==, value: "Jim"}
    ]

### Map with string keys

    iex> delete_first(
    ...>   [
    ...>     %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     %{"field" => "age", "op" => ">", "value" => 8},
    ...>     %{"field" => "name", "op" => "==", "value" => "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    [
      %{"field" => "age", "op" => ">", "value" => 8},
      %{"field" => "name", "op" => "==", "value" => "Jim"}
    ]

    iex> delete_first(
    ...>   [
    ...>     %{"field" => :name, "op" => :==, "value" => "Joe"},
    ...>     %{"field" => :age, "op" => :>, "value" => 8},
    ...>     %{"field" => :name, "op" => :==, "value" => "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    [
      %{"field" => :age, "op" => :>, "value" => 8},
      %{"field" => :name, "op" => :==, "value" => "Jim"}
    ]

### Indexed map

Filters passed as an indexed map will be converted to a list, even if no
matching filter exists.

    iex> delete_first(
    ...>   %{
    ...>     0 => %{field: "name", op: "==", value: "Joe"},
    ...>     1 => %{field: "age", op: ">", value: 8},
    ...>     2 => %{field: "name", op: "==", value: "Jim"}
    ...>   },
    ...>   :name
    ...> )
    [
      %{field: "age", op: ">", value: 8},
      %{field: "name", op: "==", value: "Jim"}
    ]

    iex> delete_first(
    ...>   %{
    ...>     "0" => %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     "1" => %{"field" => "age", "op" => ">", "value" => 8},
    ...>     "2" => %{"field" => "name", "op" => "==", "value" => "Jim"}
    ...>   },
    ...>   :name
    ...> )
    [
      %{"field" => "age", "op" => ">", "value" => 8},
      %{"field" => "name", "op" => "==", "value" => "Jim"}
    ]

# `drop`
*since 0.19.0* 

```elixir
@spec drop([t()] | [map()] | map(), [atom()]) :: [t()] | [map()]
```

Removes the filters for the given fields from a list of filters.

## Examples

### Flop.Filter struct

    iex> drop(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :color, op: :==, value: "blue"}
    ...>   ],
    ...>   [:name, :color]
    ...> )
    [%Flop.Filter{field: :age, op: :>, value: 8}]

    iex> drop(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :color, op: :==, value: "blue"},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   [:name, :species]
    ...> )
    [
      %Flop.Filter{field: :age, op: :>, value: 8},
      %Flop.Filter{field: :color, op: :==, value: "blue"}
    ]

### Map with atom keys

    iex> drop(
    ...>   [
    ...>     %{field: :name, op: :==, value: "Joe"},
    ...>     %{field: :age, op: :>, value: 8},
    ...>     %{field: :color, op: :==, value: "blue"}
    ...>   ],
    ...>   [:name, :color]
    ...> )
    [%{field: :age, op: :>, value: 8}]

### Map with string keys

    iex> drop(
    ...>   [
    ...>     %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     %{"field" => "age", "op" => ">", "value" => "8"},
    ...>     %{"field" => "color", "op" => "==", "value" => "blue"}
    ...>   ],
    ...>   [:name, :color]
    ...> )
    [%{"field" => "age", "op" => ">", "value" => "8"}]

    iex> drop(
    ...>   [
    ...>     %{"field" => :name, "op" => :==, "value" => "Joe"},
    ...>     %{"field" => :age, "op" => :>, "value" => "8"},
    ...>     %{"field" => :color, "op" => :==, "value" => "blue"}
    ...>   ],
    ...>   [:name, :color]
    ...> )
    [%{"field" => :age, "op" => :>, "value" => "8"}]

### Indexed map

Filters passed as an indexed map will be converted to a list, even if no
matching filter exists.

    iex> drop(
    ...>   %{
    ...>     0 => %{field: "name", op: "==", value: "Joe"},
    ...>     1 => %{field: "age", op: ">", value: "8"},
    ...>     2 => %{field: "color", op: "==", value: "blue"}
    ...>   },
    ...>   [:name, :color]
    ...> )
    [%{field: "age", op: ">", value: "8"}]

    iex> drop(
    ...>   %{
    ...>     "0" => %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     "1" => %{"field" => "age", "op" => ">", "value" => "8"},
    ...>     "2" => %{"field" => "color", "op" => "==", "value" => "blue"}
    ...>   },
    ...>   [:name, :color]
    ...> )
    [%{"field" => "age", "op" => ">", "value" => "8"}]

# `fetch`
*since 0.19.0* 

```elixir
@spec fetch([t()] | [map()] | map(), atom()) :: {:ok, t() | map()} | :error
```

Fetches the first filter for the given field and returns it in a tuple.

## Examples

### Flop.Filter struct

    iex> fetch([], :name)
    :error

    iex> fetch([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :name)
    {:ok, %Flop.Filter{field: :name, op: :==, value: "Joe"}}

    iex> fetch([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :age)
    :error

    iex> fetch(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    {:ok, %Flop.Filter{field: :name, op: :==, value: "Joe"}}

### Map with atom keys

    iex> fetch([%{field: :name, op: :==, value: "Joe"}], :name)
    {:ok, %{field: :name, op: :==, value: "Joe"}}

### Map with string keys

    iex> fetch([%{"field" => "name", "op" => "==", "value" => "Joe"}], :name)
    {:ok, %{"field" => "name", "op" => "==", "value" => "Joe"}}

### Indexed map

    iex> fetch(
    ...>   %{0 => %{field: "name", op: "==", value: "Joe"}},
    ...>   :name
    ...> )
    {:ok, %{field: "name", op: "==", value: "Joe"}}

    iex> fetch(
    ...>   %{"0" => %{"field" => "name", "op" => "==", "value" => "Joe"}},
    ...>   :name
    ...> )
    {:ok, %{"field" => "name", "op" => "==", "value" => "Joe"}}

# `fetch_value`
*since 0.20.0* 

```elixir
@spec fetch_value([t()] | [map()] | map(), atom()) :: {:ok, any()} | :error
```

Fetches the first filter value for the given field and returns it in a tuple.

## Examples

### Flop.Filter struct

    iex> fetch_value([], :name)
    :error

    iex> fetch_value([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :name)
    {:ok, "Joe"}

    iex> fetch_value([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :age)
    :error

    iex> fetch_value(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    {:ok, "Joe"}

### Map with atom keys

    iex> fetch_value([%{field: :name, op: :==, value: "Joe"}], :name)
    {:ok, "Joe"}

### Map with string keys

    iex> fetch_value(
    ...>   [%{"field" => "name", "op" => "==", "value" => "Joe"}],
    ...>   :name
    ...> )
    {:ok, "Joe"}

### Indexed map

    iex> fetch_value(
    ...>   %{0 => %{field: "name", op: "==", value: "Joe"}},
    ...>   :name
    ...> )
    {:ok, "Joe"}

    iex> fetch_value(
    ...>   %{"0" => %{"field" => "name", "op" => "==", "value" => "Joe"}},
    ...>   :name
    ...> )
    {:ok, "Joe"}

# `get`
*since 0.19.0* 

```elixir
@spec get([t()] | [map()] | map(), atom()) :: t() | map() | nil
```

Returns the first filter for the given field.

## Examples

### Flop.Filter struct

    iex> get([], :name)
    nil

    iex> get([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :name)
    %Flop.Filter{field: :name, op: :==, value: "Joe"}

    iex> get([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :age)
    nil

    iex> get(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    %Flop.Filter{field: :name, op: :==, value: "Joe"}

### Map with atom keys

    iex> get([%{field: :name, op: :==, value: "Joe"}], :name)
    %{field: :name, op: :==, value: "Joe"}

### Map with string keys

    iex> get([%{"field" => "name", "op" => "==", "value" => "Joe"}], :name)
    %{"field" => "name", "op" => "==", "value" => "Joe"}

    iex> get([%{"field" => :name, "op" => "==", "value" => "Joe"}], :name)
    %{"field" => :name, "op" => "==", "value" => "Joe"}

### Indexed map

    iex> get(
    ...>   %{0 => %{field: "name", op: "==", value: "Joe"}},
    ...>   :name
    ...> )
    %{field: "name", op: "==", value: "Joe"}

    iex> get(
    ...>   %{0 => %{field: :name, op: "==", value: "Joe"}},
    ...>   :name
    ...> )
    %{field: :name, op: "==", value: "Joe"}

    iex> get(
    ...>   %{"0" => %{"field" => "name", "op" => "==", "value" => "Joe"}},
    ...>   :name
    ...> )
    %{"field" => "name", "op" => "==", "value" => "Joe"}

    iex> get(
    ...>   %{"0" => %{"field" => :name, "op" => "==", "value" => "Joe"}},
    ...>   :name
    ...> )
    %{"field" => :name, "op" => "==", "value" => "Joe"}

# `get_all`
*since 0.19.0* 

```elixir
@spec get_all([t()] | [map()] | map(), atom()) :: [t()] | [map()]
```

Returns the all filters for the given field.

## Examples

### Flop.Filter struct

    iex> get_all([], :name)
    []

    iex> get_all([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :name)
    [%Flop.Filter{field: :name, op: :==, value: "Joe"}]

    iex> get_all([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :age)
    []

    iex> get_all(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    [
      %Flop.Filter{field: :name, op: :==, value: "Joe"},
      %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ]

### Map with atom keys

    iex> get_all(
    ...>   [
    ...>     %{field: :name, op: :==, value: "Joe"},
    ...>     %{field: :age, op: :>, value: 8},
    ...>     %{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    [
      %{field: :name, op: :==, value: "Joe"},
      %{field: :name, op: :==, value: "Jim"}
    ]

### Map with string keys

    iex> get_all(
    ...>   [
    ...>     %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     %{"field" => "age", "op" => ">", "value" => 8},
    ...>     %{"field" => "name", "op" => "==", "value" => "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    [
      %{"field" => "name", "op" => "==", "value" => "Joe"},
      %{"field" => "name", "op" => "==", "value" => "Jim"}
    ]

### Indexed map

    iex> get_all(
    ...>   %{
    ...>     0 => %{field: "name", op: "==", value: "Joe"},
    ...>     1 => %{field: "age", op: ">", value: 8},
    ...>     2 => %{field: "name", op: "==", value: "Jim"}
    ...>   },
    ...>   :name
    ...> )
    [
      %{field: "name", op: "==", value: "Joe"},
      %{field: "name", op: "==", value: "Jim"}
    ]

    iex> get_all(
    ...>   %{
    ...>     "0" => %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     "1" => %{"field" => "age", "op" => ">", "value" => 8},
    ...>     "2" => %{"field" => "name", "op" => "==", "value" => "Jim"}
    ...>   },
    ...>   :name
    ...> )
    [
      %{"field" => "name", "op" => "==", "value" => "Joe"},
      %{"field" => "name", "op" => "==", "value" => "Jim"}
    ]

# `get_value`
*since 0.20.0* 

```elixir
@spec get_value([t()] | [map()] | map(), atom()) :: any() | nil
```

Returns the first filter value for the given field.

## Examples

### Flop.Filter struct

    iex> get_value([], :name)
    nil

    iex> get_value([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :name)
    "Joe"

    iex> get_value([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :age)
    nil

    iex> get_value(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   :name
    ...> )
    "Joe"

    iex> get_value([%Flop.Filter{field: :ok, op: :empty, value: false}], :ok)
    false

### Map with atom keys

    iex> get_value([%{field: :name, op: :==, value: "Joe"}], :name)
    "Joe"

### Map with string keys

    iex> get_value(
    ...>   [%{"field" => "name", "op" => "==", "value" => "Joe"}],
    ...>   :name
    ...> )
    "Joe"

### Indexed map

    iex> get_value(
    ...>   %{0 => %{field: "name", op: "==", value: "Joe"}},
    ...>   :name
    ...> )
    "Joe"

    iex> get_value(
    ...>   %{"0" => %{"field" => "name", "op" => "==", "value" => "Joe"}},
    ...>   :name
    ...> )
    "Joe"

# `new`
*since 0.19.0* 

```elixir
@spec new(
  Enumerable.t(),
  keyword()
) :: [t()]
```

Creates a list of filters from an enumerable.

The default operator is `:==`.

    iex> filters = new(%{name: "George", age: 8})
    iex> Enum.sort(filters)
    [
      %Flop.Filter{field: :age, op: :==, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "George"}
    ]

    iex> filters = new([name: "George", age: 8])
    iex> Enum.sort(filters)
    [
      %Flop.Filter{field: :age, op: :==, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "George"}
    ]

You can optionally pass a mapping from field names to operators as a map
with atom keys.

    iex> filters = new(
    ...>   %{name: "George", age: 8},
    ...>   operators: %{name: :ilike_and}
    ...> )
    iex> Enum.sort(filters)
    [
      %Flop.Filter{field: :age, op: :==, value: 8},
      %Flop.Filter{field: :name, op: :ilike_and, value: "George"}
    ]

You can also pass a map to rename fields.

    iex> filters = new(
    ...>   %{s: "George", age: 8},
    ...>   rename: %{s: :name}
    ...> )
    iex> Enum.sort(filters)
    [
      %Flop.Filter{field: :age, op: :==, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "George"}
    ]

    iex> filters = new(
    ...>   %{s: "George", cat: true},
    ...>   rename: %{s: :name, cat: :dog}
    ...> )
    iex> Enum.sort(filters)
    [
      %Flop.Filter{field: :dog, op: :==, value: true},
      %Flop.Filter{field: :name, op: :==, value: "George"}
    ]

If both a rename option and an operator are set for a field, the operator
option needs to use the new field name.

    iex> new(
    ...>   %{n: "George"},
    ...>   rename: %{n: :name},
    ...>   operators: %{name: :ilike_or}
    ...> )
    [%Flop.Filter{field: :name, op: :ilike_or, value: "George"}]

If the enumerable uses string keys as field names, the function attempts to
convert them to existing atoms. If the atom does not exist, the filter is
removed from the list.

    iex> new(%{"name" => "George", "age" => 8})
    [
      %Flop.Filter{field: :age, op: :==, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "George"}
    ]

    iex> new(%{"name" => "George", "doesnotexist" => 8})
    [
      %Flop.Filter{field: :name, op: :==, value: "George"}
    ]

Other key types are also removed.

    iex> new(%{"name" => "George", 2 => 8})
    [
      %Flop.Filter{field: :name, op: :==, value: "George"}
    ]

# `pop`
*since 0.19.0* 

```elixir
@spec pop([t()] | [map()] | map(), atom(), any()) ::
  {t() | any(), [t()]} | {map() | any(), [map()]}
```

Returns the first filter for the given field and removes all other filters for
the same field from the filter list.

Returns a tuple with the first matching filter for `key` and the remaining
filter list. If there is no filter for the field in the list, the default
value is returned as the first tuple element.

See also `Flop.Filter.pop_first/3`, `Flop.Filter.pop_value/3` and
`Flop.Filter.pop_first_value/3`.

## Examples

### Flop.Filter struct

    iex> pop([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :name)
    {%Flop.Filter{field: :name, op: :==, value: "Joe"}, []}

    iex> pop([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :age)
    {nil, [%Flop.Filter{field: :name, op: :==, value: "Joe"}]}

    iex> pop(
    ...>   [%Flop.Filter{field: :name, op: :==, value: "Joe"}],
    ...>   :age,
    ...>   %Flop.Filter{field: :age, op: :>, value: 8}
    ...> )
    {
      %Flop.Filter{field: :age, op: :>, value: 8},
      [%Flop.Filter{field: :name, op: :==, value: "Joe"}]
    }

    iex> pop(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"},
    ...>   ],
    ...>   :name
    ...> )
    {
      %Flop.Filter{field: :name, op: :==, value: "Joe"},
      [%Flop.Filter{field: :age, op: :>, value: 8}]
    }

### Map with atom keys

    iex> pop([%{field: :name, op: :==, value: "Joe"}], :name)
    {%{field: :name, op: :==, value: "Joe"}, []}

### Map with string keys

    iex> pop([%{"field" => "name", "op" => "==", "value" => "Joe"}], :name)
    {%{"field" => "name", "op" => "==", "value" => "Joe"}, []}

### Indexed map

Filters passed as an indexed map will be converted to a list, even if no
matching filter exists.

    iex> pop(
    ...>   %{
    ...>     0 => %{field: "name", op: "==", value: "Joe"},
    ...>     1 => %{field: "age", op: ">", value: "8"},
    ...>     2 => %{field: "name", op: "==", value: "Jim"},
    ...>   },
    ...>   :name
    ...> )
    {
      %{field: "name", op: "==", value: "Joe"},
      [%{field: "age", op: ">", value: "8"}]
    }

    iex> pop(
    ...>   %{
    ...>     0 => %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     1 => %{"field" => "age", "op" => ">", "value" => "8"},
    ...>     2 => %{"field" => "name", "op" => "==", "value" => "Jim"},
    ...>   },
    ...>   :name
    ...> )
    {
      %{"field" => "name", "op" => "==", "value" => "Joe"},
      [%{"field" => "age", "op" => ">", "value" => "8"}]
    }

# `pop_first`
*since 0.19.0* 

```elixir
@spec pop_first([t()] | [map()] | map(), atom(), any()) ::
  {t() | any(), [t()]} | {map() | any(), [map()]}
```

Returns the first filter for the given field and a filter list with all
remaining filters.

Returns a tuple with the first matching filter for `key` and the
remaining filter list. If there is no filter for the field in the list, the
default value is returned as the first tuple element.

See also `Flop.Filter.pop/3`, `Flop.Filter.pop_value/3` and
`Flop.Filter.pop_first_value/3`.

## Examples

### Flop.Filter struct

    iex> pop_first([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :name)
    {%Flop.Filter{field: :name, op: :==, value: "Joe"}, []}

    iex> pop_first([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :age)
    {nil, [%Flop.Filter{field: :name, op: :==, value: "Joe"}]}

    iex> pop_first(
    ...>   [%Flop.Filter{field: :name, op: :==, value: "Joe"}],
    ...>   :age,
    ...>   %Flop.Filter{field: :age, op: :>, value: 8}
    ...> )
    {
      %Flop.Filter{field: :age, op: :>, value: 8},
      [%Flop.Filter{field: :name, op: :==, value: "Joe"}]
    }

    iex> pop_first(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"},
    ...>   ],
    ...>   :name
    ...> )
    {
      %Flop.Filter{field: :name, op: :==, value: "Joe"},
      [
        %Flop.Filter{field: :age, op: :>, value: 8},
        %Flop.Filter{field: :name, op: :==, value: "Jim"}
      ]
    }

### Map with atom keys

    iex> pop_first([%{field: :name, op: :==, value: "Joe"}], :name)
    {%{field: :name, op: :==, value: "Joe"}, []}

### Map with string keys

    iex> pop_first(
    ...>   [%{"field" => "name", "op" => "==", "value" => "Joe"}],
    ...>   :name
    ...> )
    {%{"field" => "name", "op" => "==", "value" => "Joe"}, []}

### Indexed map

Filters passed as an indexed map will be converted to a list, even if no
matching filter exists.

    iex> pop_first(
    ...>   %{
    ...>     0 => %{field: "name", op: "==", value: "Joe"},
    ...>     1 => %{field: "age", op: ">", value: 8},
    ...>     2 => %{field: "name", op: "==", value: "Jim"},
    ...>   },
    ...>   :name
    ...> )
    {
      %{field: "name", op: "==", value: "Joe"},
      [
        %{field: "age", op: ">", value: 8},
        %{field: "name", op: "==", value: "Jim"}
      ]
    }

    iex> pop_first(
    ...>   %{
    ...>     "0" => %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     "1" => %{"field" => "age", "op" => ">", "value" => 8},
    ...>     "2" => %{"field" => "name", "op" => "==", "value" => "Jim"},
    ...>   },
    ...>   :name
    ...> )
    {
      %{"field" => "name", "op" => "==", "value" => "Joe"},
      [
        %{"field" => "age", "op" => ">", "value" => 8},
        %{"field" => "name", "op" => "==", "value" => "Jim"}
      ]
    }

# `pop_first_value`
*since 0.20.0* 

```elixir
@spec pop_first_value([t()] | [map()] | map(), atom(), any()) ::
  {t() | any(), [t()]} | {map() | any(), [map()]}
```

Returns the first filter for the given field and a filter list with all
remaining filters.

Returns a tuple with the first matching filter value for `key` and the
remaining filter list. If there is no filter for the field in the list, the
default value is returned as the first tuple element.

See also `Flop.Filter.pop/3`, `Flop.Filter.pop_value/3` and
`Flop.Filter.pop_first/3`.

## Examples

### Flop.Filter struct

    iex> pop_first_value(
    ...>   [%Flop.Filter{field: :name, op: :==, value: "Joe"}],
    ...>   :name
    ...> )
    {"Joe", []}

    iex> pop_first_value(
    ...>   [%Flop.Filter{field: :name, op: :==, value: "Joe"}],
    ...>   :age
    ...> )
    {nil, [%Flop.Filter{field: :name, op: :==, value: "Joe"}]}

    iex> pop_first_value(
    ...>   [%Flop.Filter{field: :name, op: :==, value: "Joe"}],
    ...>   :age,
    ...>   8
    ...> )
    {8, [%Flop.Filter{field: :name, op: :==, value: "Joe"}]}

    iex> pop_first_value(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"},
    ...>   ],
    ...>   :name
    ...> )
    {
      "Joe",
      [
        %Flop.Filter{field: :age, op: :>, value: 8},
        %Flop.Filter{field: :name, op: :==, value: "Jim"}
      ]
    }

### Map with atom keys

    iex> pop_first_value([%{field: :name, op: :==, value: "Joe"}], :name)
    {"Joe", []}

### Map with string keys

    iex> pop_first_value(
    ...>   [%{"field" => "name", "op" => "==", "value" => "Joe"}],
    ...>   :name
    ...> )
    {"Joe", []}

### Indexed map

Filters passed as an indexed map will be converted to a list, even if no
matching filter exists.

    iex> pop_first_value(
    ...>   %{
    ...>     0 => %{field: "name", op: "==", value: "Joe"},
    ...>     1 => %{field: "age", op: ">", value: 8},
    ...>     2 => %{field: "name", op: "==", value: "Jim"},
    ...>   },
    ...>   :name
    ...> )
    {
      "Joe",
      [
        %{field: "age", op: ">", value: 8},
        %{field: "name", op: "==", value: "Jim"}
      ]
    }

    iex> pop_first_value(
    ...>   %{
    ...>     "0" => %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     "1" => %{"field" => "age", "op" => ">", "value" => 8},
    ...>     "2" => %{"field" => "name", "op" => "==", "value" => "Jim"},
    ...>   },
    ...>   :name
    ...> )
    {
      "Joe",
      [
        %{"field" => "age", "op" => ">", "value" => 8},
        %{"field" => "name", "op" => "==", "value" => "Jim"}
      ]
    }

# `pop_value`
*since 0.20.0* 

```elixir
@spec pop_value([t()] | [map()] | map(), atom(), any()) ::
  {t() | any(), [t()]} | {map() | any(), [map()]}
```

Returns the first filter value for the given field and removes all other
filters for the same field from the filter list.

Returns a tuple with the value of the first matching filter for `key` and the
remaining filter list. If there is no filter for the field in the list, the
default value is returned as the first tuple element.

See also `Flop.Filter.pop/3`, `Flop.Filter.pop_first/3` and
`Flop.Filter.pop_first_value/3`

## Examples

### Flop.Filter struct

    iex> pop_value([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :name)
    {"Joe", []}

    iex> pop_value([%Flop.Filter{field: :name, op: :==, value: "Joe"}], :age)
    {nil, [%Flop.Filter{field: :name, op: :==, value: "Joe"}]}

    iex> pop_value(
    ...>   [%Flop.Filter{field: :name, op: :==, value: "Joe"}],
    ...>   :age,
    ...>   8
    ...> )
    {8, [%Flop.Filter{field: :name, op: :==, value: "Joe"}]}

    iex> pop_value(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"},
    ...>   ],
    ...>   :name
    ...> )
    {"Joe", [%Flop.Filter{field: :age, op: :>, value: 8}]}

### Map with atom keys

    iex> pop_value([%{field: :name, op: :==, value: "Joe"}], :name)
    {"Joe", []}

### Map with string keys

    iex> pop_value([%{"field" => "name", "op" => "==", "value" => "Joe"}], :name)
    {"Joe", []}

### Indexed map

Filters passed as an indexed map will be converted to a list, even if no
matching filter exists.

    iex> pop_value(
    ...>   %{
    ...>     0 => %{field: "name", op: "==", value: "Joe"},
    ...>     1 => %{field: "age", op: ">", value: "8"},
    ...>     2 => %{field: "name", op: "==", value: "Jim"},
    ...>   },
    ...>   :name
    ...> )
    {"Joe", [%{field: "age", op: ">", value: "8"}]}

    iex> pop_value(
    ...>   %{
    ...>     0 => %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     1 => %{"field" => "age", "op" => ">", "value" => "8"},
    ...>     2 => %{"field" => "name", "op" => "==", "value" => "Jim"},
    ...>   },
    ...>   :name
    ...> )
    {"Joe", [%{"field" => "age", "op" => ">", "value" => "8"}]}

# `put`
*since 0.19.0* 

```elixir
@spec put([t()], t()) :: [t()]
```

Adds the given filter to the filter list and removes all existing filters for
the same field from the list.

## Examples

    iex> put(
    ...>   [%Flop.Filter{field: :name, op: :==, value: "Joe"}],
    ...>   %Flop.Filter{field: :age, op: :>, value: 8}
    ...> )
    [
      %Flop.Filter{field: :age, op: :>, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "Joe"}
    ]

    iex> put(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   %Flop.Filter{field: :name, op: :==, value: "Jane"}
    ...> )
    [
      %Flop.Filter{field: :name, op: :==, value: "Jane"},
      %Flop.Filter{field: :age, op: :>, value: 8}
    ]

# `put_new`
*since 0.19.0* 

```elixir
@spec put_new([t()], t()) :: [t()]
```

Adds the given filter to the filter list only if no filter for the field
exists yet.

## Examples

    iex> put_new(
    ...>   [%Flop.Filter{field: :name, op: :==, value: "Joe"}],
    ...>   %Flop.Filter{field: :age, op: :>, value: 8}
    ...> )
    [
      %Flop.Filter{field: :age, op: :>, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "Joe"}
    ]

    iex> put_new(
    ...>   [
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   %Flop.Filter{field: :name, op: :==, value: "Jane"}
    ...> )
    [
      %Flop.Filter{field: :age, op: :>, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ]

# `put_new_value`
*since 0.20.0* 

```elixir
@spec put_new_value([t()], atom(), any(), op()) :: [t()]
```

Adds the given filter value to the filter list only if no filter for the field
exists yet.

## Examples

    iex> put_new_value(
    ...>   [%Flop.Filter{field: :name, op: :==, value: "Joe"}],
    ...>   :age,
    ...>   8,
    ...>   :>
    ...> )
    [
      %Flop.Filter{field: :age, op: :>, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "Joe"}
    ]

    iex> put_new_value(
    ...>   [
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   :name,
    ...>   "Jane"
    ...> )
    [
      %Flop.Filter{field: :age, op: :>, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ]

# `put_value`
*since 0.20.0* 

```elixir
@spec put_value([t()], atom(), any(), op()) :: [t()]
```

Adds the given filter value to the filter list and removes all existing
filters for the same field from the list.

## Examples

    iex> put_value(
    ...>   [%Flop.Filter{field: :name, op: :==, value: "Joe"}],
    ...>   :age,
    ...>   8
    ...> )
    [
      %Flop.Filter{field: :age, op: :==, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "Joe"}
    ]

    iex> put_value(
    ...>   [%Flop.Filter{field: :name, op: :==, value: "Joe"}],
    ...>   :age,
    ...>   8,
    ...>   :>=
    ...> )
    [
      %Flop.Filter{field: :age, op: :>=, value: 8},
      %Flop.Filter{field: :name, op: :==, value: "Joe"}
    ]

    iex> put_value(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   :name,
    ...>   "Jane"
    ...> )
    [
      %Flop.Filter{field: :name, op: :==, value: "Jane"},
      %Flop.Filter{field: :age, op: :>, value: 8}
    ]

# `take`
*since 0.19.0* 

```elixir
@spec take([t()] | [map()] | map(), [atom()]) :: [t()] | [map()]
```

Takes all filters for the given fields from a filter list.

## Examples

### Flop.Filter struct

    iex> take(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>, value: 8},
    ...>     %Flop.Filter{field: :color, op: :==, value: "blue"},
    ...>     %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ...>   ],
    ...>   [:name, :color]
    ...> )
    [
      %Flop.Filter{field: :name, op: :==, value: "Joe"},
      %Flop.Filter{field: :color, op: :==, value: "blue"},
      %Flop.Filter{field: :name, op: :==, value: "Jim"}
    ]

### Map with atom keys

    iex> take(
    ...>   [
    ...>     %{field: :name, op: :==, value: "Joe"},
    ...>     %{field: :age, op: :>, value: 8},
    ...>     %{field: :color, op: :==, value: "blue"}
    ...>   ],
    ...>   [:name, :color]
    ...> )
    [
      %{field: :name, op: :==, value: "Joe"},
      %{field: :color, op: :==, value: "blue"}
    ]

### Map with string keys

    iex> take(
    ...>   [
    ...>     %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     %{"field" => "age", "op" => ">", "value" => 8},
    ...>     %{"field" => "color", "op" => "==", "value" => "blue"}
    ...>   ],
    ...>   [:name, :color]
    ...> )
    [
      %{"field" => "name", "op" => "==", "value" => "Joe"},
      %{"field" => "color", "op" => "==", "value" => "blue"}
    ]

### Indexed map

Filters passed as an indexed map will be converted to a list, even if no
matching filter exists.

    iex> take(
    ...>   %{
    ...>     0 => %{field: "name", op: "==", value: "Joe"},
    ...>     1 => %{field: "age", op: ">", value: 8},
    ...>     2 => %{field: "color", op: "==", value: "blue"}
    ...>   },
    ...>   [:name, :color]
    ...> )
    [
      %{field: "name", op: "==", value: "Joe"},
      %{field: "color", op: "==", value: "blue"}
    ]

    iex> take(
    ...>   %{
    ...>     "0" => %{"field" => "name", "op" => "==", "value" => "Joe"},
    ...>     "1" => %{"field" => "age", "op" => ">", "value" => 8},
    ...>     "2" => %{"field" => "color", "op" => "==", "value" => "blue"}
    ...>   },
    ...>   [:name, :color]
    ...> )
    [
      %{"field" => "name", "op" => "==", "value" => "Joe"},
      %{"field" => "color", "op" => "==", "value" => "blue"}
    ]

# `update_value`
*since 0.25.0* 

```elixir
@spec update_value([t()] | [map()] | map(), atom(), (any() -&gt; any())) ::
  t() | map() | nil
```

Updates all filter values for the given field.

If no filter for the given field is set, the filter list will be returned
unchanged.

## Examples

### Flop.Filter struct

    iex> update_value(
    ...>   [
    ...>     %Flop.Filter{field: :name, op: :==, value: "Joe"},
    ...>     %Flop.Filter{field: :age, op: :>=, value: 30}
    ...>   ],
    ...>   :name,
    ...>   fn
    ...>     nil -> nil
    ...>     value -> String.downcase(value)
    ...>   end
    ...> )
    [
      %Flop.Filter{field: :name, op: :==, value: "joe"},
      %Flop.Filter{field: :age, op: :>=, value: 30}
    ]

    iex> update_value(
    ...>   [%Flop.Filter{field: :age, op: :==, value: 8}],
    ...>   :name,
    ...>   fn
    ...>     nil -> nil
    ...>     value -> String.downcase(value)
    ...>   end
    ...> )
    [%Flop.Filter{field: :age, op: :==, value: 8}]

### Map with atom keys

    iex> update_value(
    ...>   [%{field: :name, op: :==, value: "Joe"}],
    ...>   :name,
    ...>   fn
    ...>     nil -> nil
    ...>     value -> String.downcase(value)
    ...>   end
    ...> )
    [%{field: :name, op: :==, value: "joe"}]

    iex> update_value(
    ...>   [%{field: "name", op: "==", value: "Joe"}],
    ...>   :name,
    ...>   fn
    ...>     nil -> nil
    ...>     value -> String.downcase(value)
    ...>   end
    ...> )
    [%{field: "name", op: "==", value: "joe"}]

### Map with string keys

    iex> update_value(
    ...>   [%{"field" => :updated_at, "op" => :>=, "value" => "2023-10-01"}],
    ...>   :updated_at,
    ...>   fn
    ...>     nil -> nil
    ...>     value -> value <> " 00:00:00"
    ...>   end
    ...> )
    [%{"field" => :updated_at, "op" => :>=, "value" => "2023-10-01 00:00:00"}]

    iex> update_value(
    ...>   [%{"field" => "updated_at", "op" => ">=", "value" => "2023-10-01"}],
    ...>   :updated_at,
    ...>   fn
    ...>     nil -> nil
    ...>     value -> value <> " 00:00:00"
    ...>   end
    ...> )
    [%{"field" => "updated_at", "op" => ">=", "value" => "2023-10-01 00:00:00"}]

### Indexed map

    iex> update_value(
    ...>   %{0 => %{field: "name", op: "==", value: "Joe"}},
    ...>   :name,
    ...>   fn
    ...>     nil -> nil
    ...>     value -> String.downcase(value)
    ...>   end
    ...> )
    %{0 => %{field: "name", op: "==", value: "joe"}}

    iex> update_value(
    ...>   %{0 => %{field: :name, op: "==", value: "Joe"}},
    ...>   :name,
    ...>   fn
    ...>     nil -> nil
    ...>     value -> String.downcase(value)
    ...>   end
    ...> )
    %{0 => %{field: :name, op: "==", value: "joe"}}

    iex> update_value(
    ...>   %{"0" => %{"field" => "updated_at", "op" => ">=", "value" => "2023-10-01"}},
    ...>   :updated_at,
    ...>   fn
    ...>     nil -> nil
    ...>     value -> value <> " 00:00:00"
    ...>   end
    ...> )
    %{"0" => %{"field" => "updated_at", "op" => ">=", "value" => "2023-10-01 00:00:00"}}

    iex> update_value(
    ...>   %{"0" => %{"field" => :name, "op" => "==", "value" => "Joe"}},
    ...>   :name,
    ...>   fn
    ...>     nil -> nil
    ...>     value -> String.downcase(value)
    ...>   end
    ...> )
    %{"0" => %{"field" => :name, "op" => "==", "value" => "joe"}}

---

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