# `PhoenixKitCatalogue.Catalogue.Search`
[🔗](https://github.com/BeamLabEU/phoenix_kit_catalogue/blob/0.1.14/lib/phoenix_kit_catalogue/catalogue/search.ex#L1)

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`.

# `count_search_items`

```elixir
@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`

```elixir
@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`

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

Total match count for `search_items_in_category/3`.

# `search_items`

```elixir
@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`.
  * `:limit` — max results (default 50).
  * `:offset` — paging offset (default 0).

# `search_items_in_catalogue`

```elixir
@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.

# `search_items_in_category`

```elixir
@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]`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
