From bd0336c4a2e5901cf3a620b193ecca24a846ef75 Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Sun, 10 Nov 2024 13:38:50 +0000 Subject: [PATCH] Start extracting a Collection context --- lib/music_library/collection.ex | 55 +++++++++++++++ lib/music_library/records.ex | 67 +++++-------------- lib/music_library/wishlist.ex | 61 +++-------------- .../live/record_live/index.ex | 7 +- .../live/stats_live/index.ex | 8 +-- priv/gettext/default.pot | 12 ++-- 6 files changed, 96 insertions(+), 114 deletions(-) create mode 100644 lib/music_library/collection.ex diff --git a/lib/music_library/collection.ex b/lib/music_library/collection.ex new file mode 100644 index 00000000..b5448dd9 --- /dev/null +++ b/lib/music_library/collection.ex @@ -0,0 +1,55 @@ +defmodule MusicLibrary.Collection do + import Ecto.Query, warn: false + + alias MusicLibrary.Repo + alias MusicLibrary.Records + alias MusicLibrary.Records.Record + + def search_records(query, opts \\ []) do + limit = Keyword.get(opts, :limit, 20) + offset = Keyword.get(opts, :offset, 0) + + Records.search_records(base_search(), query, limit: limit, offset: offset) + end + + def search_records_count(query) do + Records.search_records_count(base_search(), query) + end + + def count_records_by_format do + q = + from r in base_search(), + group_by: r.format, + order_by: [desc: count(r.id)], + select: {r.format, count(r.id)} + + Repo.all(q) + end + + def count_records_by_type do + q = + from r in base_search(), + group_by: r.type, + order_by: [desc: count(r.id)], + select: {r.type, count(r.id)} + + Repo.all(q) + end + + def get_latest_record! do + fields = Records.minimal_record_fields() + + q = + from r in base_search(), + order_by: [desc: r.purchased_at], + limit: 1, + select: ^fields + + Repo.one!(q) + end + + defp base_search do + from r in Record, + where: not is_nil(r.purchased_at) + end +end diff --git a/lib/music_library/records.ex b/lib/music_library/records.ex index 0556bd36..aacfd410 100644 --- a/lib/music_library/records.ex +++ b/lib/music_library/records.ex @@ -6,13 +6,15 @@ defmodule MusicLibrary.Records do @fields [:id, :type, :artists, :format, :title, :release, :genres, :musicbrainz_id, :cover_hash] - def search_records(query, opts \\ []) do - limit = Keyword.get(opts, :limit, 20) - offset = Keyword.get(opts, :offset, 0) + def minimal_record_fields, do: @fields + + def search_records(initial_search, query, opts) do + limit = Keyword.fetch!(opts, :limit) + offset = Keyword.fetch!(opts, :offset) search = - query - |> build_search() + initial_search + |> build_search(query) |> limit(^limit) |> offset(^offset) |> select(^@fields) @@ -20,24 +22,24 @@ defmodule MusicLibrary.Records do Repo.all(search) end - def search_records_count(query) do - search = build_search(query) + def search_records_count(initial_search, query) do + search = build_search(initial_search, query) Repo.aggregate(search, :count) end - defp build_search(query) do + defp build_search(initial_search, query) do {:ok, parsed_query} = SearchParser.parse(query) - base_search = - from r in Record, - where: not is_nil(r.purchased_at), - order_by: - fragment( - "json_extract(artists, '$[0].sort_name') COLLATE NOCASE ASC, title COLLATE NOCASE ASC" - ) + search_with_order = + initial_search + |> order_by( + fragment( + "json_extract(artists, '$[0].sort_name') COLLATE NOCASE ASC, title COLLATE NOCASE ASC" + ) + ) - Enum.reduce(parsed_query, base_search, fn + Enum.reduce(parsed_query, search_with_order, fn {:artist, artist}, search -> search |> where([r], like(r.artists, ^"%#{artist}%")) @@ -62,41 +64,8 @@ defmodule MusicLibrary.Records do end) end - def count_records_by_format do - q = - from r in Record, - where: not is_nil(r.purchased_at), - group_by: r.format, - order_by: [desc: count(r.id)], - select: {r.format, count(r.id)} - - Repo.all(q) - end - - def count_records_by_type do - q = - from r in Record, - where: not is_nil(r.purchased_at), - group_by: r.type, - order_by: [desc: count(r.id)], - select: {r.type, count(r.id)} - - Repo.all(q) - end - def get_record!(id), do: Repo.get!(Record, id) - def get_latest_record! do - q = - from r in Record, - where: not is_nil(r.purchased_at), - order_by: [desc: r.purchased_at], - limit: 1, - select: ^@fields - - Repo.one!(q) - end - def get_cover(id) do q = from r in Record, diff --git a/lib/music_library/wishlist.ex b/lib/music_library/wishlist.ex index e9d0eb83..5bca2e45 100644 --- a/lib/music_library/wishlist.ex +++ b/lib/music_library/wishlist.ex @@ -2,71 +2,26 @@ defmodule MusicLibrary.Wishlist do import Ecto.Query, warn: false alias MusicLibrary.Repo - alias MusicLibrary.Records.{Record, SearchParser} - - @fields [:id, :type, :artists, :format, :title, :release, :genres, :musicbrainz_id, :cover_hash] + alias MusicLibrary.Records + alias MusicLibrary.Records.Record def search_records(query, opts \\ []) do limit = Keyword.get(opts, :limit, 20) offset = Keyword.get(opts, :offset, 0) - search = - query - |> build_search() - |> limit(^limit) - |> offset(^offset) - |> select(^@fields) - - Repo.all(search) + Records.search_records(base_search(), query, limit: limit, offset: offset) end def search_records_count(query) do - search = build_search(query) - - Repo.aggregate(search, :count) + Records.search_records_count(base_search(), query) end def count do - q = - from r in Record, - where: is_nil(r.purchased_at) - - Repo.aggregate(q, :count) + Repo.aggregate(base_search(), :count) end - defp build_search(query) do - {:ok, parsed_query} = SearchParser.parse(query) - - base_search = - from r in Record, - where: is_nil(r.purchased_at), - order_by: - fragment( - "json_extract(artists, '$[0].sort_name') COLLATE NOCASE ASC, title COLLATE NOCASE ASC" - ) - - Enum.reduce(parsed_query, base_search, fn - {:artist, artist}, search -> - search |> where([r], like(r.artists, ^"%#{artist}%")) - - {:album, album}, search -> - search |> where([r], like(r.title, ^"%#{album}%")) - - {:mbid, mbid}, search -> - search |> where([r], r.musicbrainz_id == ^mbid or like(r.artists, ^"%#{mbid}%")) - - {:format, format}, search -> - search |> where([r], r.format == ^format) - - {:type, type}, search -> - search |> where([r], r.type == ^type) - - {:query, raw_query}, search -> - search - |> where( - [r], - like(r.title, ^"%#{raw_query}%") or like(r.artists, ^"%#{raw_query}%") - ) - end) + defp base_search do + from r in Record, + where: is_nil(r.purchased_at) end end diff --git a/lib/music_library_web/live/record_live/index.ex b/lib/music_library_web/live/record_live/index.ex index 47d1ec67..00182ea2 100644 --- a/lib/music_library_web/live/record_live/index.ex +++ b/lib/music_library_web/live/record_live/index.ex @@ -3,6 +3,7 @@ defmodule MusicLibraryWeb.RecordLive.Index do import MusicLibraryWeb.Pagination alias MusicLibrary.Records + alias MusicLibrary.Collection @default_records_list_params %{ query: "", @@ -57,7 +58,7 @@ defmodule MusicLibraryWeb.RecordLive.Index do defp apply_action(socket, :index, params) do query = params["query"] || "" - total_records = Records.search_records_count(query) + total_records = Collection.search_records_count(query) record_list_params = @default_records_list_params @@ -65,7 +66,9 @@ defmodule MusicLibraryWeb.RecordLive.Index do |> merge_pagination(params, total_records) offset = page_to_offset(record_list_params.page, record_list_params.page_size) - records = Records.search_records(query, limit: record_list_params.page_size, offset: offset) + + records = + Collection.search_records(query, limit: record_list_params.page_size, offset: offset) socket |> assign(:page_title, gettext("Collection")) diff --git a/lib/music_library_web/live/stats_live/index.ex b/lib/music_library_web/live/stats_live/index.ex index d00c8a76..13835280 100644 --- a/lib/music_library_web/live/stats_live/index.ex +++ b/lib/music_library_web/live/stats_live/index.ex @@ -3,20 +3,20 @@ defmodule MusicLibraryWeb.StatsLive.Index do import MusicLibraryWeb.StatsLive.DataComponents - alias MusicLibrary.{Records, Wishlist} + alias MusicLibrary.{Collection, Records, Wishlist} alias Records.Record def mount(_params, _session, socket) do - collection_count_by_format = Records.count_records_by_format() + collection_count_by_format = Collection.count_records_by_format() - collection_count_by_type = Records.count_records_by_type() + collection_count_by_type = Collection.count_records_by_type() collection_count = Enum.reduce(collection_count_by_format, 0, fn {_, count}, acc -> acc + count end) wishlist_count = Wishlist.count() - latest_record = Records.get_latest_record!() + latest_record = Collection.get_latest_record!() recent_tracks = LastFm.Feed.all() diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index e0eebab7..a89b14cc 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -51,7 +51,7 @@ msgid "Choose a value" msgstr "" #: lib/music_library_web/components/layouts/app.html.heex:13 -#: lib/music_library_web/live/record_live/index.ex:71 +#: lib/music_library_web/live/record_live/index.ex:74 #, elixir-autogen, elixir-format msgid "Collection" msgstr "" @@ -69,7 +69,7 @@ msgstr "" msgid "Delete" msgstr "" -#: lib/music_library_web/live/record_live/index.ex:54 +#: lib/music_library_web/live/record_live/index.ex:55 #: lib/music_library_web/live/record_live/index.html.heex:144 #: lib/music_library_web/live/record_live/show.ex:50 #: lib/music_library_web/live/record_live/show.html.heex:4 @@ -81,7 +81,7 @@ msgstr "" msgid "Edit" msgstr "" -#: lib/music_library_web/live/record_live/index.ex:118 +#: lib/music_library_web/live/record_live/index.ex:121 #: lib/music_library_web/live/stats_live/index.ex:60 #: lib/music_library_web/live/stats_live/index.ex:66 #: lib/music_library_web/live/wishlist_live/index.ex:117 @@ -122,7 +122,7 @@ msgstr "" msgid "Import" msgstr "" -#: lib/music_library_web/live/record_live/index.ex:40 +#: lib/music_library_web/live/record_live/index.ex:41 #: lib/music_library_web/live/wishlist_live/index.ex:41 #, elixir-autogen, elixir-format msgid "Import from MusicBrainz" @@ -209,7 +209,7 @@ msgstr "" msgid "Purchased on" msgstr "" -#: lib/music_library_web/live/record_live/index.ex:109 +#: lib/music_library_web/live/record_live/index.ex:112 #: lib/music_library_web/live/stats_live/index.ex:52 #: lib/music_library_web/live/wishlist_live/index.ex:109 #, elixir-autogen, elixir-format @@ -283,7 +283,7 @@ msgstr "" msgid "Success!" msgstr "" -#: lib/music_library_web/live/record_live/index.ex:17 +#: lib/music_library_web/live/record_live/index.ex:18 #: lib/music_library_web/live/record_live/show.ex:19 #: lib/music_library_web/live/wishlist_live/index.ex:18 #: lib/music_library_web/live/wishlist_live/show.ex:19