defmodule StarkBank.Utils.Rest do @moduledoc false alias StarkBank.Utils.Request, as: Request alias StarkBank.Utils.QueryGenerator, as: QueryGenerator alias StarkBank.Utils.API, as: API alias StarkBank.Utils.JSON, as: JSON def get_list(user, {resource_name, resource_maker}, query \\ %{}) do limit = query[:limit] getter = make_getter(user, resource_name) Stream.resource( fn -> {:ok, pid} = QueryGenerator.start_query(getter, API.last_name_plural(resource_name), query |> Map.put(:limit, limit)) pid end, fn pid -> case QueryGenerator.get(pid) do :halt -> {:halt, pid} {:ok, element} -> {[{:ok, API.from_api_json(element, resource_maker)}], pid} {:error, error} -> {[{:error, error}], pid} end end, fn _pid -> nil end ) end def get_list!(user, {resource_name, resource_maker}, query \\ %{}) do limit = query[:limit] getter = make_getter(user, resource_name) Stream.resource( fn -> {:ok, pid} = QueryGenerator.start_query(getter, API.last_name_plural(resource_name), query |> Map.put(:limit, limit)) pid end, fn pid -> case QueryGenerator.get(pid) do :halt -> {:halt, pid} {:ok, element} -> {[API.from_api_json(element, resource_maker)], pid} {:error, errors} -> raise API.errors_to_string(errors) end end, fn _pid -> nil end ) end defp make_getter(user, resource_name) do fn query -> Request.fetch( user, :get, API.endpoint(resource_name), query: query ) end end def get_id(user, {resource_name, resource_maker}, id) do case Request.fetch(user, :get, "#{API.endpoint(resource_name)}/#{id}") do {:ok, response} -> {:ok, process_single_response(response, resource_name, resource_maker)} {:error, errors} -> {:error, errors} end end def get_id!(user, {resource_name, resource_maker}, id) do case get_id(user, {resource_name, resource_maker}, id) do {:ok, entity} -> entity {:error, errors} -> raise API.errors_to_string(errors) end end def get_pdf(user, {resource_name, _resource_maker}, id) do case Request.fetch(user, :get, "#{API.endpoint(resource_name)}/#{id}/pdf") do {:ok, pdf} -> {:ok, pdf} {:error, errors} -> {:error, errors} end end def get_pdf!(user, {resource_name, _resource_maker}, id) do case Request.fetch(user, :get, "#{API.endpoint(resource_name)}/#{id}/pdf") do {:ok, pdf} -> pdf {:error, errors} -> raise API.errors_to_string(errors) end end def post(user, {resource_name, resource_maker}, entities) do case Request.fetch(user, :post, "#{API.endpoint(resource_name)}", payload: prepare_payload(resource_name, entities)) do {:ok, response} -> {:ok, process_response(resource_name, resource_maker, response)} {:error, errors} -> {:error, errors} end end def post!(user, {resource_name, resource_maker}, entities) do case post(user, {resource_name, resource_maker}, entities) do {:ok, entities} -> entities {:error, errors} -> raise API.errors_to_string(errors) end end def post_single(user, {resource_name, resource_maker}, entity) do case Request.fetch(user, :post, "#{API.endpoint(resource_name)}", payload: API.api_json(entity)) do {:ok, response} -> {:ok, process_single_response(response, resource_name, resource_maker)} {:error, errors} -> {:error, errors} end end def post_single!(user, {resource_name, resource_maker}, entity) do case post_single(user, {resource_name, resource_maker}, entity) do {:ok, entity} -> entity {:error, errors} -> raise API.errors_to_string(errors) end end def delete_id(user, {resource_name, resource_maker}, id) do case Request.fetch(user, :delete, "#{API.endpoint(resource_name)}/#{id}") do {:ok, response} -> {:ok, process_single_response(response, resource_name, resource_maker)} {:error, errors} -> {:error, errors} end end def delete_id!(user, {resource_name, resource_maker}, id) do case delete_id(user, {resource_name, resource_maker}, id) do {:ok, entity} -> entity {:error, errors} -> raise API.errors_to_string(errors) end end def patch_id(user, {resource_name, resource_maker}, id, payload) do case Request.fetch(user, :patch, "#{API.endpoint(resource_name)}/#{id}", payload: payload |> API.cast_json_to_api_format) do {:ok, response} -> {:ok, process_single_response(response, resource_name, resource_maker)} {:error, errors} -> {:error, errors} end end def patch_id!(user, {resource_name, resource_maker}, id, payload) do case patch_id(user, {resource_name, resource_maker}, id, payload) do {:ok, entity} -> entity {:error, errors} -> raise API.errors_to_string(errors) end end defp prepare_payload(resource_name, entities) do Map.put( %{}, API.last_name_plural(resource_name), Enum.map(entities, &API.api_json/1) ) end defp process_single_response(response, resource_name, resource_maker) do JSON.decode!(response)[API.last_name(resource_name)] |> API.from_api_json(resource_maker) end defp process_response(resource_name, resource_maker, response) do JSON.decode!(response)[API.last_name_plural(resource_name)] |> Enum.map(fn json -> API.from_api_json(json, resource_maker) end) end end