surgeventures/surgex

View on GitHub
lib/surgex/parser/parsers/geolocation_parser.ex

Summary

Maintainability
Test Coverage
defmodule Surgex.Parser.GeolocationParser do
  @moduledoc false

  alias Surgex.Parser.{FloatParser, Geolocation}

  @type errors :: :invalid_geolocation_tuple | :invalid_geolocation | FloatParser.errors()

  @spec call(term()) :: {:ok, Geolocation.t() | nil} | {:error, errors()}
  def call(nil), do: {:ok, nil}
  def call(""), do: {:ok, nil}

  def call(input) when is_binary(input) do
    case String.split(input, ",") do
      [lat_string, lng_string] ->
        parse_lat_lng_strings(lat_string, lng_string)

      _split_result ->
        {:error, :invalid_geolocation_tuple}
    end
  end

  def call({lat_string, lng_string}) when is_binary(lat_string) and is_binary(lng_string) do
    parse_lat_lng_strings(lat_string, lng_string)
  end

  def call(_input), do: {:error, :invalid_geolocation_tuple}

  defp parse_lat_lng_strings(lat_string, lng_string) do
    with {:ok, lat} <- FloatParser.call(lat_string),
         {:ok, lng} <- FloatParser.call(lng_string),
         true <- valid_location?(lat, lng) do
      {:ok, %Geolocation{latitude: lat, longitude: lng}}
    else
      false -> {:error, :invalid_geolocation}
      {:error, reason} -> {:error, reason}
    end
  end

  defp valid_location?(lat, _lng) when lat < -90, do: false
  defp valid_location?(lat, _lng) when lat > 90, do: false
  defp valid_location?(_lat, lng) when lng < -180, do: false
  defp valid_location?(_lat, lng) when lng > 180, do: false
  defp valid_location?(_lat, _lng), do: true
end