From e713a2e108efab0d45a2eb24a07c8d2ca15fabef Mon Sep 17 00:00:00 2001 From: shibao Date: Mon, 5 Jun 2023 19:03:13 -0400 Subject: [PATCH] improve ActivityLog.get_used_count --- lib/cannery/activity_log.ex | 54 ++++++++++++------- lib/cannery_web/live/type_live/show.ex | 2 +- test/cannery/activity_log_test.exs | 22 ++++---- .../controllers/export_controller_test.exs | 4 +- 4 files changed, 50 insertions(+), 32 deletions(-) diff --git a/lib/cannery/activity_log.ex b/lib/cannery/activity_log.ex index 4fbc2f6..371dc6b 100644 --- a/lib/cannery/activity_log.ex +++ b/lib/cannery/activity_log.ex @@ -287,16 +287,6 @@ defmodule Cannery.ActivityLog do end end - @doc """ - Returns the number of shot rounds for a pack - """ - @spec get_used_count(Pack.t(), User.t()) :: non_neg_integer() - def get_used_count(%Pack{id: pack_id} = pack, user) do - [pack] - |> get_used_counts(user) - |> Map.get(pack_id, 0) - end - @doc """ Returns the number of shot rounds for multiple packs """ @@ -346,6 +336,9 @@ defmodule Cannery.ActivityLog do |> Map.new() end + @type get_used_count_option :: {:pack_id, Pack.id() | nil} | {:type_id, Type.id() | nil} + @type get_used_count_options :: [get_used_count_option()] + @doc """ Gets the total number of rounds shot for a type @@ -353,20 +346,45 @@ defmodule Cannery.ActivityLog do ## Examples - iex> get_used_count_for_type(123, %User{id: 123}) + iex> get_used_count(%User{id: 123}, type_id: 123) 35 - iex> get_used_count_for_type(456, %User{id: 123}) - ** (Ecto.NoResultsError) + iex> get_used_count(%User{id: 123}, pack_id: 456) + 50 """ - @spec get_used_count_for_type(Type.t(), User.t()) :: non_neg_integer() - def get_used_count_for_type(%Type{id: type_id} = type, user) do - [type] - |> get_used_count_for_types(user) - |> Map.get(type_id, 0) + @spec get_used_count(User.t(), get_used_count_options()) :: non_neg_integer() + def get_used_count(%User{id: user_id}, opts) do + from(sr in ShotRecord, + as: :sr, + left_join: p in Pack, + on: sr.pack_id == p.id, + on: p.user_id == ^user_id, + as: :p, + where: sr.user_id == ^user_id, + where: not (sr.count |> is_nil()), + select: sum(sr.count), + distinct: true + ) + |> get_used_count_type_id(Keyword.get(opts, :type_id)) + |> get_used_count_pack_id(Keyword.get(opts, :pack_id)) + |> Repo.one() || 0 end + @spec get_used_count_pack_id(Queryable.t(), Pack.id() | nil) :: Queryable.t() + defp get_used_count_pack_id(query, pack_id) when pack_id |> is_binary() do + query |> where([sr: sr], sr.pack_id == ^pack_id) + end + + defp get_used_count_pack_id(query, _nil), do: query + + @spec get_used_count_type_id(Queryable.t(), Type.id() | nil) :: Queryable.t() + defp get_used_count_type_id(query, type_id) when type_id |> is_binary() do + query |> where([p: p], p.type_id == ^type_id) + end + + defp get_used_count_type_id(query, _nil), do: query + @doc """ Gets the total number of rounds shot for multiple types diff --git a/lib/cannery_web/live/type_live/show.ex b/lib/cannery_web/live/type_live/show.ex index ab5199e..4b2c287 100644 --- a/lib/cannery_web/live/type_live/show.ex +++ b/lib/cannery_web/live/type_live/show.ex @@ -68,7 +68,7 @@ defmodule CanneryWeb.TypeLive.Show do packs |> Ammo.get_original_counts(current_user), Ammo.get_packs_count(current_user, type_id: type.id, show_used: :only_used), Ammo.get_packs_count(current_user, type_id: type.id, show_used: true), - type |> ActivityLog.get_used_count_for_type(current_user), + ActivityLog.get_used_count(current_user, type_id: type.id), type |> Ammo.get_historical_count_for_type(current_user) ] else diff --git a/test/cannery/activity_log_test.exs b/test/cannery/activity_log_test.exs index 7bc96cc..fee726c 100644 --- a/test/cannery/activity_log_test.exs +++ b/test/cannery/activity_log_test.exs @@ -188,24 +188,24 @@ defmodule Cannery.ActivityLogTest do end end - test "get_used_count/2 returns accurate used count", %{ + test "get_used_count/2 returns accurate used count for pack_id", %{ pack: pack, type: type, container: container, current_user: current_user } do {1, [another_pack]} = pack_fixture(type, container, current_user) - assert 0 = another_pack |> ActivityLog.get_used_count(current_user) - assert 5 = pack |> ActivityLog.get_used_count(current_user) + assert 0 = ActivityLog.get_used_count(current_user, pack_id: another_pack.id) + assert 5 = ActivityLog.get_used_count(current_user, pack_id: pack.id) shot_record_fixture(%{count: 15}, current_user, pack) - assert 20 = pack |> ActivityLog.get_used_count(current_user) + assert 20 = ActivityLog.get_used_count(current_user, pack_id: pack.id) shot_record_fixture(%{count: 10}, current_user, pack) - assert 30 = pack |> ActivityLog.get_used_count(current_user) + assert 30 = ActivityLog.get_used_count(current_user, pack_id: pack.id) {1, [another_pack]} = pack_fixture(type, container, current_user) - assert 0 = another_pack |> ActivityLog.get_used_count(current_user) + assert 0 = ActivityLog.get_used_count(current_user, pack_id: another_pack.id) end test "get_used_counts/2 returns accurate used counts", %{ @@ -294,17 +294,17 @@ defmodule Cannery.ActivityLogTest do assert %{^another_pack_id => ~D[2022-11-09]} = last_used_shot_records end - test "get_used_count_for_type/2 gets accurate used round count for type", + test "get_used_count/2 gets accurate used round count for type_id", %{type: type, pack: pack, current_user: current_user} do another_type = type_fixture(current_user) - assert 0 = another_type |> ActivityLog.get_used_count_for_type(current_user) - assert 5 = type |> ActivityLog.get_used_count_for_type(current_user) + assert 0 = ActivityLog.get_used_count(current_user, type_id: another_type.id) + assert 5 = ActivityLog.get_used_count(current_user, type_id: type.id) shot_record_fixture(%{count: 5}, current_user, pack) - assert 10 = type |> ActivityLog.get_used_count_for_type(current_user) + assert 10 = ActivityLog.get_used_count(current_user, type_id: type.id) shot_record_fixture(%{count: 1}, current_user, pack) - assert 11 = type |> ActivityLog.get_used_count_for_type(current_user) + assert 11 = ActivityLog.get_used_count(current_user, type_id: type.id) end test "get_used_count_for_types/2 gets accurate used round count for types", %{ diff --git a/test/cannery_web/controllers/export_controller_test.exs b/test/cannery_web/controllers/export_controller_test.exs index de89320..b65a0d3 100644 --- a/test/cannery_web/controllers/export_controller_test.exs +++ b/test/cannery_web/controllers/export_controller_test.exs @@ -51,7 +51,7 @@ defmodule CanneryWeb.ExportControllerTest do "price_paid" => pack.price_paid, "lot_number" => pack.lot_number, "staged" => pack.staged, - "used_count" => pack |> ActivityLog.get_used_count(current_user), + "used_count" => ActivityLog.get_used_count(current_user, pack_id: pack.id), "original_count" => pack |> Ammo.get_original_count(current_user), "cpr" => pack |> Ammo.get_cpr(current_user), "percentage_remaining" => pack |> Ammo.get_percentage_remaining(current_user) @@ -92,7 +92,7 @@ defmodule CanneryWeb.ExportControllerTest do "dram_equivalent" => type.dram_equivalent, "average_cost" => type |> Ammo.get_average_cost_for_type(current_user), "round_count" => type |> Ammo.get_round_count_for_type(current_user), - "used_count" => type |> ActivityLog.get_used_count_for_type(current_user), + "used_count" => ActivityLog.get_used_count(current_user, type_id: type.id), "pack_count" => Ammo.get_packs_count(current_user, type_id: type.id), "total_pack_count" => Ammo.get_packs_count(current_user, type_id: type.id, show_used: true)