defmodule StatesLanguage.JSONPath do
@moduledoc """
Functions for handling JSONPath support
"""
def get_parameters(data, input_path, parameters) when is_binary(input_path) do
get_parameters(data, [input_path], parameters)
end
def get_parameters(data, input_path, parameters) when is_list(input_path) do
input_path
|> Enum.reduce(data, &run_json_path/2)
|> generate_parameters(parameters)
end
def put_result(data, resource_path, output_path, parameters) do
result =
parameters
|> put_path(resource_path, data)
run_json_path(output_path, result)
end
def run_json_path("$", data), do: data
def run_json_path(<<"$", _::binary>> = path, %{__struct__: _} = data) do
run_json_path(path, Map.from_struct(data))
end
def run_json_path(<<"$", rest::binary>>, data) when is_map(data) do
Elixpath.get!(data, rest)
end
def run_json_path(_p, data), do: data
def put_path(_input, "$", result), do: result
def put_path(%{__struct__: _} = input, <<"$", _::binary>> = path, result) do
put_path(Map.from_struct(input), path, result)
end
def put_path(input, <<"$.", path::binary>>, result) when is_map(input) do
path =
path
|> String.split(".")
|> Enum.reverse()
|> Enum.reduce([], fn key, acc ->
create_path(key, acc)
end)
put_in(input, Enum.map(path, &Access.key(&1, %{})), result)
end
def put_path(_, _, result), do: result
defp create_path(<<":", key::binary>>, acc) do
key = String.to_existing_atom(key)
create_path(key, acc)
end
defp create_path(key, acc) do
[key | acc]
end
def generate_parameters(input, params) when map_size(params) == 0, do: input
def generate_parameters(input, params) do
Enum.reduce(params, %{}, fn {k, v}, acc -> parse_parameters({k, v}, input, acc) end)
end
defp parse_parameters({k, v}, input, acc) when is_map(v) do
Map.put(acc, k, generate_parameters(input, v))
end
defp parse_parameters({k, v}, input, acc) when is_list(v) do
Map.put(
acc,
k,
Enum.map(v, fn i ->
generate_parameters(input, i)
end)
)
end
defp parse_parameters({k, <<"$", _path::binary>> = v}, input, acc) do
if String.ends_with?(k, ".$") do
key = String.slice(k, 0..-3//1)
val = run_json_path(v, input)
Map.put(acc, key, val)
else
Map.put(acc, k, v)
end
end
defp parse_parameters({k, v}, _input, acc) do
Map.put(acc, k, v)
end
end