Start extracting a Collection context

This commit is contained in:
Claudio Ortolina
2024-11-10 13:38:50 +00:00
parent b247cb2536
commit bd0336c4a2
6 changed files with 96 additions and 114 deletions
+55
View File
@@ -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
+15 -46
View File
@@ -6,13 +6,15 @@ defmodule MusicLibrary.Records do
@fields [:id, :type, :artists, :format, :title, :release, :genres, :musicbrainz_id, :cover_hash] @fields [:id, :type, :artists, :format, :title, :release, :genres, :musicbrainz_id, :cover_hash]
def search_records(query, opts \\ []) do def minimal_record_fields, do: @fields
limit = Keyword.get(opts, :limit, 20)
offset = Keyword.get(opts, :offset, 0) def search_records(initial_search, query, opts) do
limit = Keyword.fetch!(opts, :limit)
offset = Keyword.fetch!(opts, :offset)
search = search =
query initial_search
|> build_search() |> build_search(query)
|> limit(^limit) |> limit(^limit)
|> offset(^offset) |> offset(^offset)
|> select(^@fields) |> select(^@fields)
@@ -20,24 +22,24 @@ defmodule MusicLibrary.Records do
Repo.all(search) Repo.all(search)
end end
def search_records_count(query) do def search_records_count(initial_search, query) do
search = build_search(query) search = build_search(initial_search, query)
Repo.aggregate(search, :count) Repo.aggregate(search, :count)
end end
defp build_search(query) do defp build_search(initial_search, query) do
{:ok, parsed_query} = SearchParser.parse(query) {:ok, parsed_query} = SearchParser.parse(query)
base_search = search_with_order =
from r in Record, initial_search
where: not is_nil(r.purchased_at), |> order_by(
order_by:
fragment( fragment(
"json_extract(artists, '$[0].sort_name') COLLATE NOCASE ASC, title COLLATE NOCASE ASC" "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 -> {:artist, artist}, search ->
search |> where([r], like(r.artists, ^"%#{artist}%")) search |> where([r], like(r.artists, ^"%#{artist}%"))
@@ -62,41 +64,8 @@ defmodule MusicLibrary.Records do
end) end)
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_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 def get_cover(id) do
q = q =
from r in Record, from r in Record,
+8 -53
View File
@@ -2,71 +2,26 @@ defmodule MusicLibrary.Wishlist do
import Ecto.Query, warn: false import Ecto.Query, warn: false
alias MusicLibrary.Repo alias MusicLibrary.Repo
alias MusicLibrary.Records.{Record, SearchParser} alias MusicLibrary.Records
alias MusicLibrary.Records.Record
@fields [:id, :type, :artists, :format, :title, :release, :genres, :musicbrainz_id, :cover_hash]
def search_records(query, opts \\ []) do def search_records(query, opts \\ []) do
limit = Keyword.get(opts, :limit, 20) limit = Keyword.get(opts, :limit, 20)
offset = Keyword.get(opts, :offset, 0) offset = Keyword.get(opts, :offset, 0)
search = Records.search_records(base_search(), query, limit: limit, offset: offset)
query
|> build_search()
|> limit(^limit)
|> offset(^offset)
|> select(^@fields)
Repo.all(search)
end end
def search_records_count(query) do def search_records_count(query) do
search = build_search(query) Records.search_records_count(base_search(), query)
Repo.aggregate(search, :count)
end end
def count do def count do
q = Repo.aggregate(base_search(), :count)
end
defp base_search do
from r in Record, from r in Record,
where: is_nil(r.purchased_at) where: is_nil(r.purchased_at)
Repo.aggregate(q, :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)
end end
end end
@@ -3,6 +3,7 @@ defmodule MusicLibraryWeb.RecordLive.Index do
import MusicLibraryWeb.Pagination import MusicLibraryWeb.Pagination
alias MusicLibrary.Records alias MusicLibrary.Records
alias MusicLibrary.Collection
@default_records_list_params %{ @default_records_list_params %{
query: "", query: "",
@@ -57,7 +58,7 @@ defmodule MusicLibraryWeb.RecordLive.Index do
defp apply_action(socket, :index, params) do defp apply_action(socket, :index, params) do
query = params["query"] || "" query = params["query"] || ""
total_records = Records.search_records_count(query) total_records = Collection.search_records_count(query)
record_list_params = record_list_params =
@default_records_list_params @default_records_list_params
@@ -65,7 +66,9 @@ defmodule MusicLibraryWeb.RecordLive.Index do
|> merge_pagination(params, total_records) |> merge_pagination(params, total_records)
offset = page_to_offset(record_list_params.page, record_list_params.page_size) 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 socket
|> assign(:page_title, gettext("Collection")) |> assign(:page_title, gettext("Collection"))
@@ -3,20 +3,20 @@ defmodule MusicLibraryWeb.StatsLive.Index do
import MusicLibraryWeb.StatsLive.DataComponents import MusicLibraryWeb.StatsLive.DataComponents
alias MusicLibrary.{Records, Wishlist} alias MusicLibrary.{Collection, Records, Wishlist}
alias Records.Record alias Records.Record
def mount(_params, _session, socket) do 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 = collection_count =
Enum.reduce(collection_count_by_format, 0, fn {_, count}, acc -> acc + count end) Enum.reduce(collection_count_by_format, 0, fn {_, count}, acc -> acc + count end)
wishlist_count = Wishlist.count() wishlist_count = Wishlist.count()
latest_record = Records.get_latest_record!() latest_record = Collection.get_latest_record!()
recent_tracks = LastFm.Feed.all() recent_tracks = LastFm.Feed.all()
+6 -6
View File
@@ -51,7 +51,7 @@ msgid "Choose a value"
msgstr "" msgstr ""
#: lib/music_library_web/components/layouts/app.html.heex:13 #: 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 #, elixir-autogen, elixir-format
msgid "Collection" msgid "Collection"
msgstr "" msgstr ""
@@ -69,7 +69,7 @@ msgstr ""
msgid "Delete" msgid "Delete"
msgstr "" 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/index.html.heex:144
#: lib/music_library_web/live/record_live/show.ex:50 #: lib/music_library_web/live/record_live/show.ex:50
#: lib/music_library_web/live/record_live/show.html.heex:4 #: lib/music_library_web/live/record_live/show.html.heex:4
@@ -81,7 +81,7 @@ msgstr ""
msgid "Edit" msgid "Edit"
msgstr "" 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:60
#: lib/music_library_web/live/stats_live/index.ex:66 #: lib/music_library_web/live/stats_live/index.ex:66
#: lib/music_library_web/live/wishlist_live/index.ex:117 #: lib/music_library_web/live/wishlist_live/index.ex:117
@@ -122,7 +122,7 @@ msgstr ""
msgid "Import" msgid "Import"
msgstr "" 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 #: lib/music_library_web/live/wishlist_live/index.ex:41
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Import from MusicBrainz" msgid "Import from MusicBrainz"
@@ -209,7 +209,7 @@ msgstr ""
msgid "Purchased on" msgid "Purchased on"
msgstr "" 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/stats_live/index.ex:52
#: lib/music_library_web/live/wishlist_live/index.ex:109 #: lib/music_library_web/live/wishlist_live/index.ex:109
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@@ -283,7 +283,7 @@ msgstr ""
msgid "Success!" msgid "Success!"
msgstr "" 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/record_live/show.ex:19
#: lib/music_library_web/live/wishlist_live/index.ex:18 #: lib/music_library_web/live/wishlist_live/index.ex:18
#: lib/music_library_web/live/wishlist_live/show.ex:19 #: lib/music_library_web/live/wishlist_live/show.ex:19