Skip to content

Commit

Permalink
feat(Repository.routes): overwrite colors with line colors (#228)
Browse files Browse the repository at this point in the history
* feat(Repository.routes): overwrite colors with line colors

* refactor: overwrite route color at parsing time
  • Loading branch information
KaylaBrady authored Oct 29, 2024
1 parent d1961eb commit b35fde3
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 38 deletions.
12 changes: 8 additions & 4 deletions lib/mbta_v3_api/json_api/object.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule MBTAV3API.JsonApi.Object do
Shared logic for all objects that can be represented as JSON:API resources.
"""
alias MBTAV3API.JsonApi
alias MBTAV3API.Route

@doc """
JSON:API type name for the object this module represents.
Expand All @@ -16,6 +17,7 @@ defmodule MBTAV3API.JsonApi.Object do
Map of related objects that can be included to their struct modules. `%{trip: MBTAV3API.Trip, stops: MBTAV3API.Stop, parent_station: MBTAV3API.Stop}`, etc. Names should match `defstruct/1`.
"""
@callback includes :: %{atom() => module()}

@doc """
If needed, a custom serialize function.
Expand Down Expand Up @@ -180,10 +182,12 @@ defmodule MBTAV3API.JsonApi.Object do
Preserving references is probably not still useful now that we are never nesting objects.
"""
@spec parse(JsonApi.Item.t()) :: t()
@spec parse(JsonApi.Reference.t()) :: JsonApi.Reference.t()
def parse(%JsonApi.Item{type: type} = item), do: module_for(type).parse(item)
def parse(%JsonApi.Reference{} = ref), do: ref
@spec parse(JsonApi.Item.t(), [JsonApi.Item.t()]) :: t()
@spec parse(JsonApi.Reference.t(), [JsonApi.Item.t()]) :: JsonApi.Reference.t()
def parse(item, included \\ [])
def parse(%JsonApi.Item{type: "route"} = item, included), do: Route.parse(item, included)
def parse(%JsonApi.Item{type: type} = item, _included), do: module_for(type).parse(item)
def parse(%JsonApi.Reference{} = ref, _included), do: ref

@doc """
Gets the `id` of a single `JsonApi.Reference`.
Expand Down
4 changes: 2 additions & 2 deletions lib/mbta_v3_api/json_api/response.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ defmodule MBTAV3API.JsonApi.Response do
@spec parse(JsonApi.t()) :: t(JsonApi.Object.t())
def parse(%JsonApi{data: data, included: included}) do
%__MODULE__{
data: Enum.map(data, &JsonApi.Object.parse/1),
included: included |> Enum.map(&JsonApi.Object.parse/1) |> to_full_map()
data: Enum.map(data, &JsonApi.Object.parse(&1, included)),
included: included |> Enum.map(&JsonApi.Object.parse(&1, included)) |> to_full_map()
}
end
end
22 changes: 17 additions & 5 deletions lib/mbta_v3_api/route.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,34 @@ defmodule MBTAV3API.Route do
def serialize_filter_value(:type, type), do: serialize_type(type)
def serialize_filter_value(_field, value), do: value

@spec parse(JsonApi.Item.t()) :: t()
def parse(%JsonApi.Item{} = item) do
@spec parse(JsonApi.Item.t(), [JsonApi.Object.t()]) :: t()
def parse(%JsonApi.Item{} = item, included_items \\ []) do
line_id = JsonApi.Object.get_one_id(item.relationships["line"])

line = Enum.find(included_items, fn item -> item.type == "line" && item.id == line_id end)

# Override colors with line color when available. This way, OL Shuttle colors
# match the OL rather than matching other buses.
{color, text_color} =
case line do
%{attributes: %{"color" => color, "text_color" => text_color}} -> {color, text_color}
nil -> {item.attributes["color"], item.attributes["text_color"]}
end

%__MODULE__{
id: item.id,
type:
if type = item.attributes["type"] do
parse_type(type)
end,
color: item.attributes["color"],
color: color,
direction_names: item.attributes["direction_names"],
direction_destinations: item.attributes["direction_destinations"],
long_name: item.attributes["long_name"],
short_name: item.attributes["short_name"],
sort_order: item.attributes["sort_order"],
text_color: item.attributes["text_color"],
line_id: JsonApi.Object.get_one_id(item.relationships["line"]),
text_color: text_color,
line_id: line_id,
route_pattern_ids: JsonApi.Object.get_many_ids(item.relationships["route_patterns"])
}
end
Expand Down
143 changes: 143 additions & 0 deletions test/mbta_v3_api/repository_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule MBTAV3API.RepositoryTest do

import Mox

alias MBTAV3API.Route
alias MBTAV3API.{Alert, Repository, RoutePattern, Stop}
import Test.Support.Sigils

Expand Down Expand Up @@ -222,6 +223,148 @@ defmodule MBTAV3API.RepositoryTest do
}} = Repository.route_patterns([])
end

