PhoenixKitCatalogue.Catalogue.Search (PhoenixKitCatalogue v0.21.0)

Copy Markdown View Source

Item search — global, per-catalogue, and per-category, with optional scope composition (catalogue_uuids AND category_uuids).

Matches case-insensitively against name, description, sku, and the multilang data JSONB. Excludes items in deleted catalogues or deleted categories. Uncategorized items are included unless a :category_uuids filter narrows the search.

Public surface is re-exported from PhoenixKitCatalogue.Catalogue.

Summary

Functions

Returns the total number of items matching search_items/2's filters. Ignores :limit/:offset. Same scope opts as search_items/2.

Narrows any query with an :item named binding to the items a search term matches — name, description, SKU, and every translated string in the record's data.

Categories whose NAME or description matches, within one catalogue.

Searches items with flexible scope.

Searches items within a specific catalogue. Convenience wrapper around search_items/2 with catalogue_uuids: [catalogue_uuid], but orders by category position first (then item name) for a stable walk through a catalogue's categories.

Searches items within a specific category. Convenience wrapper around search_items/2 with category_uuids: [category_uuid].

Functions

count_search_items(query, opts \\ [])

@spec count_search_items(
  String.t(),
  keyword()
) :: non_neg_integer()

Returns the total number of items matching search_items/2's filters. Ignores :limit/:offset. Same scope opts as search_items/2.

count_search_items_in_catalogue(catalogue_uuid, query)

@spec count_search_items_in_catalogue(Ecto.UUID.t(), String.t()) :: non_neg_integer()

Total match count for search_items_in_catalogue/3.

count_search_items_in_category(category_uuid, query)

@spec count_search_items_in_category(Ecto.UUID.t(), String.t()) :: non_neg_integer()

Total match count for search_items_in_category/3.

match_text(query, term)

@spec match_text(Ecto.Query.t(), String.t() | nil) :: Ecto.Query.t()

Narrows any query with an :item named binding to the items a search term matches — name, description, SKU, and every translated string in the record's data.

Public because the attribute filter's FACET COUNTS have to agree with the list beside them: a value offered as live while a search is on has to still be live under that search, and it can only promise that by asking the same question the listing asks. nil or a blank term is "no text constraint" and leaves the query alone.

Callers pass a raw user string; trimming and LIKE-escaping happen here.

search_categories(catalogue_uuid, query_str, opts \\ [])

@spec search_categories(Ecto.UUID.t(), String.t(), keyword()) :: [
  PhoenixKitCatalogue.Schemas.Category.t()
]

Categories whose NAME or description matches, within one catalogue.

Item search never covered these: searching a catalogue for a category it contains returned nothing, and the page looked like it had matched only because that category's own card happened to be on screen (Max, 2026-08-28).

:parent_uuid narrows to that category's SUBTREE (itself excluded), mirroring how search_items_in_category/3 scopes items when the user has drilled in. Deleted categories and categories of deleted catalogues are excluded, as everywhere else.

search_items(query, opts \\ [])

@spec search_items(
  String.t(),
  keyword()
) :: [PhoenixKitCatalogue.Schemas.Item.t()]

Searches items with flexible scope.

Options

  • :catalogue_uuids — list of catalogue UUIDs to scope to. nil or [] = all.
  • :category_uuids — list of category UUIDs to scope to. nil or [] = all + uncategorized. Must contain only non-nil UUIDs; passing [nil] raises ArgumentError (use :only => :uncategorized_only for that intent).
  • :include_descendants — when true (default since V103), each entry in :category_uuids is expanded to include every descendant category in the nested-category tree. Pass false to scope strictly to the given UUIDs.
  • :only:uncategorized_only restricts to items with no category_uuid; :categorized_only restricts to items that belong to some category. nil (default) is unrestricted. Combining :uncategorized_only with a non-empty :category_uuids is a logical contradiction and raises ArgumentError.
  • :statuses — list of item statuses to include ("active", "inactive", "discontinued"). nil or [] = all non-deleted (the historical default). Soft-deleted rows stay excluded even if "deleted" is listed. Atoms are accepted and stringified.
  • :limit — max results (default 50).
  • :offset — paging offset (default 0).
  • :preload — extra associations appended to the default [:catalogue, category: :catalogue]. Pass [catalogue_rules: :referenced_catalogue] for smart-pricing.

search_items_in_catalogue(catalogue_uuid, query, opts \\ [])

@spec search_items_in_catalogue(Ecto.UUID.t(), String.t(), keyword()) :: [
  PhoenixKitCatalogue.Schemas.Item.t()
]

Searches items within a specific catalogue. Convenience wrapper around search_items/2 with catalogue_uuids: [catalogue_uuid], but orders by category position first (then item name) for a stable walk through a catalogue's categories.

Same :preload opt as search_items/2 (extra associations appended to the default [:catalogue, category: :catalogue]).

search_items_in_category(category_uuid, query, opts \\ [])

@spec search_items_in_category(Ecto.UUID.t(), String.t(), keyword()) :: [
  PhoenixKitCatalogue.Schemas.Item.t()
]

Searches items within a specific category. Convenience wrapper around search_items/2 with category_uuids: [category_uuid].