# index

Signature
`index<Term, Value>(family: AtomFamily<Value>, predicate: (value: Value, term: Term) => boolean, options?: IndexOptions<Term>): (term: Term) => Selector<Atom<Value>[]>`

valdres
Create memoized reactive family filters

`index` creates a memoized selector for each search term. Each selector returns
the atoms in an `atomFamily` whose current values satisfy the predicate.

```ts
import { atomFamily, index, store } from "valdres"

const post = atomFamily<{ title: string; tags: string[] }, [string]>(null)
const postsByTag = index(
    post,
    (value, tag: string) => value.tags.includes(tag),
    { name: "postsByTag" },
)

const app = store()
app.set(post("one"), { title: "First post", tags: ["news"] })
app.get(postsByTag("news")) // [post("one")]
```

## Reactive-filter semantics

Despite its name, `index` is a reactive filter rather than a materialized
database index. The first read for a term is O(n) in the number of family
members. After a member changes, its predicate selector is the only predicate
that recomputes. If its boolean result is unchanged, equality pruning stops
there in O(1). If the result flips, the term selector walks the family to
preserve the ordered array result, so a membership-changing update is O(n).

This is a good fit for modest collections and for queries whose predicate is
more expensive than walking the family. For large, frequently updated
collections that require sublinear writes, maintain a lookup structure in store
state as part of the same transaction that changes the source family.

Term selectors are cached weakly. Repeated calls return the same selector while
a caller or live store dependency graph retains it, but querying many one-off
terms does not retain every selector and term for the lifetime of the `index`
function.

## Term identity and `keyOf`

Terms use the same collision-safe structural key codec as `atomFamily` and
`selectorFamily`. Primitive types remain distinct, while plain Object property
order and Map/Set insertion order do not affect identity. Symbols, functions,
Promises, class instances, accessor properties, and cyclic structures are not
supported by default.

Use `keyOf` to derive supported identity for one of those terms, or to
intentionally group multiple term objects:

```ts
type Query = { tag: string; uiState: Map<string, unknown> }

const postsByQuery = index(
    post,
    (value, query: Query) => value.tags.includes(query.tag),
    { keyOf: query => query.tag },
)
```

`keyOf` receives the term and its result is encoded by the canonical family-key
codec.

## See also

- [atomFamily](https://valdres.dev/valdres/atomFamily) — create the source collection
- [selectorFamily](https://valdres.dev/valdres/selectorFamily) — create arbitrary keyed derivations
- [selector](https://valdres.dev/valdres/selector) — derive a single value
