Current section
Files
Jump to
Current section
Files
lib/get_geocode.ex
defmodule GetGeocode do
alias GetGeocode.Apis.{ViaCep, Nominatim}
alias GetGeocode.Geocode
@moduledoc """
The main module with `get/1` function to retrieve data from CEP (brazilian format) or full address format (Nominatim).
"""
@moduledoc since: "0.0.1"
@doc """
Gets geodata from `input`.
Returns a tuple with `{:ok, %GetGeocode.Geocode{}}`.
## Examples
```
iex> GetGeocode.get "69030000"
{:ok,
%GetGeocode.Geocode{
city: "Manaus",
full_details: "Rua Izaurina Braga, Compensa, Manaus, Região Geográfica Imediata de Manaus, Região Geográfica Intermediária de Manaus, Amazonas, Região Norte, 69000-000, Brasil",
lat: "-3.1054153",
lng: "-60.0547259",
neighborhood: "Compensa",
postalcode: "69030-000",
state: "AM",
street: "Rua Izaurina Braga"
}}
```
"""
def get(input) when is_binary(input) do
cond do
cep?(input) -> get_viacep(input)
addr?(input) -> get_nominatim(input)
true -> msg_invalid_input()
end
end
def get(_) do
msg_invalid_input()
end
@doc """
Returns a error `{:error, "Invalid input"}`.
Argument must be provided.
## Examples
```
iex> GetGeocode.get
{:error, "Invalid input"}
```
"""
def get() do
msg_invalid_input()
end
defp get_viacep(cep) do
result = ViaCep.get_cep(cep)
case result do
%{"erro" => _} -> msg_invalid_input()
_ -> builder_from_viacep(result)
end
end
defp get_nominatim(addr) do
result = Nominatim.get_data(addr)
case result do
{_, _} -> result
_ -> builder_from_nominatim(result)
end
end
defp addr?(addr) do
addr
|> String.match?(~r/([a-zA-Z]+[\s|,]+[a-zA-Z]+[\s]*)/)
end
defp cep?(cep) do
cep
|> String.match?(~r/\b([0-9]{5}-?[0-9]{3})$/)
end
defp builder_from_viacep(result) do
%{
"bairro" => neighborhood,
"cep" => postalcode,
"localidade" => city,
"logradouro" => street,
"uf" => state
} = result
%{
"lon" => lng,
"lat" => lat,
"display_name" => full_details
} =
Regex.replace(~r/(.)\1+/, ~s[#{street},#{neighborhood},#{city}], "\\1")
|> Nominatim.get_data()
{:ok,
%Geocode{
postalcode: postalcode,
street: street,
neighborhood: neighborhood,
city: city,
state: state,
lat: lat,
lng: lng,
full_details: full_details
}}
end
defp builder_from_nominatim(result) do
%{
"display_name" => full_details,
"lat" => lat,
"lon" => lng
} = result
[street, neighborhood, city, _, _, state, _, postalcode | _] =
full_details
|> String.split(",")
|> Enum.map(fn x -> String.trim(x) end)
{:ok,
%Geocode{
postalcode: postalcode,
street: street,
neighborhood: neighborhood,
city: city,
state: state,
lat: lat,
lng: lng,
full_details: full_details
}}
end
defp msg_invalid_input() do
{:error, "Invalid input"}
end
end