diff --git a/lib/music_library/collection.ex b/lib/music_library/collection.ex index 1de5d634..239e8be4 100644 --- a/lib/music_library/collection.ex +++ b/lib/music_library/collection.ex @@ -161,6 +161,23 @@ defmodule MusicLibrary.Collection do Repo.all(q) end + @spec count_records_by_release_year(keyword()) :: [{String.t(), non_neg_integer()}] + def count_records_by_release_year(opts \\ []) do + limit = Keyword.get(opts, :limit, @pagination[:stats_limit]) + + q = + from r in Record, + where: not is_nil(r.purchased_at), + where: not is_nil(r.release_date), + where: r.release_date != "", + group_by: fragment("substr(?, 1, 4)", r.release_date), + order_by: [desc: fragment("count(1)")], + select: {fragment("substr(?, 1, 4)", r.release_date), fragment("count(1)")}, + limit: ^limit + + Repo.all(q) + end + @spec collected_releases_query() :: Ecto.Query.t() def collected_releases_query do from rr in RecordRelease, diff --git a/lib/music_library_web/live/stats_live/index.ex b/lib/music_library_web/live/stats_live/index.ex index 930a8557..95319441 100644 --- a/lib/music_library_web/live/stats_live/index.ex +++ b/lib/music_library_web/live/stats_live/index.ex @@ -292,7 +292,7 @@ defmodule MusicLibraryWeb.StatsLive.Index do -
+

{gettext("Top %{n} Collection Artists", %{n: length(@records_by_artist)})} @@ -336,6 +336,23 @@ defmodule MusicLibraryWeb.StatsLive.Index do />

+ +
+

+ {gettext("Top 20 Release Years")} +

+
+ <.vertical_bar_chart + data={@records_by_release_year} + width={600} + height={26 * length(@records_by_release_year)} + color_class="fill-red-500" + label_fn={fn {year, _count} -> year end} + value_fn={fn {_year, count} -> count end} + class="w-full" + /> +
+
""" @@ -347,6 +364,7 @@ defmodule MusicLibraryWeb.StatsLive.Index do latest_record = Collection.get_latest_record() records_by_artists = Collection.count_records_by_artist(limit: 20) records_by_genre = Collection.count_records_by_genre(limit: 20) + records_by_release_year = Collection.count_records_by_release_year(limit: 20) records_on_this_day = current_date @@ -375,6 +393,7 @@ defmodule MusicLibraryWeb.StatsLive.Index do current_section: :stats, records_by_artist: records_by_artists, records_by_genre: records_by_genre, + records_by_release_year: records_by_release_year, records_on_this_day: records_on_this_day )} end diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index ad45939b..89a72f9c 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -2336,3 +2336,8 @@ msgstr "" #, elixir-autogen, elixir-format msgid "Track ID" msgstr "" + +#: lib/music_library_web/live/stats_live/index.ex +#, elixir-autogen, elixir-format +msgid "Top 20 Release Years" +msgstr "" diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index 0b8df7e4..6c960e2f 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -2336,3 +2336,8 @@ msgstr "" #, elixir-autogen, elixir-format, fuzzy msgid "Track ID" msgstr "" + +#: lib/music_library_web/live/stats_live/index.ex +#, elixir-autogen, elixir-format +msgid "Top 20 Release Years" +msgstr "" diff --git a/test/music_library/collection_test.exs b/test/music_library/collection_test.exs index 0fac8526..43d6441b 100644 --- a/test/music_library/collection_test.exs +++ b/test/music_library/collection_test.exs @@ -156,6 +156,79 @@ defmodule MusicLibrary.CollectionTest do end end + describe "count_records_by_release_year/1" do + test "returns counts grouped by release year, ordered by count descending" do + record_with_artist("Artist A", %{ + release_date: "1994-09-13", + purchased_at: ~U[2024-12-27 16:50:57Z] + }) + + record_with_artist("Artist B", %{ + release_date: "1994-03-01", + purchased_at: ~U[2024-12-28 16:50:57Z] + }) + + record_with_artist("Artist C", %{ + release_date: "2020", + purchased_at: ~U[2024-12-29 16:50:57Z] + }) + + assert [{"1994", 2}, {"2020", 1}] = Collection.count_records_by_release_year() + end + + test "excludes wishlisted records" do + record_with_artist("Artist A", %{ + release_date: "2020", + purchased_at: ~U[2024-12-27 16:50:57Z] + }) + + record_with_artist("Artist B", %{ + release_date: "2020", + purchased_at: nil + }) + + assert [{"2020", 1}] = Collection.count_records_by_release_year() + end + + test "excludes records without a release date" do + record_with_artist("Artist A", %{ + release_date: "2020", + purchased_at: ~U[2024-12-27 16:50:57Z] + }) + + record_with_artist("Artist B", %{ + release_date: nil, + purchased_at: ~U[2024-12-28 16:50:57Z] + }) + + record_with_artist("Artist C", %{ + release_date: "", + purchased_at: ~U[2024-12-29 16:50:57Z] + }) + + assert [{"2020", 1}] = Collection.count_records_by_release_year() + end + + test "respects limit" do + record_with_artist("Artist A", %{ + release_date: "1994", + purchased_at: ~U[2024-12-27 16:50:57Z] + }) + + record_with_artist("Artist B", %{ + release_date: "1994", + purchased_at: ~U[2024-12-28 16:50:57Z] + }) + + record_with_artist("Artist C", %{ + release_date: "2020", + purchased_at: ~U[2024-12-29 16:50:57Z] + }) + + assert [{"1994", 2}] = Collection.count_records_by_release_year(limit: 1) + end + end + describe "collected_artist_ids/0" do setup [:fill_collection]