View Source Flop.Filter (Flop v0.25.0)

Defines a filter.

Summary

Types

Represents valid filter operators.

t()

Represents filter query parameters.

Functions

Returns the allowed operators for the given Ecto type.

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

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

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

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

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

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

Returns the first filter for the given field.

Returns the all filters for the given field.

Returns the first filter value for the given field.

Creates a list of filters from an enumerable.

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

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

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

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

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

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

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

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

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

Updates all filter values for the given field.

Types

@type op() ::
  :==
  | :!=
  | :=~
  | :empty
  | :not_empty
  | :<=
  | :<
  | :>=
  | :>
  | :in
  | :not_in
  | :contains
  | :not_contains
  | :like
  | :not_like
  | :like_and
  | :like_or
  | :ilike
  | :not_ilike
  | :ilike_and
  | :ilike_or

Represents valid filter operators.

OperatorValueWHERE clause
:=="Salicaceae"WHERE column = 'Salicaceae'
:!="Salicaceae"WHERE column != 'Salicaceae'
:=~"cyth"WHERE column ILIKE '%cyth%'
:emptytrueWHERE (column IS NULL) = true
:emptyfalseWHERE (column IS NULL) = false
:not_emptytrueWHERE (column IS NOT NULL) = true
:not_emptyfalseWHERE (column IS NOT NULL) = false
:<=10WHERE column <= 10
:<10WHERE column < 10
:>=10WHERE column >= 10
:>10WHERE 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%'

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.
@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.

Functions

@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]
Link to this function

allowed_operators(module, field)

View Source
@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]
Link to this function

delete(filters, field)

View Source (since 0.19.0)
@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"}]
Link to this function

delete_first(filters, field)

View Source (since 0.19.0)
@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"}
]
Link to this function

drop(filters, fields)

View Source (since 0.19.0)
@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"}]
Link to this function

fetch(filters, field)

View Source (since 0.19.0)
@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"}}
Link to this function

fetch_value(filters, field)

View Source (since 0.20.0)
@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"}
Link to this function

get(filters, field)

View Source (since 0.19.0)
@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"}
Link to this function

get_all(filters, field)

View Source (since 0.19.0)
@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"}
]
Link to this function

get_value(filters, field)

View Source (since 0.20.0)
@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"
Link to this function

new(enum, opts \\ [])

View Source (since 0.19.0)
@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"}
]
Link to this function

pop(filters, field, default \\ nil)

View Source (since 0.19.0)
@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"}]
}
Link to this function

pop_first(filters, field, default \\ nil)

View Source (since 0.19.0)
@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"}
  ]
}
Link to this function

pop_first_value(filters, field, default \\ nil)

View Source (since 0.20.0)
@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"}
  ]
}
Link to this function

pop_value(filters, field, default \\ nil)

View Source (since 0.20.0)
@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"}]}
Link to this function

put(filters, filter)

View Source (since 0.19.0)
@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}
]
Link to this function

put_new(filters, filter)

View Source (since 0.19.0)
@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"}
]
Link to this function

put_new_value(filters, field, value, op \\ :==)

View Source (since 0.20.0)
@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"}
]
Link to this function

put_value(filters, field, value, op \\ :==)

View Source (since 0.20.0)
@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}
]
Link to this function

take(filters, fields)

View Source (since 0.19.0)
@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"}
]
Link to this function

update_value(filters, field, fun)

View Source (since 0.25.0)
@spec update_value([t()] | [map()] | map(), atom(), (any() -> 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"}}