diff --git a/lib/music_library/record_sets.ex b/lib/music_library/record_sets.ex index 2ce987de..a7d8a319 100644 --- a/lib/music_library/record_sets.ex +++ b/lib/music_library/record_sets.ex @@ -21,6 +21,23 @@ defmodule MusicLibrary.RecordSets do Repo.aggregate(RecordSet, :count) end + def count_record_sets(query) do + record_sets_search_query(query) + |> Repo.aggregate(:count) + end + + def search_record_sets(query, opts \\ []) do + offset = Keyword.get(opts, :offset, 0) + limit = Keyword.get(opts, :limit, 20) + + record_sets_search_query(query) + |> order_by([rs], desc: rs.updated_at) + |> offset(^offset) + |> limit(^limit) + |> preload(items: :record) + |> Repo.all() + end + def get_record_set!(id) do RecordSet |> Repo.get!(id) @@ -125,6 +142,37 @@ defmodule MusicLibrary.RecordSets do {:ok, get_record_set!(record_set.id)} end + defp record_sets_search_query(""), do: from(rs in RecordSet) + + defp record_sets_search_query(query) do + like_query = "%#{query}%" + + from(rs in RecordSet, + where: + like(rs.name, ^like_query) or + like(rs.description, ^like_query) or + fragment( + """ + EXISTS ( + SELECT 1 FROM record_set_items AS i + JOIN records AS r ON r.id = i.record_id + WHERE i.record_set_id = ? + AND ( + r.title LIKE ? + OR EXISTS ( + SELECT 1 FROM json_each(r.artists) + WHERE json_extract(value, '$.name') LIKE ? + ) + ) + ) + """, + rs.id, + ^like_query, + ^like_query + ) + ) + end + defp recompact_positions(record_set_id) do items = from(i in RecordSetItem, diff --git a/lib/music_library_web/live/record_set_live/index.ex b/lib/music_library_web/live/record_set_live/index.ex index 74a5bc2f..9d081dbd 100644 --- a/lib/music_library_web/live/record_set_live/index.ex +++ b/lib/music_library_web/live/record_set_live/index.ex @@ -47,10 +47,12 @@ defmodule MusicLibraryWeb.RecordSetLive.Index do end defp apply_action(socket, :index, params) do - total_sets = RecordSets.count_record_sets() + query = params["query"] || "" + total_sets = RecordSets.count_record_sets(query) list_params = @default_list_params + |> merge_query(query) |> merge_pagination(params, total_sets) load_and_assign_sets(socket, list_params) @@ -75,6 +77,10 @@ defmodule MusicLibraryWeb.RecordSetLive.Index do |> Map.put(:total_records, total_records) end + defp merge_query(params, query) do + Map.put(params, :query, query) + end + defp parse_page(nil), do: 1 defp parse_page(page) when is_binary(page) do @@ -101,7 +107,7 @@ defmodule MusicLibraryWeb.RecordSetLive.Index do offset = page_to_offset(list_params.page, list_params.page_size) sets = - RecordSets.list_record_sets( + RecordSets.search_record_sets(list_params.query, offset: offset, limit: list_params.page_size ) @@ -119,7 +125,8 @@ defmodule MusicLibraryWeb.RecordSetLive.Index do def back_path(list_params) do qs = list_params - |> Map.take([:page, :page_size]) + |> Map.take([:query, :page, :page_size]) + |> Enum.filter(fn {_, v} -> v not in ["", nil] end) ~p"/record-sets?#{qs}" end @@ -152,6 +159,15 @@ defmodule MusicLibraryWeb.RecordSetLive.Index do end @impl true + def handle_event("search", %{"query" => query}, socket) do + qs = + @default_list_params + |> Map.put(:query, query) + |> Map.take([:query, :page, :page_size]) + + {:noreply, push_patch(socket, to: ~p"/record-sets?#{qs}")} + end + def handle_event("delete_set", %{"id" => id}, socket) do record_set = RecordSets.get_record_set!(id) {:ok, _} = RecordSets.delete_record_set(record_set) diff --git a/lib/music_library_web/live/record_set_live/index.html.heex b/lib/music_library_web/live/record_set_live/index.html.heex index 4be75e94..893e825a 100644 --- a/lib/music_library_web/live/record_set_live/index.html.heex +++ b/lib/music_library_web/live/record_set_live/index.html.heex @@ -19,6 +19,8 @@ + <.search_form query={@list_params.query} /> +