Current section
Files
Jump to
Current section
Files
lib/kvasir/command/decoder.ex
defmodule Kvasir.Command.Decoder do
def decode(value, meta \\ %Kvasir.Command.Meta{}) do
with {:ok, data} <- Jason.decode(value) do
do_decode(data, update_meta(meta, data["meta"]))
end
end
defp update_meta(meta, data) when is_map(data) do
struct!(
Kvasir.Command.Meta,
for(
{key, val} when val != nil <- data,
into: Map.from_struct(meta),
do: {String.to_atom(key), val}
)
)
end
defp update_meta(meta, _nil), do: meta
defp do_decode(data, meta) do
command = Module.concat("Elixir", data["type"])
if Code.ensure_compiled?(command),
do: decode_command(command, data["payload"], meta),
else: {:error, :unknown_comand}
end
defp decode_command(command, data, meta),
do: do_decode_command(command.__command__(:fields), data, struct(command, %{__meta__: meta}))
defp do_decode_command([], _data, acc), do: acc
defp do_decode_command([{property, type} | props], data, acc) do
case Map.fetch(data, to_string(property)) do
{:ok, value} ->
do_decode_command(props, data, Map.put(acc, property, parse_type(value, type)))
:error ->
{:error, :invalid_command_payload}
end
end
@unix ~N[1970-01-01 00:00:00]
defp parse_type(nil, _), do: nil
defp parse_type(value, :datetime), do: NaiveDateTime.add(@unix, value, :milliseconds)
defp parse_type(value, _), do: value
end