describe "routes/2" do
test "fetches routes" do
expect(
MobileAppBackend.HTTPMock,
:request,
fn %Req.Request{url: %URI{path: "/routes"}, options: _params} ->
{:ok,
Req.Response.json(%{
data: [
%{
attributes: %{
color: "ED8B00",
description: "Rapid Transit",
direction_destinations: [
"Forest Hills",
"Oak Grove"
],
direction_names: [
"South",
"North"
],
fare_class: "Rapid Transit",
long_name: "Orange Line",
short_name: "",
sort_order: 10_020,
text_color: "FFFFFF",
type: 1
},
id: "Orange",
links: %{
self: "/routes/Orange"
},
relationships: %{
line: %{
data: %{
id: "line-Orange",
type: "line"
}
}
},
type: "route"
}
]
})}
end
)

assert {:ok,
%{
data: [
%Route{
id: "Orange",
long_name: "Orange Line"
}
]
}} = Repository.routes([])
end

test "overrides route color with line color" do
expect(
MobileAppBackend.HTTPMock,
:request,
fn %Req.Request{
url: %URI{path: "/routes"},
options: %{
params: %{"include" => "line,route_patterns", "fields[route]" => "short_name"}
}
} ->
{:ok,
Req.Response.json(%{
data: [
%{
attributes: %{
color: "FFC72C",
description: "Rail Replacement Bus",
direction_destinations: [
"Forest Hills",
"Back Bay"
],
direction_names: [
"South",
"North"
],
fare_class: "Free",
long_name: "Forest Hills - Back Bay",
short_name: "Orange Line Shuttle",
sort_order: 60_491,
text_color: "000000",
type: 3
},
id: "Shuttle-BackBayForestHills",
links: %{
self: "/routes/Shuttle-BackBayForestHills"
},
relationships: %{
line: %{
data: %{
id: "line-Orange",
type: "line"
}
}
},
type: "route"
}
],
included: [
%{
attributes: %{
color: "ED8B00",
long_name: "Orange Line",
short_name: "",
sort_order: 10_020,
text_color: "FFFFFF"
},
id: "line-Orange",
links: %{
self: "/lines/line-Orange"
},
type: "line"
}
]
})}
end
)

assert {:ok,
%{
data: [
%Route{
id: "Shuttle-BackBayForestHills",
color: "ED8B00",
text_color: "FFFFFF"
}
]
}} =
Repository.routes(
include: [:line, :route_patterns],
fields: [route: [:short_name]]
)
end
end

test "stops/2" do
expect(
MobileAppBackend.HTTPMock,
Expand Down
99 changes: 72 additions & 27 deletions test/mbta_v3_api/route_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,78 @@ defmodule MBTAV3API.RouteTest do
alias MBTAV3API.JsonApi
alias MBTAV3API.Route

test "parse/1" do
assert Route.parse(%JsonApi.Item{
id: "Green-C",
attributes: %{
"color" => "00843D",
"direction_destinations" => ["Cleveland Circle", "Government Center"],
"direction_names" => ["West", "East"],
"long_name" => "Green Line C",
"short_name" => "C",
"sort_order" => 10_033,
"text_color" => "FFFFFF",
"type" => 0
},
relationships: %{
"line" => %JsonApi.Reference{type: "line", id: "line-Green"}
describe "parse/1" do
test "parse route only" do
assert Route.parse(%JsonApi.Item{
id: "Green-C",
attributes: %{
"color" => "00843D",
"direction_destinations" => ["Cleveland Circle", "Government Center"],
"direction_names" => ["West", "East"],
"long_name" => "Green Line C",
"short_name" => "C",
"sort_order" => 10_033,
"text_color" => "FFFFFF",
"type" => 0
},
relationships: %{
"line" => %JsonApi.Reference{type: "line", id: "line-Green"}
}
}) == %Route{
id: "Green-C",
color: "00843D",
direction_destinations: ["Cleveland Circle", "Government Center"],
direction_names: ["West", "East"],
long_name: "Green Line C",
short_name: "C",
sort_order: 10_033,
text_color: "FFFFFF",
type: :light_rail,
line_id: "line-Green"
}
}) == %Route{
id: "Green-C",
color: "00843D",
direction_destinations: ["Cleveland Circle", "Government Center"],
direction_names: ["West", "East"],
long_name: "Green Line C",
short_name: "C",
sort_order: 10_033,
text_color: "FFFFFF",
type: :light_rail,
line_id: "line-Green"
}
end

test "parse with included line overrides route color" do
assert %Route{
id: "orange-shuttle",
color: "line_color",
direction_destinations: ["Oak Grove", "Forest Hills"],
direction_names: ["Northbound", "Southbound"],
long_name: "Orange Line Shuttle",
short_name: "OL Shuttle",
sort_order: 123,
text_color: "line_text_color",
type: :bus,
line_id: "line-Orange"
} ==
Route.parse(
%JsonApi.Item{
id: "orange-shuttle",
attributes: %{
"color" => "bus_color",
"direction_destinations" => ["Oak Grove", "Forest Hills"],
"direction_names" => ["Northbound", "Southbound"],
"long_name" => "Orange Line Shuttle",
"short_name" => "OL Shuttle",
"sort_order" => 123,
"text_color" => "bus_text_color",
"type" => 3
},
relationships: %{
"line" => %JsonApi.Reference{type: "line", id: "line-Orange"}
}
},
[
%JsonApi.Item{
type: "line",
id: "line-Orange",
attributes: %{
"color" => "line_color",
"text_color" => "line_text_color"
}
}
]
)
end
end
end

0 comments on commit b35fde3

Please sign in to comment.