feat(member). added search action to ressource

This commit is contained in:
carla 2025-10-30 16:39:44 +01:00
parent c7c6d329fb
commit f6bfeadb7b

View file

@ -3,6 +3,11 @@ defmodule Mv.Membership.Member do
domain: Mv.Membership,
data_layer: AshPostgres.DataLayer
require Ash.Query
import Ash.Expr
@default_fields [:first_name, :last_name, :email, :phone_number, :city, :street, :house_number, :postal_code]
postgres do
table "members"
repo Mv.Repo
@ -108,6 +113,47 @@ defmodule Mv.Membership.Member do
where [changing(:user)]
end
end
read :search do
argument :query, :string, allow_nil?: true
argument :fields, {:array, :atom}, allow_nil?: true
argument :similarity_threshold, :float, allow_nil?: true
prepare fn query, _ctx ->
q = Ash.Query.get_argument(query, :query) || ""
fields = Ash.Query.get_argument(query, :fields) || @default_fields
threshold = Ash.Query.get_argument(query, :similarity_threshold) || 0.2
if is_binary(q) and String.trim(q) != "" do
q2 = String.trim(q)
pat = "%" <> q2 <> "%"
# FTS as main filter and fuzzy search just fo first name, last name and strees
query
|> Ash.Query.filter(
expr(
fragment("search_vector @@ websearch_to_tsquery('simple', ?)", ^q2) or
fragment("search_vector @@ plainto_tsquery('simple', ?)", ^q2) or
# Substring on numeric-like fields (best effort, supports middle substrings)
contains(postal_code, ^q2) or
contains(house_number, ^q2) or
contains(phone_number, ^q2) or
fragment("? % first_name", ^q2) or
fragment("? % last_name", ^q2) or
fragment("? % street", ^q2) or
fragment("word_similarity(?, first_name) > ?", ^q2, ^threshold) or
fragment("word_similarity(?, last_name) > ?", ^q2, ^threshold) or
fragment("word_similarity(?, street) > ?", ^q2, ^threshold) or
fragment("similarity(first_name, ?) > ?", ^q2, ^threshold) or
fragment("similarity(last_name, ?) > ?", ^q2, ^threshold) or
fragment("similarity(street, ?) > ?", ^q2, ^threshold)
)
)
else
query
end
end
end
end
validations do
@ -281,4 +327,21 @@ defmodule Mv.Membership.Member do
identities do
identity :unique_email, [:email]
end
# Fuzzy Search function that can be called by live view and calls search action
def fuzzy_search(query, opts) do
q = (opts[:query] || opts["query"] || "") |> to_string()
if String.trim(q) == "" do
query
else
args =
case (opts[:fields] || opts["fields"]) do
nil -> %{query: q}
fields -> %{query: q, fields: fields}
end
Ash.Query.for_read(query, :search, args)
end
end
end