# `Flicker.Providers.Static`
[🔗](https://github.com/team-alembic/flicker/blob/v0.1.0/lib/flicker/providers/static.ex#L1)

A small in-memory `Flicker.Provider` backed by a fixed list of results.

This is Flicker's reference pure-Elixir provider: it proves the
`Flicker.Provider` contract stands alone with no Ash dependency, and it
doubles as the test double for component tests
([Spec 001](https://github.com/team-alembic/flicker/blob/main/docs/specs/spec-001-portable-single-select.md)
onward). It is also the worked example for third parties writing their
own provider from the docs alone.

Configure it with `{Flicker.Providers.Static, results: [...]}`:

    results = [
      %Flicker.Result{value: 1, label: "Casey Cassidy", sublabel: "Bass"},
      %Flicker.Result{value: 2, label: "Alex Rivers", sublabel: "Drums"}
    ]

    Flicker.Provider.run_search(
      {Flicker.Providers.Static, results: results},
      %Flicker.Query{text: "cas"}
    )
    #=> {:ok, [%Flicker.Result{value: 1, label: "Casey Cassidy", sublabel: "Bass"}]}

`search/2` matches `query.text` case-insensitively against `:label` and
`:sublabel`; a blank query returns the full (optionally `:limit`-ed) list,
mirroring how a real provider shows a default listing when the picker
opens with nothing typed yet. `fetch/2` resolves all matching `:value`s in
one pass, silently omitting any that aren't present in `:results` — the
same "partial results are normal" behaviour ADR-003 requires of every
provider.

`search/2` matches text only and **ignores `query.facets` entirely** — a
fixed in-memory list has no type system for `Flicker.Providers.AshResource`-style
facet derivation to introspect, so faceted filtering isn't something this
provider can meaningfully support. A `facets:`-configured `Flicker.select/1`
backed by `Static` still gets facet-key/value autocomplete over a
hand-built `Flicker.Facet` registry (Spec 003), it just won't narrow
`:results` by them — write a custom provider (or use `AshResource`) if
that's needed.

# `fetch`

```elixir
@spec fetch([term()], keyword()) :: {:ok, [Flicker.Result.t()]} | {:error, term()}
```

Resolves `values` against `opts[:results]` in one pass, returning only
the ones present — unresolvable values are simply absent, not an error
(ADR-003).

Matches by `to_string/1`, not strict term equality: form-field mode's
`field.value` always arrives as a string (from params, or a LiveSocket
reconnect), while a result's `:value` is commonly an integer or atom —
the same string-normalised comparison `Flicker.Components.Select` itself
uses everywhere (`reorder_like/2`, `matches_values?/2`, `filter_selected/2`).

# `search`

```elixir
@spec search(Flicker.Query.t(), keyword()) ::
  {:ok, [Flicker.Result.t()]} | {:error, term()}
```

Returns results whose `:label` or `:sublabel` contains `query.text`
(case-insensitively), windowed by `opts[:offset]` (default `0`) and
`opts[:limit]` (default: no limit) via `Enum.slice/3`
([Spec 010](https://github.com/team-alembic/flicker/blob/main/docs/specs/spec-010-windowed-search.md)).

A blank `query.text` matches everything, so callers get a listing rather
than an empty set when the picker opens with no input yet. Omitting
`:offset` (the default `0`) is byte-identical to the pre-windowing
behaviour.

---

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