Skip to content
Permalink
Browse files

Code for step 4

  • Loading branch information
akoutmos committed Aug 21, 2019
1 parent 9477652 commit 6c6f8110918deda3c4e84ea34d4d88c51ef6c29a
@@ -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
@@ -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

@@ -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
@@ -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
@@ -13,6 +13,12 @@ defmodule ElixirMonitoringPromWeb.Router do
plug :accepts, ["json"]
end

scope "/api", ElixirMonitoringPromWeb do
pipe_through :api

get "/breweries", BreweryController, :index
end

scope "/", ElixirMonitoringPromWeb do
pipe_through :browser

@@ -44,7 +44,8 @@ defmodule ElixirMonitoringProm.MixProject do
{:jason, "~> 1.0"},
{:plug_cowboy, "~> 2.0"},
{:geo, "~> 3.1.0"},
{:geo_postgis, "~> 3.1.0"}
{:geo_postgis, "~> 3.1.0"},
{:faker, "~> 0.12.0"}
]
end

@@ -6,6 +6,7 @@
"decimal": {:hex, :decimal, "1.8.0", "ca462e0d885f09a1c5a342dbd7c1dcf27ea63548c65a65e67334f4b61803822e", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "3.1.7", "fa21d06ef56cdc2fdaa62574e8c3ba34a2751d44ea34c30bc65f0728421043e5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"ecto_sql": {:hex, :ecto_sql, "3.1.6", "1e80e30d16138a729c717f73dcb938590bcdb3a4502f3012414d0cbb261045d8", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0 or ~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
"faker": {:hex, :faker, "0.12.0", "796cbac868c86c2df6f273ea4cdf2e271860863820e479e04a374b7ee6c376b6", [:mix], [], "hexpm"},
"file_system": {:hex, :file_system, "0.2.7", "e6f7f155970975789f26e77b8b8d8ab084c59844d8ecfaf58cbda31c494d14aa", [:mix], [], "hexpm"},
"geo": {:hex, :geo, "3.1.0", "727e005262430d037e870ff364e65d80ca5ca21d5ac8eddd57a1ada72c3f83b0", [:mix], [], "hexpm"},
"geo_postgis": {:hex, :geo_postgis, "3.1.0", "d06c8fa5fd140a52a5c9dab4ad6623a696dd7d99dd791bb361d3f94942442ff9", [:mix], [{:geo, "~> 3.1", [hex: :geo, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0 or ~> 4.0", [hex: :poison, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm"},
@@ -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

0 comments on commit 6c6f811

Please sign in to comment.
You can’t perform that action at this time.