Current section
Files
Jump to
Current section
Files
lib/singyeong/query.ex
defmodule Singyeong.Query do
use TypedStruct
@boolean_op_names [
:"$eq",
:"$ne",
:"$gt",
:"$gte",
:"$lt",
:"$lte",
:"$in",
:"$nin",
:"$contains",
:"$ncontains",
]
@logical_op_names [
:"$and",
:"$or",
:"$nor",
]
@selector_names [
:"$min",
:"$max",
:"$avg",
]
@type ops() :: [op()] | []
@type boolean_op_name() ::
:"$eq"
| :"$ne"
| :"$gt"
| :"$gte"
| :"$lt"
| :"$lte"
| :"$in"
| :"$nin"
| :"$contains"
| :"$ncontains"
@type logical_op_name() ::
:"$and"
| :"$or"
| :"$nor"
@type boolean_op() :: %{
required(boolean_op_name()) => term()
}
@type logical_op() :: %{
required(logical_op_name()) => maybe_improper_list(boolean_op(), logical_op())
}
@type op() :: %{
required(binary()) => boolean_op() | logical_op()
}
@type selector() ::
:"$min"
| :"$max"
| :"$avg"
typedstruct do
field :application, String.t() | nil
field :restricted, boolean(), default: false
field :key, String.t() | nil, default: nil
field :droppable, boolean(), default: false
field :optional, boolean(), default: false
field :ops, [op()], default: []
field :selector, selector() | nil, default: nil
end
@doc """
Creates a new query for the given target application
"""
@spec new(String.t() | nil) :: __MODULE__.t()
def new(name), do: %__MODULE__{application: name}
@doc """
Converts the provided values into a proper boolean op.
"""
@spec values_to_op(boolean_op_name(), String.t(), term()) :: boolean_op()
def values_to_op(op, key, value), do: %{key => %{op => value}}
@doc """
Adds the provided boolean op to the query.
"""
@spec with_op(__MODULE__.t(), boolean_op_name(), String.t(), term()) :: __MODULE__.t()
def with_op(%__MODULE__{ops: ops} = query, op, key, value) when op in @boolean_op_names do
%{query | ops: ops ++ [values_to_op(op, key, value)]}
end
@doc """
Adds the provided boolean op to the query.
"""
@spec with_op(__MODULE__.t(), boolean_op()) :: __MODULE__.t()
def with_op(%__MODULE__{ops: ops} = query, op) when op in @boolean_op_names do
%{query | ops: ops ++ [op]}
end
@doc """
Adds the provided logical op over the provided ops to the query.
"""
@spec with_logical_op(__MODULE__.t(), logical_op_name(), op(), op()) :: __MODULE__.t()
def with_logical_op(%__MODULE__{ops: ops} = query, logical_op, op1, op2) when logical_op in @logical_op_names do
%{query | ops: ops ++ [%{logical_op => [op1, op2]}]}
end
@doc """
Sets the query's selector to the specified key
"""
@spec with_selector(__MODULE__.t(), selector(), String.t()) :: __MODULE__.t()
def with_selector(%__MODULE__{} = query, selector, key) when is_nil(selector) or selector in @selector_names do
if is_nil(selector) do
%{query | selector: nil}
else
%{query | selector: %{selector => key}}
end
end
end