Current section

Files

Jump to
dagger lib dagger core query_builder.ex
Raw

lib/dagger/core/query_builder.ex

defmodule Dagger.Core.QueryBuilder do
@moduledoc false
defstruct [:name, :args, :prev, alias: ""]
def query(), do: %__MODULE__{}
def select(%__MODULE__{} = selection, name) when is_binary(name) do
select_with_alias(selection, "", name)
end
def select_with_alias(%__MODULE__{} = selection, alias, name)
when is_binary(alias) and is_binary(name) do
%__MODULE__{
name: name,
alias: alias,
prev: selection
}
end
def put_arg(%__MODULE__{args: args} = selection, name, value) when is_binary(name) do
args = args || %{}
%{selection | args: Map.put(args, name, value)}
end
def maybe_put_arg(%__MODULE__{} = selection, _name, nil), do: selection
def maybe_put_arg(%__MODULE__{} = selection, name, value) do
put_arg(selection, name, value)
end
def build(%__MODULE__{} = selection) do
fields = build_fields(selection, [])
Enum.join(fields, "{") <> String.duplicate("}", Enum.count(fields) - 1)
end
def build_fields(%__MODULE__{prev: nil}, acc) do
["query" | acc]
end
def build_fields(%__MODULE__{prev: selection, name: name, args: args, alias: alias}, acc) do
q = [build_alias(alias) | [name | build_args(args)]]
build_fields(selection, [IO.iodata_to_binary(q) | acc])
end
defp build_alias(""), do: []
defp build_alias(alias), do: [alias, ~c":"]
defp build_args(nil), do: []
defp build_args(args) do
fun = fn {name, value} -> [name, ~c":", encode_value(value)] end
[~c"(", Enum.map(args, fun) |> Enum.intersperse(","), ~c")"]
end
defp encode_value(value) when is_atom(value),
do: to_string(value)
defp encode_value(value) when is_binary(value) do
string =
value
|> String.replace("\\", "\\\\")
|> String.replace("\r", "\\r")
|> String.replace("\n", "\\n")
|> String.replace("\t", "\\t")
|> String.replace("\"", "\\\"")
[~c"\"", string, ~c"\""]
end
defp encode_value(value) when is_list(value) do
[~c"[", Enum.map_intersperse(value, ",", &encode_value/1), ~c"]"]
end
defp encode_value(value) when is_struct(value) do
value
|> Map.from_struct()
|> encode_value()
end
defp encode_value(value) when is_map(value) do
fun = fn {name, value} ->
[to_string(name), ~c":", encode_value(value)]
end
[~c"{", Enum.map_intersperse(value, ",", fun), ~c"}"]
end
defp encode_value(value), do: [to_string(value)]
def path(selection) do
path(selection, [])
end
def path(%__MODULE__{prev: nil, name: nil}, acc), do: acc
def path(%__MODULE__{prev: selection, name: name}, acc), do: path(selection, [name | acc])
end
defmodule Dagger.QueryError do
@moduledoc false
defstruct [:errors]
end