forked from shibao/cannery
improve ActivityLog.get_grouped_used_counts
This commit is contained in:
parent
e713a2e108
commit
8466fcd1f9
@ -287,26 +287,6 @@ defmodule Cannery.ActivityLog do
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the number of shot rounds for multiple packs
|
||||
"""
|
||||
@spec get_used_counts([Pack.t()], User.t()) ::
|
||||
%{optional(Pack.id()) => non_neg_integer()}
|
||||
def get_used_counts(packs, %User{id: user_id}) do
|
||||
pack_ids =
|
||||
packs
|
||||
|> Enum.map(fn %{id: pack_id} -> pack_id end)
|
||||
|
||||
Repo.all(
|
||||
from sr in ShotRecord,
|
||||
where: sr.pack_id in ^pack_ids,
|
||||
where: sr.user_id == ^user_id,
|
||||
group_by: sr.pack_id,
|
||||
select: {sr.pack_id, sum(sr.count)}
|
||||
)
|
||||
|> Map.new()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the last entered shot record date for a pack
|
||||
"""
|
||||
@ -385,31 +365,77 @@ defmodule Cannery.ActivityLog do
|
||||
|
||||
defp get_used_count_type_id(query, _nil), do: query
|
||||
|
||||
@type get_grouped_used_counts_option ::
|
||||
{:packs, [Pack.t()] | nil}
|
||||
| {:types, [Type.t()] | nil}
|
||||
| {:group_by, :type_id | :pack_id}
|
||||
@type get_grouped_used_counts_options :: [get_grouped_used_counts_option()]
|
||||
|
||||
@doc """
|
||||
Gets the total number of rounds shot for multiple types
|
||||
Gets the total number of rounds shot for multiple types or packs
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_used_count_for_types(123, %User{id: 123})
|
||||
iex> get_grouped_used_counts(
|
||||
...> %User{id: 123},
|
||||
...> group_by: :type_id,
|
||||
...> types: [%Type{id: 456, user_id: 123}]
|
||||
...> )
|
||||
35
|
||||
|
||||
"""
|
||||
@spec get_used_count_for_types([Type.t()], User.t()) ::
|
||||
%{optional(Type.id()) => non_neg_integer()}
|
||||
def get_used_count_for_types(types, %User{id: user_id}) do
|
||||
type_ids =
|
||||
types
|
||||
|> Enum.map(fn %Type{id: type_id, user_id: ^user_id} -> type_id end)
|
||||
iex> get_grouped_used_counts(
|
||||
...> %User{id: 123},
|
||||
...> group_by: :pack_id,
|
||||
...> packs: [%Pack{id: 456, user_id: 123}]
|
||||
...> )
|
||||
22
|
||||
|
||||
Repo.all(
|
||||
from p in Pack,
|
||||
left_join: sr in ShotRecord,
|
||||
on: p.id == sr.pack_id,
|
||||
where: p.type_id in ^type_ids,
|
||||
where: not (sr.count |> is_nil()),
|
||||
group_by: p.type_id,
|
||||
select: {p.type_id, sum(sr.count)}
|
||||
"""
|
||||
@spec get_grouped_used_counts(User.t(), get_grouped_used_counts_options()) ::
|
||||
%{optional(Type.id() | Pack.id()) => non_neg_integer()}
|
||||
def get_grouped_used_counts(%User{id: user_id}, opts) do
|
||||
from(p in Pack,
|
||||
as: :p,
|
||||
left_join: sr in ShotRecord,
|
||||
on: p.id == sr.pack_id,
|
||||
on: p.user_id == ^user_id,
|
||||
as: :sr,
|
||||
where: sr.user_id == ^user_id,
|
||||
where: not (sr.count |> is_nil())
|
||||
)
|
||||
|> get_grouped_used_counts_group_by(Keyword.fetch!(opts, :group_by))
|
||||
|> get_grouped_used_counts_types(Keyword.get(opts, :types))
|
||||
|> get_grouped_used_counts_packs(Keyword.get(opts, :packs))
|
||||
|> Repo.all()
|
||||
|> Map.new()
|
||||
end
|
||||
|
||||
@spec get_grouped_used_counts_group_by(Queryable.t(), :type_id | :pack_id) :: Queryable.t()
|
||||
defp get_grouped_used_counts_group_by(query, :type_id) do
|
||||
query
|
||||
|> group_by([p: p], p.type_id)
|
||||
|> select([sr: sr, p: p], {p.type_id, sum(sr.count)})
|
||||
end
|
||||
|
||||
defp get_grouped_used_counts_group_by(query, :pack_id) do
|
||||
query
|
||||
|> group_by([sr: sr], sr.pack_id)
|
||||
|> select([sr: sr], {sr.pack_id, sum(sr.count)})
|
||||
end
|
||||
|
||||
@spec get_grouped_used_counts_types(Queryable.t(), [Type.t()] | nil) :: Queryable.t()
|
||||
defp get_grouped_used_counts_types(query, types) when types |> is_list() do
|
||||
type_ids = types |> Enum.map(fn %Type{id: type_id} -> type_id end)
|
||||
query |> where([p: p], p.type_id in ^type_ids)
|
||||
end
|
||||
|
||||
defp get_grouped_used_counts_types(query, _nil), do: query
|
||||
|
||||
@spec get_grouped_used_counts_packs(Queryable.t(), [Pack.t()] | nil) :: Queryable.t()
|
||||
defp get_grouped_used_counts_packs(query, packs) when packs |> is_list() do
|
||||
pack_ids = packs |> Enum.map(fn %Pack{id: pack_id} -> pack_id end)
|
||||
query |> where([p: p], p.id in ^pack_ids)
|
||||
end
|
||||
|
||||
defp get_grouped_used_counts_packs(query, _nil), do: query
|
||||
end
|
||||
|
@ -267,7 +267,7 @@ defmodule Cannery.Ammo do
|
||||
@spec get_historical_count_for_types([Type.t()], User.t()) ::
|
||||
%{optional(Type.id()) => non_neg_integer()}
|
||||
def get_historical_count_for_types(types, %User{id: user_id} = user) do
|
||||
used_counts = types |> ActivityLog.get_used_count_for_types(user)
|
||||
used_counts = ActivityLog.get_grouped_used_counts(user, types: types, group_by: :type_id)
|
||||
round_counts = types |> get_round_count_for_types(user)
|
||||
|
||||
types
|
||||
@ -840,7 +840,8 @@ defmodule Cannery.Ammo do
|
||||
@spec get_original_counts([Pack.t()], User.t()) ::
|
||||
%{optional(Pack.id()) => non_neg_integer()}
|
||||
def get_original_counts(packs, %User{id: user_id} = current_user) do
|
||||
used_counts = ActivityLog.get_used_counts(packs, current_user)
|
||||
used_counts =
|
||||
ActivityLog.get_grouped_used_counts(current_user, packs: packs, group_by: :pack_id)
|
||||
|
||||
packs
|
||||
|> Map.new(fn %Pack{id: pack_id, count: count, user_id: ^user_id} ->
|
||||
|
@ -158,7 +158,7 @@ defmodule CanneryWeb.Components.TypeTableComponent do
|
||||
[used_counts, historical_round_counts, historical_pack_counts, used_pack_counts] =
|
||||
if show_used do
|
||||
[
|
||||
types |> ActivityLog.get_used_count_for_types(current_user),
|
||||
ActivityLog.get_grouped_used_counts(current_user, types: types, group_by: :type_id),
|
||||
types |> Ammo.get_historical_count_for_types(current_user),
|
||||
Ammo.get_grouped_packs_count(current_user,
|
||||
types: types,
|
||||
|
@ -4,7 +4,10 @@ defmodule CanneryWeb.ExportController do
|
||||
|
||||
def export(%{assigns: %{current_user: current_user}} = conn, %{"mode" => "json"}) do
|
||||
types = Ammo.list_types(current_user)
|
||||
used_counts = types |> ActivityLog.get_used_count_for_types(current_user)
|
||||
|
||||
used_counts =
|
||||
ActivityLog.get_grouped_used_counts(current_user, types: types, group_by: :type_id)
|
||||
|
||||
round_counts = types |> Ammo.get_round_count_for_types(current_user)
|
||||
pack_counts = Ammo.get_grouped_packs_count(current_user, types: types, group_by: :type_id)
|
||||
|
||||
@ -29,7 +32,10 @@ defmodule CanneryWeb.ExportController do
|
||||
end)
|
||||
|
||||
packs = Ammo.list_packs(current_user, show_used: true)
|
||||
used_counts = packs |> ActivityLog.get_used_counts(current_user)
|
||||
|
||||
used_counts =
|
||||
ActivityLog.get_grouped_used_counts(current_user, packs: packs, group_by: :pack_id)
|
||||
|
||||
original_counts = packs |> Ammo.get_original_counts(current_user)
|
||||
cprs = packs |> Ammo.get_cprs(current_user)
|
||||
percentages_remaining = packs |> Ammo.get_percentages_remaining(current_user)
|
||||
|
@ -170,7 +170,7 @@ msgstr ""
|
||||
"Ungültige Nummer an Kopien. Muss zwischen 1 and %{max} liegen. War "
|
||||
"%{multiplier}"
|
||||
|
||||
#: lib/cannery/ammo.ex:979
|
||||
#: lib/cannery/ammo.ex:980
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Invalid multiplier"
|
||||
msgstr ""
|
||||
|
@ -153,7 +153,7 @@ msgstr ""
|
||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
|
||||
msgstr ""
|
||||
|
||||
#: lib/cannery/ammo.ex:979
|
||||
#: lib/cannery/ammo.ex:980
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Invalid multiplier"
|
||||
msgstr ""
|
||||
|
@ -152,7 +152,7 @@ msgstr ""
|
||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
|
||||
msgstr ""
|
||||
|
||||
#: lib/cannery/ammo.ex:979
|
||||
#: lib/cannery/ammo.ex:980
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Invalid multiplier"
|
||||
msgstr ""
|
||||
|
@ -168,7 +168,7 @@ msgstr "No se ha podido procesar el número de copias"
|
||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
|
||||
msgstr "Número inválido de copias, debe ser entre 1 y %{max}. Fue %{multiplier"
|
||||
|
||||
#: lib/cannery/ammo.ex:979
|
||||
#: lib/cannery/ammo.ex:980
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Invalid multiplier"
|
||||
msgstr "Multiplicador inválido"
|
||||
|
@ -169,7 +169,7 @@ msgstr "Impossible d'analyser le nombre de copies"
|
||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
|
||||
msgstr "Nombre de copies invalide, doit être 1 et %{max}. Été %{multiplier}"
|
||||
|
||||
#: lib/cannery/ammo.ex:979
|
||||
#: lib/cannery/ammo.ex:980
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Invalid multiplier"
|
||||
msgstr "Multiplicateur invalide"
|
||||
|
@ -168,7 +168,7 @@ msgstr ""
|
||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
|
||||
msgstr ""
|
||||
|
||||
#: lib/cannery/ammo.ex:979
|
||||
#: lib/cannery/ammo.ex:980
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Invalid multiplier"
|
||||
msgstr ""
|
||||
|
@ -208,7 +208,7 @@ defmodule Cannery.ActivityLogTest do
|
||||
assert 0 = ActivityLog.get_used_count(current_user, pack_id: another_pack.id)
|
||||
end
|
||||
|
||||
test "get_used_counts/2 returns accurate used counts", %{
|
||||
test "get_grouped_used_counts/2 returns accurate used counts for packs", %{
|
||||
pack: %{id: pack_id} = pack,
|
||||
type: type,
|
||||
container: container,
|
||||
@ -217,20 +217,41 @@ defmodule Cannery.ActivityLogTest do
|
||||
{1, [%{id: another_pack_id} = another_pack]} = pack_fixture(type, container, current_user)
|
||||
|
||||
assert %{pack_id => 5} ==
|
||||
[pack, another_pack] |> ActivityLog.get_used_counts(current_user)
|
||||
ActivityLog.get_grouped_used_counts(current_user,
|
||||
packs: [pack, another_pack],
|
||||
group_by: :pack_id
|
||||
)
|
||||
|
||||
shot_record_fixture(%{count: 5}, current_user, another_pack)
|
||||
used_counts = [pack, another_pack] |> ActivityLog.get_used_counts(current_user)
|
||||
|
||||
used_counts =
|
||||
ActivityLog.get_grouped_used_counts(current_user,
|
||||
packs: [pack, another_pack],
|
||||
group_by: :pack_id
|
||||
)
|
||||
|
||||
assert %{^pack_id => 5} = used_counts
|
||||
assert %{^another_pack_id => 5} = used_counts
|
||||
|
||||
shot_record_fixture(%{count: 15}, current_user, pack)
|
||||
used_counts = [pack, another_pack] |> ActivityLog.get_used_counts(current_user)
|
||||
|
||||
used_counts =
|
||||
ActivityLog.get_grouped_used_counts(current_user,
|
||||
packs: [pack, another_pack],
|
||||
group_by: :pack_id
|
||||
)
|
||||
|
||||
assert %{^pack_id => 20} = used_counts
|
||||
assert %{^another_pack_id => 5} = used_counts
|
||||
|
||||
shot_record_fixture(%{count: 10}, current_user, pack)
|
||||
used_counts = [pack, another_pack] |> ActivityLog.get_used_counts(current_user)
|
||||
|
||||
used_counts =
|
||||
ActivityLog.get_grouped_used_counts(current_user,
|
||||
packs: [pack, another_pack],
|
||||
group_by: :pack_id
|
||||
)
|
||||
|
||||
assert %{^pack_id => 30} = used_counts
|
||||
assert %{^another_pack_id => 5} = used_counts
|
||||
end
|
||||
@ -317,13 +338,19 @@ defmodule Cannery.ActivityLogTest do
|
||||
{1, [pack]} = pack_fixture(another_type, container, current_user)
|
||||
|
||||
assert %{type_id => 5} ==
|
||||
[type, another_type]
|
||||
|> ActivityLog.get_used_count_for_types(current_user)
|
||||
ActivityLog.get_grouped_used_counts(current_user,
|
||||
types: [type, another_type],
|
||||
group_by: :type_id
|
||||
)
|
||||
|
||||
# use generated pack
|
||||
shot_record_fixture(%{count: 5}, current_user, pack)
|
||||
|
||||
used_counts = [type, another_type] |> ActivityLog.get_used_count_for_types(current_user)
|
||||
used_counts =
|
||||
ActivityLog.get_grouped_used_counts(current_user,
|
||||
types: [type, another_type],
|
||||
group_by: :type_id
|
||||
)
|
||||
|
||||
assert %{^type_id => 5} = used_counts
|
||||
assert %{^another_type_id => 5} = used_counts
|
||||
@ -331,7 +358,11 @@ defmodule Cannery.ActivityLogTest do
|
||||
# use generated pack again
|
||||
shot_record_fixture(%{count: 1}, current_user, pack)
|
||||
|
||||
used_counts = [type, another_type] |> ActivityLog.get_used_count_for_types(current_user)
|
||||
used_counts =
|
||||
ActivityLog.get_grouped_used_counts(current_user,
|
||||
types: [type, another_type],
|
||||
group_by: :type_id
|
||||
)
|
||||
|
||||
assert %{^type_id => 5} = used_counts
|
||||
assert %{^another_type_id => 6} = used_counts
|
||||
|
Loading…
Reference in New Issue
Block a user