Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
8 changed files
with
155 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@@ -0,0 +1,20 @@ | ||
defmodule ElixirMonitoringProm.Breweries do | ||
alias ElixirMonitoringProm.{Breweries.Brewery, Repo, ZipCodes} | ||
import Ecto.Query | ||
|
||
def get_breweries_in_radius(zip_code_to_search, radius_in_miles) do | ||
zip_codes_in_radius = | ||
zip_code_to_search | ||
|> ZipCodes.get_zip_codes_in_radius(radius_in_miles) | ||
|> case do | ||
{:ok, zip_codes} -> Enum.map(zip_codes, & &1.zip_code) | ||
error -> error | ||
end | ||
|
||
query = | ||
from brewery in Brewery, | ||
where: brewery.zip_code in ^zip_codes_in_radius | ||
|
||
Repo.all(query) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@@ -0,0 +1,23 @@ | ||
defmodule ElixirMonitoringProm.Breweries.Brewery do | ||
use Ecto.Schema | ||
|
||
import Ecto.Changeset | ||
|
||
alias __MODULE__ | ||
|
||
@derive {Jason.Encoder, only: ~w(brand beers zip_code)a} | ||
schema "breweries" do | ||
field :brand, :string | ||
field :beers, {:array, :string} | ||
field :zip_code, :string | ||
end | ||
|
||
def changeset(%Brewery{} = brewery, attrs \\ %{}) do | ||
all_fields = [:brand, :beers, :zip_code] | ||
|
||
brewery | ||
|> cast(attrs, all_fields) | ||
|> validate_required(all_fields) | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@@ -0,0 +1,34 @@ | ||
defmodule ElixirMonitoringProm.ZipCodes do | ||
alias ElixirMonitoringProm.{Repo, ZipCodes.ZipCode} | ||
|
||
def get_zip_codes_in_radius(zip_code, radius_in_miles) do | ||
# Our raw Postgres query to get all the zip codes within a radius | ||
query = | ||
[ | ||
"WITH target AS (SELECT point AS p FROM zip_codes WHERE zip_code = $1::varchar)", | ||
"SELECT id, zip_code, city, state, timezone, dst, point FROM zip_codes JOIN target ON true", | ||
"WHERE ST_DWithin(p::geography, zip_codes.point::geography, $2::double precision)" | ||
] | ||
|> Enum.join(" ") | ||
|
||
# The arguments we are passing to the query | ||
args = [zip_code, miles_to_meters(radius_in_miles)] | ||
|
||
# Since we used a raw SQL query, we'll need to manually (for more information | ||
# see https://hexdocs.pm/ecto_sql/Ecto.Adapters.SQL.html#query/4) | ||
case Repo.query(query, args, log: true) do | ||
{:ok, %Postgrex.Result{columns: cols, rows: rows}} -> | ||
results = | ||
Enum.map(rows, fn row -> | ||
Repo.load(ZipCode, {cols, row}) | ||
end) | ||
|
||
{:ok, results} | ||
|
||
_ -> | ||
{:error, :not_found} | ||
end | ||
end | ||
|
||
defp miles_to_meters(miles), do: miles * 1609.344 | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@@ -0,0 +1,18 @@ | ||
defmodule ElixirMonitoringPromWeb.BreweryController do | ||
use ElixirMonitoringPromWeb, :controller | ||
|
||
alias ElixirMonitoringProm.Breweries | ||
|
||
def index(conn, %{"zip_code" => zip_code, "mile_radius" => radius}) do | ||
results = Breweries.get_breweries_in_radius(zip_code, String.to_integer(radius)) | ||
|
||
json(conn, results) | ||
end | ||
|
||
def index(conn, _) do | ||
conn | ||
|> json(%{ | ||
error: "\"zip_code\" and \"mile_radius\" are both required fields" | ||
}) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@@ -0,0 +1,51 @@ | ||
defmodule ElixirMonitoringProm.Repo.Migrations.BreweryTable do | ||
use Ecto.Migration | ||
|
||
alias ElixirMonitoringProm.{Breweries.Brewery, Repo, ZipCodes.ZipCode} | ||
alias Faker.{Beer, Company} | ||
|
||
import Ecto.Query | ||
|
||
def up do | ||
create table(:breweries) do | ||
add :brand, :string | ||
add :beers, {:array, :string} | ||
add :zip_code, :string | ||
end | ||
|
||
create index(:breweries, [:zip_code]) | ||
|
||
# Flush the database changes so that we can populate the tables with dummy data | ||
flush() | ||
|
||
Faker.start() | ||
|
||
# Go through all of the zip codes in WA state and create between 1-3 brewers | ||
ZipCode | ||
|> Repo.all() | ||
|> Enum.each(fn %ZipCode{zip_code: zip_code} -> | ||
num_breweries = Enum.random(1..3) | ||
generate_breweries(zip_code, num_breweries) | ||
end) | ||
end | ||
|
||
defp generate_breweries(_zip_code, 0), do: :ok | ||
|
||
defp generate_breweries(zip_code, count) do | ||
attrs = %{ | ||
brand: Company.name() <> " Brewers", | ||
beers: [Beer.name(), Beer.name()], | ||
zip_code: zip_code | ||
} | ||
|
||
%Brewery{} | ||
|> Brewery.changeset(attrs) | ||
|> Repo.insert() | ||
|
||
generate_breweries(zip_code, count - 1) | ||
end | ||
|
||
def down do | ||
drop table(:breweries) | ||
end | ||
end |