forked from shibao/cannery
		
	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