lib/uphill_rating/import.ex
defmodule Import do
alias UphillRating.BicyclistRace
alias UphillRating.Bicyclist
alias UphillRating.Race
alias UphillRating.Team
alias UphillRating.Repo
def process_file(resource, file_path) do
data = File.stream!(file_path)
|> CSV.decode(separator: ?;)
|> Enum.with_index
|> Enum.map(fn {row, i} ->
{st, obj, message} = process(resource, row)
{st, obj, full_message(st, message, i)}
end)
{
(if data |> Enum.any?(fn e -> elem(e, 0) == :error end), do: :error, else: :ok),
data |> Enum.map(fn e -> elem e, 1 end),
data |> Enum.map(fn e -> elem e, 2 end)
}
end
defp full_message(status, message, i) do
if status != :ok do
"Error on line #{i + 1}: #{message}"
else
nil
end
end
defp process("BicyclistRace", row) do
time = time(row |> Enum.at 0)
bicyclist_name = row |> Enum.at 1
race_name = row |> Enum.at 2
team_name = row |> Enum.at 3
unless bicyclist = bicyclist(bicyclist_name) do
{:error, nil, "bicyclist \"#{bicyclist_name}\" not exist"}
else
unless race = race(race_name) do
{:error, nil, "race \"#{race_name}\" not exist"}
else
unless team = team(team_name) do
{:error, nil, "team \"#{team_name}\" not exist"}
else
obj = %BicyclistRace{
time: time,
bicyclist_id: bicyclist.id,
race_id: race.id,
team_id: team.id
}
{:ok, obj, nil}
end
end
end
end
defp process("Bicyclist", row) do
team_name = Enum.at(row, 3)
unless team = team(team_name) do
{:error, nil, "team \"#{team_name}\" not exist"}
else
obj = %Bicyclist{
name: Enum.at(row, 0),
year: Enum.at(row, 1),
sex: Enum.at(row, 2),
team_id: team.id
}
{:ok, obj, nil}
end
end
defp time(raw_time) do
raw_time |> String.split([":", "."]) |> Enum.with_index |> Enum.map(fn {e, i} -> if i == 3 do String.to_integer(e) * 100000 else String.to_integer e end end) |> List.to_tuple |> Ecto.Time.cast |> elem(1)
end
defp bicyclist(name) do
Bicyclist |> Repo.get_by name: name
end
defp race(name) do
Race |> Repo.get_by name: name
end
defp team(name) do
Team |> Repo.get_by name: name
end
end