diff --git a/apps/lol_analytics/lib/lol_analytics/analyzer/base_analyzer.ex b/apps/lol_analytics/lib/lol_analytics/analyzer/base_analyzer.ex index 1c62152..76ea734 100644 --- a/apps/lol_analytics/lib/lol_analytics/analyzer/base_analyzer.ex +++ b/apps/lol_analytics/lib/lol_analytics/analyzer/base_analyzer.ex @@ -1,3 +1,3 @@ -defmodule LolAnalytics.Analyzer.BaseAnalyzer do +defmodule LolAnalytics.Analyzer do @callback analyze(:url, path :: String.t()) :: :ok end diff --git a/apps/lol_analytics/lib/lol_analytics/analyzer/champion_analyzer.ex b/apps/lol_analytics/lib/lol_analytics/analyzer/champion_analyzer.ex index 965d16b..aeedcb2 100644 --- a/apps/lol_analytics/lib/lol_analytics/analyzer/champion_analyzer.ex +++ b/apps/lol_analytics/lib/lol_analytics/analyzer/champion_analyzer.ex @@ -1,9 +1,17 @@ defmodule LolAnalytics.Analyzer.ChampionAnalyzer do alias Hex.HTTP - @behaviour LolAnalytics.Analyzer.BaseAnalyzer + @behaviour LolAnalytics.Analyzer + + def analyze_all_matches do + Storage.MatchStorage.S3MatchStorage.list_files("ranked") + |> Enum.map(& &1.key) + |> Enum.each(fn path -> + LolAnalytics.Analyzer.ChampionAnalyzer.analyze(:url, "http://localhost:9000/ranked/#{path}") + end) + end @doc """ - :ok + iex> LolAnalytics.Analyzer.ChampionAnalyzer.analyze(:url, "http://localhost:9000/ranked/14.9.580.2108/EUW1_6923309745.json") """ @impl true @spec analyze(atom(), String.t()) :: :ok @@ -13,19 +21,30 @@ defmodule LolAnalytics.Analyzer.ChampionAnalyzer do :ok end - @doc """ - iex> LolAnalytics.Analyzer.ChampionAnalyzer.analyze(:url, "http://localhost:9000/ranked/14.9.580.2108/EUW1_6923309745.json") - """ @impl true @spec analyze(atom(), any()) :: list(LoLAPI.Model.Participant.t()) def analyze(:data, data) do - decoded = Poison.decode!(data) - - %{"info" => %{"participants" => participants}} = decoded + decoded_match = Poison.decode!(data, as: %LoLAPI.Model.MatchResponse{}) + participants = decoded_match.info.participants + version = extract_game_version(decoded_match) participants - |> Enum.each(fn %{"win" => win, "championId" => champion_id} -> - IO.inspect(%{win: win, champion_id: champion_id}) + |> Enum.each(fn participant = %LoLAPI.Model.Participant{} -> + if participant.teamPosition != "" do + LolAnalytics.ChampionWinRate.ChampionWinRateRepo.add_champion_win_rate( + participant.championId, + version, + participant.teamPosition, + participant.win + ) + end end) end + + defp extract_game_version(game_data) do + game_data.info.gameVersion + |> String.split(".") + |> Enum.take(2) + |> Enum.join(".") + end end diff --git a/apps/lol_analytics/lib/lol_analytics/champion_win_rate/champion_win_rate_repo.ex b/apps/lol_analytics/lib/lol_analytics/champion_win_rate/champion_win_rate_repo.ex new file mode 100644 index 0000000..b24b302 --- /dev/null +++ b/apps/lol_analytics/lib/lol_analytics/champion_win_rate/champion_win_rate_repo.ex @@ -0,0 +1,56 @@ +defmodule LolAnalytics.ChampionWinRate.ChampionWinRateRepo do + import Ecto.Query + alias LolAnalytics.ChampionWinRate.ChampionWinRateSchema + alias LoLAnalytics.Repo + + @spec add_champion_win_rate( + champion_id :: String.t(), + patch :: String.t(), + position :: String.t(), + win? :: boolean + ) :: {:ok, ChampionWinRateSchema.t()} | {:error, Ecto.Changeset.t()} + def add_champion_win_rate(champion_id, patch, position, win?) do + Repo.transaction(fn -> + champion_query = + from cwr in LolAnalytics.ChampionWinRate.ChampionWinRateSchema, + where: cwr.champion_id == ^champion_id and cwr.position == ^position, + lock: "FOR UPDATE" + + champion_data = Repo.one(champion_query) + + case champion_data do + nil -> + ChampionWinRateSchema.changeset(%ChampionWinRateSchema{}, %{ + champion_id: champion_id, + patch: patch, + total_games: 1, + position: position, + total_wins: if(win?, do: 1, else: 0) + }) + |> Repo.insert!() + + _ -> + total_games = champion_data.total_games + 1 + total_wins = champion_data.total_wins + if win?, do: 1, else: 0 + + ChampionWinRateSchema.changeset(champion_data, %{ + total_games: total_games, + total_wins: total_wins + }) + |> Repo.update!() + end + end) + end + + def list_win_rates() do + Repo.all(ChampionWinRateSchema) + end + + def get_champion_win_rate(champion_id, patch) do + champion_query = + from cwr in LolAnalytics.ChampionWinRate.ChampionWinRateSchema, + where: cwr.champion_id == ^champion_id + + Repo.one(champion_query) + end +end diff --git a/apps/lol_analytics/lib/lol_analytics/champion_win_rate/champion_win_rate_schema.ex b/apps/lol_analytics/lib/lol_analytics/champion_win_rate/champion_win_rate_schema.ex new file mode 100644 index 0000000..ff95c61 --- /dev/null +++ b/apps/lol_analytics/lib/lol_analytics/champion_win_rate/champion_win_rate_schema.ex @@ -0,0 +1,20 @@ +defmodule LolAnalytics.ChampionWinRate.ChampionWinRateSchema do + use Ecto.Schema + import Ecto.Changeset + + schema "champion_win_rate" do + field :champion_id, :integer + field :total_games, :integer + field :patch, :string + field :position, :string + field :total_wins, :integer + + timestamps() + end + + def changeset(%__MODULE__{} = champion_win_rate, attrs) do + champion_win_rate + |> cast(attrs, [:champion_id, :total_games, :patch, :total_wins, :position]) + |> validate_required([:champion_id, :total_games, :patch, :total_wins, :position]) + end +end diff --git a/apps/lol_analytics/priv/repo/migrations/20240511110543_champion_win_rate.exs b/apps/lol_analytics/priv/repo/migrations/20240511110543_champion_win_rate.exs new file mode 100644 index 0000000..221205c --- /dev/null +++ b/apps/lol_analytics/priv/repo/migrations/20240511110543_champion_win_rate.exs @@ -0,0 +1,21 @@ +defmodule LoLAnalytics.Repo.Migrations.ChampionWinRate do + use Ecto.Migration + + def change do + create table("champion_win_rate") do + add :champion_id, :integer + add :patch, :string + add :position, :string + add :total_games, :integer + add :total_wins, :integer + timestamps() + end + + alter table("match") do + add :win_rate_processed, :boolean, default: false + end + + index("champion_win_rate", [:champion_id], unique: false) + index("champion_win_rate", [:champion_id, :patch], unique: true) + end +end