defmodule WinticketRaceParser.FromResponse do
alias WinticketRaceParser.Structs.{
RaceContext,
Race,
Cup,
OddsItem,
OddsCategory,
ResultItem,
PlayerDetail,
Player,
ResultHistory,
PlayerRecord,
PlayerRecordLegType,
PlayerRecordPercent,
PlayerRecordSB,
Venue
}
# body: response of /v1/keirin/cups/:cup_id/schedules/:day/races/:r?pfm=web
def parse(body) do
%{cup: cup, race: race} = parse_race_info(body["race"], body["schedule"], body["cups"])
players = parse_players(body["entries"], body["players"], body["records"])
line = parse_line(body["linePrediction"])
odds = parse_odds(body)
results = parse_results(body["results"], body["entries"])
venue = parse_venue(body["schedule"], body["cups"], body["venues"])
is_defect = [line] |> Enum.member?(nil)
is_finish = results != []
RaceContext.validate(%{
players: players,
line: line,
results: results,
odds: odds,
race: race,
venue: venue,
cup: cup,
is_defect: is_defect,
is_finish: is_finish
})
end
defp parse_venue(schedule_r, cups_r, venues_r) do
cup = Enum.find(cups_r, fn %{"id" => c_id} -> c_id == schedule_r["cupId"] end)
venue = Enum.find(venues_r, fn %{"id" => v_id} -> v_id == cup["venueId"] end)
Venue.validate(%{
name: venue["name"],
slug: venue["slug"],
id: venue["id"],
region_id: venue["regionId"],
has_food: venue["hasFood"],
distance: venue["trackDistance"],
straight_distance: venue["trackStraightDistance"],
home_width: venue["homeWidth"],
back_width: venue["backWidth"]
})
end
defp parse_race_info(race_r, schedule_r, cups_r) do
cup = Enum.find(cups_r, fn %{"id" => c_id} -> c_id == schedule_r["cupId"] end)
%{
race:
Race.validate(%{
id: race_r["id"],
r: race_r["number"],
day_index: schedule_r["index"],
day: schedule_r["day"],
start_at: race_r["startAt"],
close_at: race_r["closeAt"],
type: race_r["raceType"],
class: race_r["class"],
distance: race_r["distance"],
lap: race_r["lap"],
date: parse_date(schedule_r["date"])
}),
cup:
Cup.validate(%{
grade: cup["grade"],
venue_id: cup["venueId"],
name: cup["name"],
id: schedule_r["cupId"],
start_date: parse_date(cup["startDate"])
})
}
end
defp parse_odds([%{"key" => _, "odds" => _} | _] = odds) do
odds
|> Enum.map(fn odd ->
OddsItem.validate(%{
key: Enum.map(odd["key"], fn k -> "#{k}" end),
odds: odd["odds"]
})
end)
end
defp parse_odds(%{"quinella" => _} = odds_r) do
OddsCategory.validate(%{
nishafuku: parse_odds(odds_r["quinella"]),
nishatan: parse_odds(odds_r["exacta"])
})
end
defp parse_results(result_r, entries_r) do
result_r
|> Enum.map(fn r ->
%{
"playerId" => p_id,
"hasAccident" => has_accident,
"accident" => accident,
"factor" => factor,
"finalHalfRecord" => agari_time,
"standing" => standing,
"back" => back
} = r
hit =
entries_r
|> Enum.find(fn %{"playerId" => id} -> id == p_id end)
ResultItem.validate(%{
number: "#{hit["number"]}",
player_id: "#{p_id}",
has_accident: has_accident,
accident: with("" <- accident, do: nil),
factor: factor,
agari_time: parse_float(agari_time),
standing: standing,
back: back
})
end)
end
defp parse_line(nil) do
nil
end
defp parse_line(line_prediction_r) do
line_prediction_r["lines"]
|> Enum.map(fn line -> line["entries"] end)
|> Enum.map(fn line ->
line
|> Enum.map(fn %{"numbers" => ns} -> ns end)
|> Enum.map(fn ns ->
case ns do
[n] ->
"#{n}"
[_ | _] ->
ns |> Enum.map(fn n -> "#{n}" end)
end
end)
end)
end
defp parse_players(entries_r, players_r, record_r) do
entries_r
|> Enum.map(fn %{"playerId" => p_id, "number" => number, "absent" => absent} ->
hit =
players_r
|> Enum.find(fn %{"id" => id} -> id == p_id end)
%{
number: "#{number}",
player_id: p_id,
absent: absent,
player:
PlayerDetail.validate(%{
name: hit["name"],
term: hit["term"],
class: hit["class"],
group: hit["group"],
age: hit["age"],
region_id: hit["regionId"]
})
}
end)
|> Enum.map(fn %{player_id: id} = data ->
hit =
record_r
|> Enum.find(fn %{"playerId" => p_id} -> p_id == id end)
adjust_latest_result_item = fn r ->
ResultHistory.validate(%{
day: r["day"],
has_accident: r["hasAccident"],
accident: with("" <- r["accident"], do: nil),
back: r["back"],
standing: r["standing"],
order: r["order"],
agari_time: parse_float(r["finalHalfRecord"]),
race_id: r["raceId"]
})
end
current_cup = Enum.map(hit["currentCupResults"], fn r -> adjust_latest_result_item.(r) end)
previous_cup =
Enum.map(hit["previousCupResults"], fn r -> adjust_latest_result_item.(r) end)
record =
PlayerRecord.validate(%{
race_point: hit["racePoint"],
comment: hit["comment"],
countable: hit["first"] + hit["second"] + hit["third"] + hit["others"],
sb:
PlayerRecordSB.validate(%{
standing: hit["standing"],
back: hit["back"]
}),
percent:
PlayerRecordPercent.validate(%{
in_1: hit["firstRate"],
in_2: hit["secondRate"],
in_3: hit["thirdRate"]
}),
leg_type:
PlayerRecordLegType.validate(%{
nige: hit["frontRunner"],
sashi: hit["stalker"],
makuri: hit["deepCloser"],
marker: hit["marker"]
})
})
Player.validate(%{
number: data[:number],
absent: data[:absent],
player_id: data[:player_id],
player: data[:player],
record: record,
current_cup: current_cup,
previous_cup: previous_cup
})
end)
end
defp parse_float(str) do
case Float.parse(str) do
{f, _} -> f
_ -> nil
end
end
# * winticketはYYYYMMDDで日付を扱う
# * それをmongoで扱うよう最適化
def parse_date(date_str) do
date_str
|> Timex.parse!("{YYYY}{0M}{0D}")
|> Timex.Timezone.convert("Asia/Tokyo")
end
end