diff --git a/apps/lol_analytics/lib/lol_analytics/dimensions/champion/champion_metadata.ex b/apps/lol_analytics/lib/lol_analytics/dimensions/champion/champion_metadata.ex
new file mode 100644
index 0000000..d720241
--- /dev/null
+++ b/apps/lol_analytics/lib/lol_analytics/dimensions/champion/champion_metadata.ex
@@ -0,0 +1,44 @@
+defmodule LolAnalytics.Dimensions.Champion.ChampionMetadata do
+ alias LolAnalytics.Dimensions.Champion.ChampionRepo
+ @champions_data_url "https://ddragon.leagueoflegends.com/cdn/14.11.1/data/en_US/champion.json"
+
+ use GenServer
+
+ def update_metadata() do
+ {:ok, %{"data" => data}} = get_champions()
+
+ data
+ |> Enum.each(&save_metadata/1)
+ end
+
+ defp get_champions() do
+ with {:ok, resp} <- HTTPoison.get(@champions_data_url),
+ data <- Poison.decode(resp.body) do
+ data
+ else
+ {:error, reason} -> {:error, reason}
+ end
+ end
+
+ defp save_metadata({champion, info}) do
+ %{
+ "image" => %{
+ "full" => full_image
+ },
+ "name" => name,
+ "key" => key_string
+ } = info
+
+ attrs = %{
+ image: full_image,
+ name: name
+ }
+
+ {champion_id, _} = Integer.parse(key_string)
+
+ ChampionRepo.update(champion_id, attrs)
+
+ info
+ |> IO.inspect()
+ end
+end
diff --git a/apps/lol_analytics/lib/lol_analytics/dimensions/champion/champion_repo.ex b/apps/lol_analytics/lib/lol_analytics/dimensions/champion/champion_repo.ex
index 8bc8e44..66da15e 100644
--- a/apps/lol_analytics/lib/lol_analytics/dimensions/champion/champion_repo.ex
+++ b/apps/lol_analytics/lib/lol_analytics/dimensions/champion/champion_repo.ex
@@ -18,6 +18,13 @@ defmodule LolAnalytics.Dimensions.Champion.ChampionRepo do
end
end
+ def update(champion_id, attrs) do
+ get_or_create(champion_id)
+ |> ChampionSchema.changeset(attrs)
+ |> Repo.update()
+ end
+
+ @spec list_champions() :: any()
def list_champions() do
Repo.all(ChampionSchema)
end
diff --git a/apps/lol_analytics/lib/lol_analytics/dimensions/champion/champion_schema.ex b/apps/lol_analytics/lib/lol_analytics/dimensions/champion/champion_schema.ex
index 7cc68cb..58cbe24 100644
--- a/apps/lol_analytics/lib/lol_analytics/dimensions/champion/champion_schema.ex
+++ b/apps/lol_analytics/lib/lol_analytics/dimensions/champion/champion_schema.ex
@@ -4,12 +4,14 @@ defmodule LolAnalytics.Dimensions.Champion.ChampionSchema do
schema "dim_champion" do
field :champion_id, :integer
+ field :name, :string
+ field :image, :string
timestamps()
end
def changeset(champion = %__MODULE__{}, attrs \\ %{}) do
champion
- |> cast(attrs, [:champion_id])
+ |> cast(attrs, [:champion_id, :name, :image])
|> validate_required([:champion_id])
end
end
diff --git a/apps/lol_analytics/lib/lol_analytics/facts/champion_played_game/champion_played_game_repo.ex b/apps/lol_analytics/lib/lol_analytics/facts/champion_played_game/champion_played_game_repo.ex
index 6d70cdf..2cde458 100644
--- a/apps/lol_analytics/lib/lol_analytics/facts/champion_played_game/champion_played_game_repo.ex
+++ b/apps/lol_analytics/lib/lol_analytics/facts/champion_played_game/champion_played_game_repo.ex
@@ -1,6 +1,7 @@
defmodule LolAnalytics.Facts.ChampionPlayedGame.ChampionPlayedGameRepo do
import Ecto.Query
+ alias LolAnalytics.Dimensions.Champion.ChampionSchema
alias LolAnalytics.Dimensions.Player.PlayerRepo
alias LolAnalytics.Dimensions.Champion.ChampionRepo
alias LolAnalytics.Dimensions.Match.MatchRepo
@@ -9,19 +10,70 @@ defmodule LolAnalytics.Facts.ChampionPlayedGame.ChampionPlayedGameRepo do
alias LoLAnalytics.Repo
def insert(attrs) do
- match = MatchRepo.get_or_create(attrs.match_id)
- champion = ChampionRepo.get_or_create(attrs.champion_id)
- player = PlayerRepo.get_or_create(attrs.puuid)
- IO.puts(">>>>")
- IO.inspect(attrs)
+ _match = MatchRepo.get_or_create(attrs.match_id)
+ _champion = ChampionRepo.get_or_create(attrs.champion_id)
+ _player = PlayerRepo.get_or_create(attrs.puuid)
changeset = ChampionPlayedGameSchema.changeset(%ChampionPlayedGameSchema{}, attrs)
-
- IO.inspect(changeset)
Repo.insert(changeset)
- # Repo.insert(match)
end
def list_played_matches() do
Repo.all(ChampionPlayedGameSchema)
end
+
+ def get_win_rates2 do
+ query2 =
+ from m in ChampionPlayedGameSchema,
+ join: c in ChampionSchema,
+ on: c.champion_id == m.champion_id,
+ select: %{
+ wins: count(m.is_win),
+ win_rate:
+ fragment(
+ "
+ ((cast(count(CASE WHEN ? THEN 1 END) as float) / cast(count(*) as float)) * 100.0
+ )",
+ m.is_win
+ ),
+ id: m.champion_id,
+ name: c.name,
+ image: c.image
+ },
+ group_by: [m.champion_id, c.image, c.name]
+
+ Repo.all(query2)
+ end
+
+ def get_win_rates() do
+ query = """
+ SELECT
+ (cast(count(CASE WHEN is_win THEN 1 END) as float) / cast(count(*) as float)) * 100.0 as win_rate,
+ count(CASE WHEN is_win THEN 1 END) as games_won,
+ count(*) as total_games,
+ champion_id
+ FROM fact_champion_played_game
+
+ GROUP BY champion_id
+ ORDER BY win_rate desc;
+ """
+
+ case Ecto.Adapters.SQL.query(Repo, query, []) do
+ {:ok, %Postgrex.Result{rows: rows}} ->
+ rows
+ |> Enum.map(fn [win_rate, wins, games, champion_id] ->
+ %{
+ win_rate: win_rate,
+ wins: wins,
+ games: games,
+ champion_id: champion_id
+ }
+ end)
+
+ {:error, _exception} ->
+ :error
+ end
+ end
+
+ def get_win_rates_by_roles() do
+ end
end
diff --git a/apps/lol_analytics/priv/repo/migrations/20240530194815_champion_dim_name_image.exs b/apps/lol_analytics/priv/repo/migrations/20240530194815_champion_dim_name_image.exs
new file mode 100644
index 0000000..ede6005
--- /dev/null
+++ b/apps/lol_analytics/priv/repo/migrations/20240530194815_champion_dim_name_image.exs
@@ -0,0 +1,10 @@
+defmodule LoLAnalytics.Repo.Migrations.ChampionDimName do
+ use Ecto.Migration
+
+ def change do
+ alter table("dim_champion") do
+ add :name, :string
+ add :image, :string
+ end
+ end
+end
diff --git a/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/form_component.ex b/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/form_component.ex
new file mode 100644
index 0000000..7932cf1
--- /dev/null
+++ b/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/form_component.ex
@@ -0,0 +1,90 @@
+defmodule LoLAnalyticsWeb.ChampionLive.FormComponent do
+ use LoLAnalyticsWeb, :live_component
+
+ alias LoLAnalytics.Accounts
+
+ @impl true
+ def render(assigns) do
+ ~H"""
+
+ <.header>
+ <%= @title %>
+ <:subtitle>Use this form to manage champion records in your database.
+
+
+ <.simple_form
+ for={@form}
+ id="champion-form"
+ phx-target={@myself}
+ phx-change="validate"
+ phx-submit="save"
+ >
+
+ <:actions>
+ <.button phx-disable-with="Saving...">Save Champion
+
+
+
+ """
+ end
+
+ @impl true
+ def update(%{champion: champion} = assigns, socket) do
+ changeset = Accounts.change_champion(champion)
+
+ {:ok,
+ socket
+ |> assign(assigns)
+ |> assign_form(changeset)}
+ end
+
+ @impl true
+ def handle_event("validate", %{"champion" => champion_params}, socket) do
+ changeset =
+ socket.assigns.champion
+ |> Accounts.change_champion(champion_params)
+ |> Map.put(:action, :validate)
+
+ {:noreply, assign_form(socket, changeset)}
+ end
+
+ def handle_event("save", %{"champion" => champion_params}, socket) do
+ save_champion(socket, socket.assigns.action, champion_params)
+ end
+
+ defp save_champion(socket, :edit, champion_params) do
+ case Accounts.update_champion(socket.assigns.champion, champion_params) do
+ {:ok, champion} ->
+ notify_parent({:saved, champion})
+
+ {:noreply,
+ socket
+ |> put_flash(:info, "Champion updated successfully")
+ |> push_patch(to: socket.assigns.patch)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, assign_form(socket, changeset)}
+ end
+ end
+
+ defp save_champion(socket, :new, champion_params) do
+ case Accounts.create_champion(champion_params) do
+ {:ok, champion} ->
+ notify_parent({:saved, champion})
+
+ {:noreply,
+ socket
+ |> put_flash(:info, "Champion created successfully")
+ |> push_patch(to: socket.assigns.patch)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, assign_form(socket, changeset)}
+ end
+ end
+
+ defp assign_form(socket, %Ecto.Changeset{} = changeset) do
+ assign(socket, :form, to_form(changeset))
+ end
+
+ defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
+end
diff --git a/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/index.ex b/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/index.ex
new file mode 100644
index 0000000..65270d3
--- /dev/null
+++ b/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/index.ex
@@ -0,0 +1,80 @@
+defmodule LoLAnalyticsWeb.ChampionLive.Index do
+ alias ElixirLS.LanguageServer.Providers.Completion.Reducers.Struct
+ use LoLAnalyticsWeb, :live_view
+
+ defstruct id: "", win_rate: 0, wins: 0, image: "", name: ""
+
+ @roles ["all", "TOP", "JUNGLE", "MIDDLE", "BOTTOM", "UTILITY"]
+
+ @impl true
+ def mount(_params, _session, socket) do
+ champs = LolAnalytics.Facts.ChampionPlayedGame.ChampionPlayedGameRepo.get_win_rates2()
+
+ mapped =
+ champs
+ |> Enum.map(fn champ ->
+ Kernel.struct!(%__MODULE__{}, champ)
+ end)
+ |> Enum.sort(&(&1.win_rate >= &2.win_rate))
+
+ {:ok,
+ stream(
+ socket,
+ :champions,
+ mapped
+ )
+ |> assign(:form, to_form(%{"name" => ""}))}
+ end
+
+ def handle_event("filter", params, socket) do
+ %{"name" => query_name} = params
+
+ champs =
+ LolAnalytics.Facts.ChampionPlayedGame.ChampionPlayedGameRepo.get_win_rates2()
+ |> Enum.filter(fn %{name: name} ->
+ String.downcase(name) |> String.contains?(query_name)
+ end)
+ |> Enum.map(fn champ ->
+ Kernel.struct!(%__MODULE__{}, champ)
+ end)
+ |> Enum.sort(&(&1.win_rate >= &2.win_rate))
+
+ IO.inspect(champs)
+
+ {:noreply,
+ stream(
+ socket,
+ :champions,
+ champs
+ )}
+ end
+
+ def handle_event("filter_by", %{"name" => name}, socket) do
+ {:noreply, assign(socket, %{filter_by: name})}
+ end
+
+ @impl true
+ def handle_params(params, _url, socket) do
+ {:noreply, apply_action(socket, socket.assigns.live_action, params)}
+ end
+
+ defp apply_action(socket, :index, _params) do
+ socket
+ |> assign(:page_title, "Listing Champions")
+
+ # |> assign(:champion, nil)
+ end
+
+ @impl true
+ def handle_info({LoLAnalyticsWeb.ChampionLive.FormComponent, {:saved, champion}}, socket) do
+ {:noreply, stream_insert(socket, :champions, champion)}
+ end
+
+ # @impl true
+ # def handle_event("delete", %{"id" => id}, socket) do
+ # champion = Accounts.get_champion!(id)
+ # {:ok, _} = Accounts.delete_champion(champion)
+
+ # {:noreply, stream_delete(socket, :champions, champion)}
+ # end
+end
diff --git a/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/index.html.heex b/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/index.html.heex
new file mode 100644
index 0000000..bd689a5
--- /dev/null
+++ b/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/index.html.heex
@@ -0,0 +1,66 @@
+<.header>
+ Listing Champions
+
+
+Champions
+<.form for={@form} phx-change="filter" phx-submit="save">
+ <.input type="text" field={@form["name"]} />
+ <.input type="checkbox" field={@form["all_roles"]} />
+
+
+ <.input type="checkbox" field={@form["top_role"]} />
+
Top
+
+
+ <.input type="checkbox" field={@form["middle_role"]} />
+
Middle
+
+
+ <.input type="checkbox" field={@form["jungle_role"]} />
+
Jungle
+
+
+ <.input type="checkbox" field={@form["bottom_role"]} />
+
Bottom
+
+
+ <.input type="checkbox" field={@form["utility_role"]} />
+
Utility
+
+
+
+
+
+
+
+ <%= for {_, champion} <- @streams.champions do %>
+
+

