remove all n+1 queries for real this time
This commit is contained in:
		| @@ -843,12 +843,39 @@ defmodule Cannery.Ammo do | ||||
|  | ||||
|   """ | ||||
|   @spec get_percentage_remaining(AmmoGroup.t(), User.t()) :: non_neg_integer() | ||||
|   def get_percentage_remaining(%AmmoGroup{count: 0, user_id: user_id}, %User{id: user_id}) do | ||||
|     0 | ||||
|   def get_percentage_remaining(%AmmoGroup{id: ammo_group_id} = ammo_group, user) do | ||||
|     [ammo_group] | ||||
|     |> get_percentages_remaining(user) | ||||
|     |> Map.fetch!(ammo_group_id) | ||||
|   end | ||||
|  | ||||
|   def get_percentage_remaining(%AmmoGroup{count: count} = ammo_group, current_user) do | ||||
|     round(count / get_original_count(ammo_group, current_user) * 100) | ||||
|   @doc """ | ||||
|   Calculates the percentages remaining of multiple ammo groups out of 100 | ||||
|  | ||||
|   ## Examples | ||||
|  | ||||
|       iex> get_percentages_remaining( | ||||
|       ...>   [%AmmoGroup{id: 123, count: 5, user_id: 456}], | ||||
|       ...>   %User{id: 456} | ||||
|       ...> ) | ||||
|       %{123 => 100} | ||||
|  | ||||
|   """ | ||||
|   @spec get_percentages_remaining([AmmoGroup.t()], User.t()) :: | ||||
|           %{optional(AmmoGroup.id()) => non_neg_integer()} | ||||
|   def get_percentages_remaining(ammo_groups, %User{id: user_id} = user) do | ||||
|     original_counts = get_original_counts(ammo_groups, user) | ||||
|  | ||||
|     ammo_groups | ||||
|     |> Map.new(fn %AmmoGroup{id: ammo_group_id, count: count, user_id: ^user_id} -> | ||||
|       percentage = | ||||
|         case count do | ||||
|           0 -> 0 | ||||
|           count -> round(count / Map.fetch!(original_counts, ammo_group_id) * 100) | ||||
|         end | ||||
|  | ||||
|       {ammo_group_id, percentage} | ||||
|     end) | ||||
|   end | ||||
|  | ||||
|   @doc """ | ||||
|   | ||||
| @@ -92,7 +92,7 @@ defmodule Cannery.Containers do | ||||
|   @doc """ | ||||
|   Gets a single container. | ||||
|  | ||||
|   Raises `Ecto.NoResultsError` if the Container does not exist. | ||||
|   Raises `KeyError` if the Container does not exist. | ||||
|  | ||||
|   ## Examples | ||||
|  | ||||
| @@ -100,18 +100,37 @@ defmodule Cannery.Containers do | ||||
|       %Container{} | ||||
|  | ||||
|       iex> get_container!(456, %User{id: 123}) | ||||
|       ** (Ecto.NoResultsError) | ||||
|       ** (KeyError) | ||||
|  | ||||
|   """ | ||||
|   @spec get_container!(Container.id(), User.t()) :: Container.t() | ||||
|   def get_container!(id, %User{id: user_id}) do | ||||
|     Repo.one!( | ||||
|   def get_container!(id, user) do | ||||
|     [id] | ||||
|     |> get_containers(user) | ||||
|     |> Map.fetch!(id) | ||||
|   end | ||||
|  | ||||
|   @doc """ | ||||
|   Gets multiple containers. | ||||
|  | ||||
|  | ||||
|   ## Examples | ||||
|  | ||||
|       iex> get_containers([123], %User{id: 123}) | ||||
|       %{123 => %Container{}} | ||||
|  | ||||
|   """ | ||||
|   @spec get_containers([Container.id()], User.t()) :: %{optional(Container.id()) => Container.t()} | ||||
|   def get_containers(ids, %User{id: user_id}) do | ||||
|     Repo.all( | ||||
|       from c in Container, | ||||
|         where: c.user_id == ^user_id, | ||||
|         where: c.id == ^id, | ||||
|         where: c.id in ^ids, | ||||
|         order_by: c.name, | ||||
|         preload: ^@container_preloads | ||||
|         preload: ^@container_preloads, | ||||
|         select: {c.id, c} | ||||
|     ) | ||||
|     |> Map.new() | ||||
|   end | ||||
|  | ||||
|   @doc """ | ||||
|   | ||||
| @@ -108,14 +108,21 @@ defmodule CanneryWeb.Components.AmmoGroupTableComponent do | ||||
|         [%{label: gettext("Ammo type"), key: :ammo_type} | columns] | ||||
|       end | ||||
|  | ||||
|     containers = | ||||
|       ammo_groups | ||||
|       |> Enum.map(fn %{container_id: container_id} -> container_id end) | ||||
|       |> Containers.get_containers(current_user) | ||||
|  | ||||
|     extra_data = %{ | ||||
|       current_user: current_user, | ||||
|       ammo_type: ammo_type, | ||||
|       columns: columns, | ||||
|       container: container, | ||||
|       containers: containers, | ||||
|       original_counts: Ammo.get_original_counts(ammo_groups, current_user), | ||||
|       cprs: Ammo.get_cprs(ammo_groups, current_user), | ||||
|       last_used_dates: ActivityLog.get_last_used_dates(ammo_groups, current_user), | ||||
|       percentages_remaining: Ammo.get_percentages_remaining(ammo_groups, current_user), | ||||
|       actions: actions, | ||||
|       range: range | ||||
|     } | ||||
| @@ -202,8 +209,12 @@ defmodule CanneryWeb.Components.AmmoGroupTableComponent do | ||||
|      """} | ||||
|   end | ||||
|  | ||||
|   defp get_value_for_key(:remaining, ammo_group, %{current_user: current_user}) do | ||||
|     percentage = ammo_group |> Ammo.get_percentage_remaining(current_user) | ||||
|   defp get_value_for_key( | ||||
|          :remaining, | ||||
|          %{id: ammo_group_id}, | ||||
|          %{percentages_remaining: percentages_remaining} | ||||
|        ) do | ||||
|     percentage = Map.fetch!(percentages_remaining, ammo_group_id) | ||||
|     {percentage, gettext("%{percentage}%", percentage: percentage)} | ||||
|   end | ||||
|  | ||||
| @@ -220,12 +231,13 @@ defmodule CanneryWeb.Components.AmmoGroupTableComponent do | ||||
|   defp get_value_for_key( | ||||
|          :container, | ||||
|          %{container_id: container_id} = ammo_group, | ||||
|          %{container: container, current_user: current_user} | ||||
|          %{container: container_block, containers: containers} | ||||
|        ) do | ||||
|     container = %{name: container_name} = Map.fetch!(containers, container_id) | ||||
|  | ||||
|     assigns = %{ | ||||
|       container: | ||||
|         %{name: container_name} = container_id |> Containers.get_container!(current_user), | ||||
|       container_block: container, | ||||
|       container: container, | ||||
|       container_block: container_block, | ||||
|       ammo_group: ammo_group | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -6,7 +6,7 @@ defmodule CanneryWeb.CoreComponents do | ||||
|   import CanneryWeb.{Gettext, ViewHelpers} | ||||
|   alias Cannery.{Accounts, Accounts.Invite, Accounts.User} | ||||
|   alias Cannery.{Ammo, Ammo.AmmoGroup} | ||||
|   alias Cannery.{Containers, Containers.Container, Containers.Tag} | ||||
|   alias Cannery.{Containers.Container, Containers.Tag} | ||||
|   alias CanneryWeb.{Endpoint, HomeLive} | ||||
|   alias CanneryWeb.Router.Helpers, as: Routes | ||||
|   alias Phoenix.LiveView.{JS, Rendered} | ||||
| @@ -91,7 +91,7 @@ defmodule CanneryWeb.CoreComponents do | ||||
|   attr :original_count, :integer, default: nil | ||||
|   attr :cpr, :integer, default: nil | ||||
|   attr :last_used_date, Date, default: nil | ||||
|   attr :show_container, :boolean, default: false | ||||
|   attr :container, Container, default: nil | ||||
|   slot(:inner_block) | ||||
|  | ||||
|   def ammo_group_card(assigns) | ||||
|   | ||||
| @@ -50,17 +50,11 @@ | ||||
|       <%= gettext("$%{amount}", amount: display_currency(@cpr)) %> | ||||
|     </span> | ||||
|  | ||||
|     <span | ||||
|       :if={@show_container && Containers.get_container!(@ammo_group.container_id, @current_user)} | ||||
|       class="rounded-lg title text-lg" | ||||
|     > | ||||
|     <span :if={@container} class="rounded-lg title text-lg"> | ||||
|       <%= gettext("Container:") %> | ||||
|  | ||||
|       <.link | ||||
|         navigate={Routes.container_show_path(Endpoint, :show, @ammo_group.container_id)} | ||||
|         class="link" | ||||
|       > | ||||
|         <%= Containers.get_container!(@ammo_group.container_id, @current_user).name %> | ||||
|       <.link navigate={Routes.container_show_path(Endpoint, :show, @container)} class="link"> | ||||
|         <%= @container.name %> | ||||
|       </.link> | ||||
|     </span> | ||||
|   </div> | ||||
|   | ||||
| @@ -32,18 +32,17 @@ defmodule CanneryWeb.ExportController do | ||||
|     used_counts = ammo_groups |> ActivityLog.get_used_counts(current_user) | ||||
|     original_counts = ammo_groups |> Ammo.get_original_counts(current_user) | ||||
|     cprs = ammo_groups |> Ammo.get_cprs(current_user) | ||||
|     percentages_remaining = ammo_groups |> Ammo.get_percentages_remaining(current_user) | ||||
|  | ||||
|     ammo_groups = | ||||
|       ammo_groups | ||||
|       |> Enum.map(fn %{id: ammo_group_id} = ammo_group -> | ||||
|         percentage_remaining = ammo_group |> Ammo.get_percentage_remaining(current_user) | ||||
|  | ||||
|         ammo_group | ||||
|         |> Jason.encode!() | ||||
|         |> Jason.decode!() | ||||
|         |> Map.merge(%{ | ||||
|           "used_count" => Map.get(used_counts, ammo_group_id), | ||||
|           "percentage_remaining" => percentage_remaining, | ||||
|           "percentage_remaining" => Map.fetch!(percentages_remaining, ammo_group_id), | ||||
|           "original_count" => Map.get(original_counts, ammo_group_id), | ||||
|           "cpr" => Map.get(cprs, ammo_group_id) | ||||
|         }) | ||||
|   | ||||
| @@ -4,7 +4,7 @@ defmodule CanneryWeb.AmmoTypeLive.Show do | ||||
|   """ | ||||
|  | ||||
|   use CanneryWeb, :live_view | ||||
|   alias Cannery.{ActivityLog, Ammo, Ammo.AmmoType} | ||||
|   alias Cannery.{ActivityLog, Ammo, Ammo.AmmoType, Containers} | ||||
|   alias CanneryWeb.Endpoint | ||||
|  | ||||
|   @fields_list [ | ||||
| @@ -104,11 +104,17 @@ defmodule CanneryWeb.AmmoTypeLive.Show do | ||||
|         :edit -> gettext("Edit %{ammo_type_name}", ammo_type_name: ammo_type_name) | ||||
|       end | ||||
|  | ||||
|     containers = | ||||
|       ammo_groups | ||||
|       |> Enum.map(fn %{container_id: container_id} -> container_id end) | ||||
|       |> Containers.get_containers(current_user) | ||||
|  | ||||
|     socket | ||||
|     |> assign( | ||||
|       page_title: page_title, | ||||
|       ammo_type: ammo_type, | ||||
|       ammo_groups: ammo_groups, | ||||
|       containers: containers, | ||||
|       cprs: ammo_groups |> Ammo.get_cprs(current_user), | ||||
|       last_used_dates: ammo_groups |> ActivityLog.get_last_used_dates(current_user), | ||||
|       avg_cost_per_round: ammo_type |> Ammo.get_average_cost_for_ammo_type(current_user), | ||||
|   | ||||
| @@ -184,13 +184,13 @@ | ||||
|       <% else %> | ||||
|         <div class="flex flex-wrap justify-center items-stretch"> | ||||
|           <.ammo_group_card | ||||
|             :for={%{id: ammo_group_id} = ammo_group <- @ammo_groups} | ||||
|             :for={%{id: ammo_group_id, container_id: container_id} = ammo_group <- @ammo_groups} | ||||
|             ammo_group={ammo_group} | ||||
|             original_count={@original_counts && Map.fetch!(@original_counts, ammo_group_id)} | ||||
|             cpr={Map.get(@cprs, ammo_group_id)} | ||||
|             last_used_date={Map.get(@last_used_dates, ammo_group_id)} | ||||
|             current_user={@current_user} | ||||
|             show_container={true} | ||||
|             container={Map.fetch!(@containers, container_id)} | ||||
|           /> | ||||
|         </div> | ||||
|       <% end %> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user