Skip to main content

lib/data_bundle.ex

defmodule WarframeWorldstateDataElixirTools.DataBundle do
  @moduledoc false

  @doc """
  Reads a data file and retuns its content in a map.

  Arguments:
  1. The file name without the extention.
  2. A locale in atom form. :en is used as a default.

  ## Examples

      iex> {:ok, nodes} = WarframeWorldstateDataElixirTools.DataBundle.read_data_file("solNodes.json")
      iex> is_map(nodes)
      true

      iex> WarframeWorldstateDataElixirTools.DataBundle.read_data_file("nonexistent.json")
      {:error, :enoent}

  """
  @spec read_data_file(String.t(), atom()) ::
          {:ok, map()} | {:error, Jason.DecodeError.t() | term()}
  def read_data_file(file_name, locale \\ :en)
      when is_binary(file_name) and is_atom(locale) do
    path =
      case locale do
        :en ->
          :code.priv_dir(:warframe_worldstate_data_elixir_tools)
          |> Path.join("data/#{file_name}")

        _ ->
          :code.priv_dir(:warframe_worldstate_data_elixir_tools)
          |> Path.join("data/#{Atom.to_string(locale)}/#{file_name}")
      end

    with {:ok, res} <- File.read(path),
         {:ok, map} <- Jason.decode(res) do
      {:ok, map}
    else
      {:error, _reason} = x ->
        x
    end
  end

  @doc """
  Finds the value of a top-level key in a large JSON file
  without loading the entire file into memory.

  ## Examples

      iex> key = "/Lotus/Types/Challenges/Calendar1999/CalendarDestroyPropsEasy"
      iex> {:ok, %{"value" => value}} = WarframeWorldstateDataElixirTools.DataBundle.find_key("languages.json", key, :en)
      iex> value
      "Starve the beast"

      iex> WarframeWorldstateDataElixirTools.DataBundle.find_key("languages.json", "nonexistent_key", :en)
      {:error, :not_found}

  """
  def find_key(file_name, key, locale)
      when is_binary(file_name) and is_atom(locale) and is_binary(key) do
    path =
      case locale do
        :en ->
          :code.priv_dir(:warframe_worldstate_data_elixir_tools)
          |> Path.join("data/#{file_name}")

        _ ->
          :code.priv_dir(:warframe_worldstate_data_elixir_tools)
          |> Path.join("data/#{Atom.to_string(locale)}/#{file_name}")
      end

    path_expr = [:root, key]

    path
    |> File.stream!(4096, [])
    |> Jaxon.Stream.from_enumerable()
    |> Jaxon.Stream.query(path_expr)
    |> Enum.take(1)
    |> case do
      [value] -> {:ok, value}
      [] -> {:error, :not_found}
    end
  end
end