diff --git a/lib/membership/member.ex b/lib/membership/member.ex index 7fe69da..583f173 100644 --- a/lib/membership/member.ex +++ b/lib/membership/member.ex @@ -166,11 +166,6 @@ defmodule Mv.Membership.Member do attribute :postal_code, :string do allow_nil? true end - - attribute :search_vector, AshPostgres.Tsvector, - writable?: false, - public?: false, - select_by_default?: false end relationships do diff --git a/lib/mv_web/live/components/search_bar_component.ex b/lib/mv_web/live/components/search_bar_component.ex deleted file mode 100644 index 3eb5246..0000000 --- a/lib/mv_web/live/components/search_bar_component.ex +++ /dev/null @@ -1,61 +0,0 @@ -defmodule MvWeb.Components.SearchBarComponent do - @moduledoc """ - Provides the SearchBar Live-Component. - - - uses the DaisyUI search input field - - sends search_changed event to parent live view with a query - """ - use MvWeb, :live_component - - @impl true - def update(_assigns, socket) do - socket = - socket - |> assign_new(:query, fn -> "" end) - |> assign_new(:placeholder, fn -> gettext("Search...") end) - - {:ok, socket} - end - - @impl true - def render(assigns) do - ~H""" - - """ - end - - @impl true - # Function to handle the search - def handle_event("search", %{"query" => q}, socket) do - # Forward a high level message to the parent - send(self(), {:search_changed, q}) - {:noreply, assign(socket, :query, q)} - end -end diff --git a/lib/mv_web/live/member_live/index.ex b/lib/mv_web/live/member_live/index.ex index 6a7daab..f5edbd0 100644 --- a/lib/mv_web/live/member_live/index.ex +++ b/lib/mv_web/live/member_live/index.ex @@ -1,15 +1,11 @@ defmodule MvWeb.MemberLive.Index do use MvWeb, :live_view - import Ash.Expr - import Ash.Query - import MvWeb.TableComponents @impl true def mount(params, _session, socket) do socket = socket |> assign(:page_title, gettext("Members")) - |> assign(:query, "") |> assign_new(:sort_field, fn -> :first_name end) |> assign_new(:sort_order, fn -> :asc end) |> assign(:selected_members, []) @@ -19,32 +15,6 @@ defmodule MvWeb.MemberLive.Index do {:ok, socket} end - # ----------------------------------------------------------------- - # Receive messages from any toolbar component - # ----------------------------------------------------------------- - - # Function to handle search - @impl true - def handle_info({:search_changed, q}, socket) do - members = - if String.trim(q) == "" do - Ash.read!(Mv.Membership.Member) - else - Mv.Membership.Member - |> filter(expr(fragment("search_vector @@ plainto_tsquery('simple', ?)", ^q))) - |> Ash.read!() - end - - {:noreply, - socket - |> assign(:query, q) - |> assign(:members, members)} - end - - # ----------------------------------------------------------------- - # Handle Events - # ----------------------------------------------------------------- - # ----------------------------------------------------------------- # Handle Events # ----------------------------------------------------------------- diff --git a/lib/mv_web/live/member_live/index.html.heex b/lib/mv_web/live/member_live/index.html.heex index 4072a51..29f07dd 100644 --- a/lib/mv_web/live/member_live/index.html.heex +++ b/lib/mv_web/live/member_live/index.html.heex @@ -8,13 +8,6 @@ - <.live_component - module={MvWeb.Components.SearchBarComponent} - id="search-bar" - query={@query} - placeholder={gettext("Search...")} - /> - <.table id="members" rows={@members} diff --git a/priv/repo/migrations/20250912085235_AddSearchVectorToMembers.exs b/priv/repo/migrations/20250912085235_AddSearchVectorToMembers.exs deleted file mode 100644 index 126f369..0000000 --- a/priv/repo/migrations/20250912085235_AddSearchVectorToMembers.exs +++ /dev/null @@ -1,60 +0,0 @@ -defmodule Mv.Repo.Migrations.AddSearchVectorToMembers do - @moduledoc """ - Updates resources based on their most recent snapshots. - - This file was autogenerated with `mix ash_postgres.generate_migrations` - """ - - use Ecto.Migration - - def up do - alter table(:members) do - add :search_vector, :tsvector - end - - execute(""" - CREATE INDEX members_search_vector_idx - ON members - USING GIN (search_vector) - """) - - # Eigene Trigger-Funktion mit Gewichtung - execute(""" - CREATE FUNCTION members_search_vector_trigger() RETURNS trigger AS $$ - BEGIN - NEW.search_vector := - setweight(to_tsvector('simple', coalesce(NEW.first_name, '')), 'A') || - setweight(to_tsvector('simple', coalesce(NEW.last_name, '')), 'A') || - setweight(to_tsvector('simple', coalesce(NEW.email, '')), 'B') || - setweight(to_tsvector('simple', coalesce(NEW.birth_date::text, '')), 'C') || - setweight(to_tsvector('simple', coalesce(NEW.phone_number, '')), 'C') || - setweight(to_tsvector('simple', coalesce(NEW.join_date::text, '')), 'D') || - setweight(to_tsvector('simple', coalesce(NEW.exit_date::text, '')), 'D') || - setweight(to_tsvector('simple', coalesce(NEW.notes, '')), 'B') || - setweight(to_tsvector('simple', coalesce(NEW.city, '')), 'C') || - setweight(to_tsvector('simple', coalesce(NEW.street, '')), 'C') || - setweight(to_tsvector('simple', coalesce(NEW.house_number::text, '')), 'C') || - setweight(to_tsvector('simple', coalesce(NEW.postal_code::text, '')), 'C'); - RETURN NEW; - END - $$ LANGUAGE plpgsql; - """) - - execute(""" - CREATE TRIGGER update_search_vector - BEFORE INSERT OR UPDATE ON members - FOR EACH ROW - EXECUTE FUNCTION members_search_vector_trigger() - """) - end - - def down do - execute("DROP TRIGGER IF EXISTS update_search_vector ON members") - execute("DROP FUNCTION IF EXISTS members_search_vector_trigger()") - execute("DROP INDEX IF EXISTS members_search_vector_idx") - - alter table(:members) do - remove :search_vector - end - end -end diff --git a/priv/resource_snapshots/repo/members/20250912085235.json b/priv/resource_snapshots/repo/members/20250912085235.json deleted file mode 100644 index a8b86da..0000000 --- a/priv/resource_snapshots/repo/members/20250912085235.json +++ /dev/null @@ -1,199 +0,0 @@ -{ - "attributes": [ - { - "allow_nil?": false, - "default": "fragment(\"uuid_generate_v7()\")", - "generated?": false, - "precision": null, - "primary_key?": true, - "references": null, - "scale": null, - "size": null, - "source": "id", - "type": "uuid" - }, - { - "allow_nil?": false, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "first_name", - "type": "text" - }, - { - "allow_nil?": false, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "last_name", - "type": "text" - }, - { - "allow_nil?": false, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "email", - "type": "text" - }, - { - "allow_nil?": true, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "birth_date", - "type": "date" - }, - { - "allow_nil?": true, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "paid", - "type": "boolean" - }, - { - "allow_nil?": true, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "phone_number", - "type": "text" - }, - { - "allow_nil?": true, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "join_date", - "type": "date" - }, - { - "allow_nil?": true, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "exit_date", - "type": "date" - }, - { - "allow_nil?": true, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "notes", - "type": "text" - }, - { - "allow_nil?": true, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "city", - "type": "text" - }, - { - "allow_nil?": true, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "street", - "type": "text" - }, - { - "allow_nil?": true, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "house_number", - "type": "text" - }, - { - "allow_nil?": true, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "postal_code", - "type": "text" - }, - { - "allow_nil?": true, - "default": "nil", - "generated?": false, - "precision": null, - "primary_key?": false, - "references": null, - "scale": null, - "size": null, - "source": "search_vectors", - "type": "tsvector" - } - ], - "base_filter": null, - "check_constraints": [], - "custom_indexes": [], - "custom_statements": [], - "has_create_action": true, - "hash": "3B162FD69B92BF8258DB56BA0CBB6108FBE996B1F7231C5F2D9EC53D956EFC75", - "identities": [], - "multitenancy": { - "attribute": null, - "global": null, - "strategy": null - }, - "repo": "Elixir.Mv.Repo", - "schema": null, - "table": "members" -} \ No newline at end of file diff --git a/test/mv_web/components/search_bar_component_test.exs b/test/mv_web/components/search_bar_component_test.exs deleted file mode 100644 index 2c85f19..0000000 --- a/test/mv_web/components/search_bar_component_test.exs +++ /dev/null @@ -1,33 +0,0 @@ -defmodule MvWeb.Components.SearchBarComponentTest do - use MvWeb.ConnCase, async: true - import Phoenix.LiveViewTest - - describe "SearchBarComponent" do - test "renders with placeholder", %{conn: conn} do - conn = conn_with_oidc_user(conn) - {:ok, view, _html} = live(conn, "/members") - - assert has_element?(view, "input[placeholder='Search...']") - end - - test "updates query when user types", %{conn: conn} do - conn = conn_with_oidc_user(conn) - {:ok, view, _html} = live(conn, "/members") - - # simulate search input and check that other members are not listed - html = - view - |> element("form[role=search]") - |> render_change(%{"query" => "Friedrich"}) - - refute html =~ "Greta" - - html = - view - |> element("form[role=search]") - |> render_change(%{"query" => "Greta"}) - - refute html =~ "Friedrich" - end - end -end diff --git a/test/mv_web/member_live/index_test.exs b/test/mv_web/member_live/index_test.exs index a119a51..b4abaa5 100644 --- a/test/mv_web/member_live/index_test.exs +++ b/test/mv_web/member_live/index_test.exs @@ -108,16 +108,4 @@ defmodule MvWeb.MemberLive.IndexTest do assert conn.assigns.sort_order == :desc end end - - test "handle_info(:search_changed) updates assigns with search results", %{conn: conn} do - conn = conn_with_oidc_user(conn) - {:ok, view, _html} = live(conn, "/members") - - send(view.pid, {:search_changed, "Friedrich"}) - - state = :sys.get_state(view.pid) - - assert state.socket.assigns.query == "Friedrich" - assert is_list(state.socket.assigns.members) - end end