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
|
||||||
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 """
|
@doc """
|
||||||
Returns the last entered shot record date for a pack
|
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
|
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 """
|
@doc """
|
||||||
Gets the total number of rounds shot for multiple types
|
Gets the total number of rounds shot for multiple types or packs
|
||||||
|
|
||||||
## Examples
|
## 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
|
35
|
||||||
|
|
||||||
"""
|
iex> get_grouped_used_counts(
|
||||||
@spec get_used_count_for_types([Type.t()], User.t()) ::
|
...> %User{id: 123},
|
||||||
%{optional(Type.id()) => non_neg_integer()}
|
...> group_by: :pack_id,
|
||||||
def get_used_count_for_types(types, %User{id: user_id}) do
|
...> packs: [%Pack{id: 456, user_id: 123}]
|
||||||
type_ids =
|
...> )
|
||||||
types
|
22
|
||||||
|> Enum.map(fn %Type{id: type_id, user_id: ^user_id} -> type_id end)
|
|
||||||
|
|
||||||
Repo.all(
|
"""
|
||||||
from p in Pack,
|
@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,
|
left_join: sr in ShotRecord,
|
||||||
on: p.id == sr.pack_id,
|
on: p.id == sr.pack_id,
|
||||||
where: p.type_id in ^type_ids,
|
on: p.user_id == ^user_id,
|
||||||
where: not (sr.count |> is_nil()),
|
as: :sr,
|
||||||
group_by: p.type_id,
|
where: sr.user_id == ^user_id,
|
||||||
select: {p.type_id, sum(sr.count)}
|
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()
|
|> Map.new()
|
||||||
end
|
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
|
end
|
||||||
|
@ -267,7 +267,7 @@ defmodule Cannery.Ammo do
|
|||||||
@spec get_historical_count_for_types([Type.t()], User.t()) ::
|
@spec get_historical_count_for_types([Type.t()], User.t()) ::
|
||||||
%{optional(Type.id()) => non_neg_integer()}
|
%{optional(Type.id()) => non_neg_integer()}
|
||||||
def get_historical_count_for_types(types, %User{id: user_id} = user) do
|
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)
|
round_counts = types |> get_round_count_for_types(user)
|
||||||
|
|
||||||
types
|
types
|
||||||
@ -840,7 +840,8 @@ defmodule Cannery.Ammo do
|
|||||||
@spec get_original_counts([Pack.t()], User.t()) ::
|
@spec get_original_counts([Pack.t()], User.t()) ::
|
||||||
%{optional(Pack.id()) => non_neg_integer()}
|
%{optional(Pack.id()) => non_neg_integer()}
|
||||||
def get_original_counts(packs, %User{id: user_id} = current_user) do
|
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
|
packs
|
||||||
|> Map.new(fn %Pack{id: pack_id, count: count, user_id: ^user_id} ->
|
|> 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] =
|
[used_counts, historical_round_counts, historical_pack_counts, used_pack_counts] =
|
||||||
if show_used do
|
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),
|
types |> Ammo.get_historical_count_for_types(current_user),
|
||||||
Ammo.get_grouped_packs_count(current_user,
|
Ammo.get_grouped_packs_count(current_user,
|
||||||
types: types,
|
types: types,
|
||||||
|
@ -4,7 +4,10 @@ defmodule CanneryWeb.ExportController do
|
|||||||
|
|
||||||
def export(%{assigns: %{current_user: current_user}} = conn, %{"mode" => "json"}) do
|
def export(%{assigns: %{current_user: current_user}} = conn, %{"mode" => "json"}) do
|
||||||
types = Ammo.list_types(current_user)
|
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)
|
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)
|
pack_counts = Ammo.get_grouped_packs_count(current_user, types: types, group_by: :type_id)
|
||||||
|
|
||||||
@ -29,7 +32,10 @@ defmodule CanneryWeb.ExportController do
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
packs = Ammo.list_packs(current_user, show_used: true)
|
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)
|
original_counts = packs |> Ammo.get_original_counts(current_user)
|
||||||
cprs = packs |> Ammo.get_cprs(current_user)
|
cprs = packs |> Ammo.get_cprs(current_user)
|
||||||
percentages_remaining = packs |> Ammo.get_percentages_remaining(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 "
|
"Ungültige Nummer an Kopien. Muss zwischen 1 and %{max} liegen. War "
|
||||||
"%{multiplier}"
|
"%{multiplier}"
|
||||||
|
|
||||||
#: lib/cannery/ammo.ex:979
|
#: lib/cannery/ammo.ex:980
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Invalid multiplier"
|
msgid "Invalid multiplier"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -153,7 +153,7 @@ msgstr ""
|
|||||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
|
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/cannery/ammo.ex:979
|
#: lib/cannery/ammo.ex:980
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Invalid multiplier"
|
msgid "Invalid multiplier"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -152,7 +152,7 @@ msgstr ""
|
|||||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
|
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/cannery/ammo.ex:979
|
#: lib/cannery/ammo.ex:980
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Invalid multiplier"
|
msgid "Invalid multiplier"
|
||||||
msgstr ""
|
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}"
|
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"
|
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
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Invalid multiplier"
|
msgid "Invalid multiplier"
|
||||||
msgstr "Multiplicador inválido"
|
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}"
|
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}"
|
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
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Invalid multiplier"
|
msgid "Invalid multiplier"
|
||||||
msgstr "Multiplicateur invalide"
|
msgstr "Multiplicateur invalide"
|
||||||
|
@ -168,7 +168,7 @@ msgstr ""
|
|||||||
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
|
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/cannery/ammo.ex:979
|
#: lib/cannery/ammo.ex:980
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Invalid multiplier"
|
msgid "Invalid multiplier"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -208,7 +208,7 @@ defmodule Cannery.ActivityLogTest do
|
|||||||
assert 0 = ActivityLog.get_used_count(current_user, pack_id: another_pack.id)
|
assert 0 = ActivityLog.get_used_count(current_user, pack_id: another_pack.id)
|
||||||
end
|
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,
|
pack: %{id: pack_id} = pack,
|
||||||
type: type,
|
type: type,
|
||||||
container: container,
|
container: container,
|
||||||
@ -217,20 +217,41 @@ defmodule Cannery.ActivityLogTest do
|
|||||||
{1, [%{id: another_pack_id} = another_pack]} = pack_fixture(type, container, current_user)
|
{1, [%{id: another_pack_id} = another_pack]} = pack_fixture(type, container, current_user)
|
||||||
|
|
||||||
assert %{pack_id => 5} ==
|
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)
|
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 %{^pack_id => 5} = used_counts
|
||||||
assert %{^another_pack_id => 5} = used_counts
|
assert %{^another_pack_id => 5} = used_counts
|
||||||
|
|
||||||
shot_record_fixture(%{count: 15}, current_user, pack)
|
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 %{^pack_id => 20} = used_counts
|
||||||
assert %{^another_pack_id => 5} = used_counts
|
assert %{^another_pack_id => 5} = used_counts
|
||||||
|
|
||||||
shot_record_fixture(%{count: 10}, current_user, pack)
|
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 %{^pack_id => 30} = used_counts
|
||||||
assert %{^another_pack_id => 5} = used_counts
|
assert %{^another_pack_id => 5} = used_counts
|
||||||
end
|
end
|
||||||
@ -317,13 +338,19 @@ defmodule Cannery.ActivityLogTest do
|
|||||||
{1, [pack]} = pack_fixture(another_type, container, current_user)
|
{1, [pack]} = pack_fixture(another_type, container, current_user)
|
||||||
|
|
||||||
assert %{type_id => 5} ==
|
assert %{type_id => 5} ==
|
||||||
[type, another_type]
|
ActivityLog.get_grouped_used_counts(current_user,
|
||||||
|> ActivityLog.get_used_count_for_types(current_user)
|
types: [type, another_type],
|
||||||
|
group_by: :type_id
|
||||||
|
)
|
||||||
|
|
||||||
# use generated pack
|
# use generated pack
|
||||||
shot_record_fixture(%{count: 5}, current_user, 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 %{^type_id => 5} = used_counts
|
||||||
assert %{^another_type_id => 5} = used_counts
|
assert %{^another_type_id => 5} = used_counts
|
||||||
@ -331,7 +358,11 @@ defmodule Cannery.ActivityLogTest do
|
|||||||
# use generated pack again
|
# use generated pack again
|
||||||
shot_record_fixture(%{count: 1}, current_user, pack)
|
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 %{^type_id => 5} = used_counts
|
||||||
assert %{^another_type_id => 6} = used_counts
|
assert %{^another_type_id => 6} = used_counts
|
||||||
|
Loading…
Reference in New Issue
Block a user