defmodule ExtractQueryParams do
@moduledoc """
Module for extracting query parameters from a list of keywords.
"""
@supported_logical_operators [
"AND",
"OR",
"NOT"
]
@doc """
Turns list of keywords to SQL statement variables, connected with an operator (defaults to "AND").
## Examples
iex> ExtractQueryParams.to_variables(foo: "bar")
{"foo = ?", ["bar"]}
"""
@spec to_variables(list(keyword())) :: {binary(), list(any)}
def to_variables([]), do: {"", [""]}
def to_variables(keywords), do: to_variables(keywords, "AND")
@spec to_variables(list(keyword()), binary()) :: {binary(), any()}
def to_variables([], _), do: {"", [""]}
def to_variables(keywords, logical_operator)
when logical_operator in @supported_logical_operators do
keywords_to_query_map(keywords)
|> case do
%{query: [], variables: []} ->
""
%{query: query, variables: vars} ->
{
query |> Enum.reverse() |> Enum.join(" #{logical_operator} "),
vars |> Enum.reverse()
}
end
end
def to_variables(_, _) do
{"", [""]}
end
@doc """
Turns list of keywords to SQL statement variables, connected with an operator (defaults to "AND").
Raises an ArgumentError if the logical operator is not supported.
## Examples
iex(1)> ExtractQueryParams.to_variables!([foo: "foo", bar: "bar"], "AND")
{"foo = ? AND bar = ?", ["foo", "bar"]}
iex(2)> ExtractQueryParams.to_variables!([foo: "foo", bar: "bar"], "UNSUPPORTED")
** (ArgumentError) logical operator "UNSUPPORTED" is not supported.
"""
@spec to_variables!(list(keyword()), binary()) :: {binary(), list(any())}
def to_variables!(keywords, logical_operator)
when logical_operator in @supported_logical_operators do
to_variables(keywords, logical_operator)
end
def to_variables!(_, logical_operator) do
raise ArgumentError,
message: "logical operator #{inspect(logical_operator)} is not supported."
end
defp keywords_to_query_map(keywords),
do:
keywords
|> Enum.filter(fn
{_, nil} -> false
_ -> true
end)
|> Enum.map(fn {atom, variable} ->
{Atom.to_string(atom) <> " = ?", variable}
end)
|> Enum.reduce(
%{query: [], variables: []},
fn {query, variable}, %{query: query_, variables: variables_} ->
%{
query: [query | query_],
variables: [variable | variables_]
}
end
)
end