+
+
<%= champion.name %>
+
<%= champion.id %>
+
<%= champion.win_rate %>%
+
+
+
+
+ <.link navigate={~p"/champions/#{champion}"}>Show
+
+ <% end %>
+
+
+<.modal
+ :if={@live_action in [:new, :edit]}
+ id="champion-modal"
+ show
+ on_cancel={JS.patch(~p"/champions")}
+>
+ <.live_component
+ module={LoLAnalyticsWeb.ChampionLive.FormComponent}
+ id={@champion.champion_id || :new}
+ title={@page_title}
+ action={@live_action}
+ champion={@champion}
+ patch={~p"/champions"}
+ />
+
diff --git a/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/show.ex b/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/show.ex
new file mode 100644
index 0000000..5d6db86
--- /dev/null
+++ b/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/show.ex
@@ -0,0 +1,21 @@
+defmodule LoLAnalyticsWeb.ChampionLive.Show do
+ use LoLAnalyticsWeb, :live_view
+
+ alias LoLAnalytics.Accounts
+
+ @impl true
+ def mount(_params, _session, socket) do
+ {:ok, socket}
+ end
+
+ @impl true
+ def handle_params(%{"id" => id}, _, socket) do
+ {:noreply,
+ socket
+ |> assign(:page_title, page_title(socket.assigns.live_action))
+ |> assign(:champion, Accounts.get_champion!(id))}
+ end
+
+ defp page_title(:show), do: "Show Champion"
+ defp page_title(:edit), do: "Edit Champion"
+end
diff --git a/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/show.html.heex b/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/show.html.heex
new file mode 100644
index 0000000..c04f3c2
--- /dev/null
+++ b/apps/lol_analytics_web/lib/lol_analytics_web/live/champion_live/show.html.heex
@@ -0,0 +1,25 @@
+<.header>
+ Champion <%= @champion.id %>
+ <:subtitle>This is a champion record from your database.
+ <:actions>
+ <.link patch={~p"/champions/#{@champion}/show/edit"} phx-click={JS.push_focus()}>
+ <.button>Edit champion
+
+
+
+
+<.list>
+
+
+<.back navigate={~p"/champions"}>Back to champions
+
+<.modal :if={@live_action == :edit} id="champion-modal" show on_cancel={JS.patch(~p"/champions/#{@champion}")}>
+ <.live_component
+ module={LoLAnalyticsWeb.ChampionLive.FormComponent}
+ id={@champion.id}
+ title={@page_title}
+ action={@live_action}
+ champion={@champion}
+ patch={~p"/champions/#{@champion}"}
+ />
+
diff --git a/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/form_component.ex b/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/form_component.ex
new file mode 100644
index 0000000..d2a59b8
--- /dev/null
+++ b/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/form_component.ex
@@ -0,0 +1,90 @@
+defmodule LoLAnalyticsWeb.RoleLive.FormComponent do
+ use LoLAnalyticsWeb, :live_component
+
+ alias LoLAnalytics.Accounts
+
+ @impl true
+ def render(assigns) do
+ ~H"""
+
+ <.header>
+ <%= @title %>
+ <:subtitle>Use this form to manage role records in your database.
+
+
+ <.simple_form
+ for={@form}
+ id="role-form"
+ phx-target={@myself}
+ phx-change="validate"
+ phx-submit="save"
+ >
+
+ <:actions>
+ <.button phx-disable-with="Saving...">Save Role
+
+
+
+ """
+ end
+
+ @impl true
+ def update(%{role: role} = assigns, socket) do
+ changeset = Accounts.change_role(role)
+
+ {:ok,
+ socket
+ |> assign(assigns)
+ |> assign_form(changeset)}
+ end
+
+ @impl true
+ def handle_event("validate", %{"role" => role_params}, socket) do
+ changeset =
+ socket.assigns.role
+ |> Accounts.change_role(role_params)
+ |> Map.put(:action, :validate)
+
+ {:noreply, assign_form(socket, changeset)}
+ end
+
+ def handle_event("save", %{"role" => role_params}, socket) do
+ save_role(socket, socket.assigns.action, role_params)
+ end
+
+ defp save_role(socket, :edit, role_params) do
+ case Accounts.update_role(socket.assigns.role, role_params) do
+ {:ok, role} ->
+ notify_parent({:saved, role})
+
+ {:noreply,
+ socket
+ |> put_flash(:info, "Role updated successfully")
+ |> push_patch(to: socket.assigns.patch)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, assign_form(socket, changeset)}
+ end
+ end
+
+ defp save_role(socket, :new, role_params) do
+ case Accounts.create_role(role_params) do
+ {:ok, role} ->
+ notify_parent({:saved, role})
+
+ {:noreply,
+ socket
+ |> put_flash(:info, "Role created successfully")
+ |> push_patch(to: socket.assigns.patch)}
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ {:noreply, assign_form(socket, changeset)}
+ end
+ end
+
+ defp assign_form(socket, %Ecto.Changeset{} = changeset) do
+ assign(socket, :form, to_form(changeset))
+ end
+
+ defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
+end
diff --git a/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/index.ex b/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/index.ex
new file mode 100644
index 0000000..2fb8358
--- /dev/null
+++ b/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/index.ex
@@ -0,0 +1,37 @@
+defmodule LoLAnalyticsWeb.RoleLive.Index do
+ use LoLAnalyticsWeb, :live_view
+
+ alias LoLAnalytics.Accounts
+ alias LoLAnalytics.Accounts.Role
+
+ @roles ["ALL", "TOP", "MIDDLE", "JUNGLE", "UTILITY", "BOTTOM"]
+
+ @impl true
+ def mount(_params, _session, socket) do
+ {:ok, stream(socket, :roles, @roles)}
+ end
+
+ @impl true
+ def handle_params(params, _url, socket) do
+ {:noreply, apply_action(socket, socket.assigns.live_action, params)}
+ end
+
+ defp apply_action(socket, :index, _params) do
+ socket
+ |> assign(:page_title, "Listing Roles")
+ |> assign(:role, nil)
+ end
+
+ @impl true
+ def handle_info({LoLAnalyticsWeb.RoleLive.FormComponent, {:saved, role}}, socket) do
+ {:noreply, stream_insert(socket, :roles, role)}
+ end
+
+ # @impl true
+ # def handle_event("delete", %{"id" => id}, socket) do
+ # role = Accounts.get_role!(id)
+ # {:ok, _} = Accounts.delete_role(role)
+
+ # {:noreply, stream_delete(socket, :roles, role)}
+ # end
+end
diff --git a/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/index.html.heex b/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/index.html.heex
new file mode 100644
index 0000000..f7a4bdc
--- /dev/null
+++ b/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/index.html.heex
@@ -0,0 +1,40 @@
+<.header>
+ Listing Roles
+ <:actions>
+ <.link patch={~p"/roles/new"}>
+ <.button>New Role
+
+
+
+
+<.table
+ id="roles"
+ rows={@streams.roles}
+ row_click={fn {_id, role} -> JS.navigate(~p"/roles/#{role}") end}
+>
+ <:action :let={{_id, role}}>
+
+ <.link navigate={~p"/roles/#{role}"}>Show
+
+ <.link patch={~p"/roles/#{role}/edit"}>Edit
+
+ <:action :let={{id, role}}>
+ <.link
+ phx-click={JS.push("delete", value: %{id: role.id}) |> hide("##{id}")}
+ data-confirm="Are you sure?"
+ >
+ Delete
+
+
+
+
+<.modal :if={@live_action in [:new, :edit]} id="role-modal" show on_cancel={JS.patch(~p"/roles")}>
+ <.live_component
+ module={LoLAnalyticsWeb.RoleLive.FormComponent}
+ id={@role.id || :new}
+ title={@page_title}
+ action={@live_action}
+ role={@role}
+ patch={~p"/roles"}
+ />
+
diff --git a/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/show.ex b/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/show.ex
new file mode 100644
index 0000000..bf3fbb9
--- /dev/null
+++ b/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/show.ex
@@ -0,0 +1,21 @@
+defmodule LoLAnalyticsWeb.RoleLive.Show do
+ use LoLAnalyticsWeb, :live_view
+
+ alias LoLAnalytics.Accounts
+
+ @impl true
+ def mount(_params, _session, socket) do
+ {:ok, socket}
+ end
+
+ @impl true
+ def handle_params(%{"id" => id}, _, socket) do
+ {:noreply,
+ socket
+ |> assign(:page_title, page_title(socket.assigns.live_action))
+ |> assign(:role, Accounts.get_role!(id))}
+ end
+
+ defp page_title(:show), do: "Show Role"
+ defp page_title(:edit), do: "Edit Role"
+end
diff --git a/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/show.html.heex b/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/show.html.heex
new file mode 100644
index 0000000..b556238
--- /dev/null
+++ b/apps/lol_analytics_web/lib/lol_analytics_web/live/role_live/show.html.heex
@@ -0,0 +1,25 @@
+<.header>
+ Role <%= @role.id %>
+ <:subtitle>This is a role record from your database.
+ <:actions>
+ <.link patch={~p"/roles/#{@role}/show/edit"} phx-click={JS.push_focus()}>
+ <.button>Edit role
+
+
+
+
+<.list>
+
+
+<.back navigate={~p"/roles"}>Back to roles
+
+<.modal :if={@live_action == :edit} id="role-modal" show on_cancel={JS.patch(~p"/roles/#{@role}")}>
+ <.live_component
+ module={LoLAnalyticsWeb.RoleLive.FormComponent}
+ id={@role.id}
+ title={@page_title}
+ action={@live_action}
+ role={@role}
+ patch={~p"/roles/#{@role}"}
+ />
+
diff --git a/apps/lol_analytics_web/lib/lol_analytics_web/router.ex b/apps/lol_analytics_web/lib/lol_analytics_web/router.ex
index 75f3756..2f99a7f 100644
--- a/apps/lol_analytics_web/lib/lol_analytics_web/router.ex
+++ b/apps/lol_analytics_web/lib/lol_analytics_web/router.ex
@@ -18,6 +18,12 @@ defmodule LoLAnalyticsWeb.Router do
pipe_through :browser
get "/", PageController, :home
+ live "/champions", ChampionLive.Index, :index
+ live "/champions/new", ChampionLive.Index, :new
+ live "/champions/:id/edit", ChampionLive.Index, :edit
+
+ live "/champions/:id", ChampionLive.Show, :show
+ live "/champions/:id/show/edit", ChampionLive.Show, :edit
end
# Other scopes may use custom stacks.
diff --git a/apps/lol_analytics_web/test/lol_analytics_web/live/champion_live_test.exs b/apps/lol_analytics_web/test/lol_analytics_web/live/champion_live_test.exs
new file mode 100644
index 0000000..85ce5f0
--- /dev/null
+++ b/apps/lol_analytics_web/test/lol_analytics_web/live/champion_live_test.exs
@@ -0,0 +1,108 @@
+defmodule LoLAnalyticsWeb.ChampionLiveTest do
+ use LoLAnalyticsWeb.ConnCase
+
+ import Phoenix.LiveViewTest
+ import LoLAnalytics.AccountsFixtures
+
+ @create_attrs %{}
+ @update_attrs %{}
+ @invalid_attrs %{}
+
+ defp create_champion(_) do
+ champion = champion_fixture()
+ %{champion: champion}
+ end
+
+ describe "Index" do
+ setup [:create_champion]
+
+ test "lists all champions", %{conn: conn} do
+ {:ok, _index_live, html} = live(conn, ~p"/champions")
+
+ assert html =~ "Listing Champions"
+ end
+
+ test "saves new champion", %{conn: conn} do
+ {:ok, index_live, _html} = live(conn, ~p"/champions")
+
+ assert index_live |> element("a", "New Champion") |> render_click() =~
+ "New Champion"
+
+ assert_patch(index_live, ~p"/champions/new")
+
+ assert index_live
+ |> form("#champion-form", champion: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ assert index_live
+ |> form("#champion-form", champion: @create_attrs)
+ |> render_submit()
+
+ assert_patch(index_live, ~p"/champions")
+
+ html = render(index_live)
+ assert html =~ "Champion created successfully"
+ end
+
+ test "updates champion in listing", %{conn: conn, champion: champion} do
+ {:ok, index_live, _html} = live(conn, ~p"/champions")
+
+ assert index_live |> element("#champions-#{champion.id} a", "Edit") |> render_click() =~
+ "Edit Champion"
+
+ assert_patch(index_live, ~p"/champions/#{champion}/edit")
+
+ assert index_live
+ |> form("#champion-form", champion: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ assert index_live
+ |> form("#champion-form", champion: @update_attrs)
+ |> render_submit()
+
+ assert_patch(index_live, ~p"/champions")
+
+ html = render(index_live)
+ assert html =~ "Champion updated successfully"
+ end
+
+ test "deletes champion in listing", %{conn: conn, champion: champion} do
+ {:ok, index_live, _html} = live(conn, ~p"/champions")
+
+ assert index_live |> element("#champions-#{champion.id} a", "Delete") |> render_click()
+ refute has_element?(index_live, "#champions-#{champion.id}")
+ end
+ end
+
+ describe "Show" do
+ setup [:create_champion]
+
+ test "displays champion", %{conn: conn, champion: champion} do
+ {:ok, _show_live, html} = live(conn, ~p"/champions/#{champion}")
+
+ assert html =~ "Show Champion"
+ end
+
+ test "updates champion within modal", %{conn: conn, champion: champion} do
+ {:ok, show_live, _html} = live(conn, ~p"/champions/#{champion}")
+
+ assert show_live |> element("a", "Edit") |> render_click() =~
+ "Edit Champion"
+
+ assert_patch(show_live, ~p"/champions/#{champion}/show/edit")
+
+ assert show_live
+ |> form("#champion-form", champion: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ assert show_live
+ |> form("#champion-form", champion: @update_attrs)
+ |> render_submit()
+
+ assert_patch(show_live, ~p"/champions/#{champion}")
+
+ html = render(show_live)
+ assert html =~ "Champion updated successfully"
+ end
+ end
+end
diff --git a/apps/lol_analytics_web/test/lol_analytics_web/live/role_live_test.exs b/apps/lol_analytics_web/test/lol_analytics_web/live/role_live_test.exs
new file mode 100644
index 0000000..2070ac7
--- /dev/null
+++ b/apps/lol_analytics_web/test/lol_analytics_web/live/role_live_test.exs
@@ -0,0 +1,108 @@
+defmodule LoLAnalyticsWeb.RoleLiveTest do
+ use LoLAnalyticsWeb.ConnCase
+
+ import Phoenix.LiveViewTest
+ import LoLAnalytics.AccountsFixtures
+
+ @create_attrs %{}
+ @update_attrs %{}
+ @invalid_attrs %{}
+
+ defp create_role(_) do
+ role = role_fixture()
+ %{role: role}
+ end
+
+ describe "Index" do
+ setup [:create_role]
+
+ test "lists all roles", %{conn: conn} do
+ {:ok, _index_live, html} = live(conn, ~p"/roles")
+
+ assert html =~ "Listing Roles"
+ end
+
+ test "saves new role", %{conn: conn} do
+ {:ok, index_live, _html} = live(conn, ~p"/roles")
+
+ assert index_live |> element("a", "New Role") |> render_click() =~
+ "New Role"
+
+ assert_patch(index_live, ~p"/roles/new")
+
+ assert index_live
+ |> form("#role-form", role: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ assert index_live
+ |> form("#role-form", role: @create_attrs)
+ |> render_submit()
+
+ assert_patch(index_live, ~p"/roles")
+
+ html = render(index_live)
+ assert html =~ "Role created successfully"
+ end
+
+ test "updates role in listing", %{conn: conn, role: role} do
+ {:ok, index_live, _html} = live(conn, ~p"/roles")
+
+ assert index_live |> element("#roles-#{role.id} a", "Edit") |> render_click() =~
+ "Edit Role"
+
+ assert_patch(index_live, ~p"/roles/#{role}/edit")
+
+ assert index_live
+ |> form("#role-form", role: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ assert index_live
+ |> form("#role-form", role: @update_attrs)
+ |> render_submit()
+
+ assert_patch(index_live, ~p"/roles")
+
+ html = render(index_live)
+ assert html =~ "Role updated successfully"
+ end
+
+ test "deletes role in listing", %{conn: conn, role: role} do
+ {:ok, index_live, _html} = live(conn, ~p"/roles")
+
+ assert index_live |> element("#roles-#{role.id} a", "Delete") |> render_click()
+ refute has_element?(index_live, "#roles-#{role.id}")
+ end
+ end
+
+ describe "Show" do
+ setup [:create_role]
+
+ test "displays role", %{conn: conn, role: role} do
+ {:ok, _show_live, html} = live(conn, ~p"/roles/#{role}")
+
+ assert html =~ "Show Role"
+ end
+
+ test "updates role within modal", %{conn: conn, role: role} do
+ {:ok, show_live, _html} = live(conn, ~p"/roles/#{role}")
+
+ assert show_live |> element("a", "Edit") |> render_click() =~
+ "Edit Role"
+
+ assert_patch(show_live, ~p"/roles/#{role}/show/edit")
+
+ assert show_live
+ |> form("#role-form", role: @invalid_attrs)
+ |> render_change() =~ "can't be blank"
+
+ assert show_live
+ |> form("#role-form", role: @update_attrs)
+ |> render_submit()
+
+ assert_patch(show_live, ~p"/roles/#{role}")
+
+ html = render(show_live)
+ assert html =~ "Role updated successfully"
+ end
+ end
+end
diff --git a/queries.md b/queries.md
index 4652a32..ebb0775 100644
--- a/queries.md
+++ b/queries.md
@@ -7,4 +7,16 @@ SELECT
FROM fact_champion_played_game
GROUP BY champion_id
ORDER BY win_rate desc;
+```
+
+```
+SELECT
+ (cast(count(CASE WHEN is_win THEN 1 END) as float) / cast(count(*) as float)) * 100.0 as win_rate,
+ count(CASE WHEN is_win THEN 1 END) as games_won,
+ count(*) as total_games,
+ champion_id,
+ team_position
+ FROM fact_champion_played_game
+ GROUP BY champion_id, team_position
+ ORDER BY win_rate desc;
```
\ No newline at end of file