
# Query

`RecordQuery` è il filtro in streaming usato con `stream()`. Copre i modelli di accesso basati sulle aggiunte: riprendere da un cursore, leggere una finestra temporale, filtrare per uguaglianza di campo e fermarsi a un limite. Per predicati più complessi, ordinamento e ricerche basate su indici, usate il [generatore di query](https://storh.inline0.dev/it/docs/query-builder); per tutte le operazioni che un semplice `foreach` su uno stream può svolgere, `RecordQuery` è lo strumento più leggero.

`RecordQuery` è immutabile. Ogni modificatore restituisce una query clonata:

```php
$query = Storh\RecordQuery::all()
    ->after($lastSeenId)
    ->time_range_ms($fromMs, $untilMs)
    ->where_equal('kind', 'page')
    ->limit(100);

foreach ($store->stream($query) as $record) {
    // Records are yielded lazily.
}
```

`after()` e `time_range_ms()` usano l'ordinamento UUID, quindi non richiedono un campo timestamp nei dati del record. In `SegmentedLog` evitano anche lavoro inutile: i segmenti il cui intervallo di ID è fuori dalla finestra non vengono mai aperti e gli indici sparsi per segmento consentono di raggiungere il primo record corrispondente senza scorrere dall'inizio.

`where_equal()` confronta un campo dei dati di primo livello con `===` e accetta valori scalari o `null`. Un filtro `null` corrisponde ai record in cui il campo è presente e null; i record senza quel campo non corrispondono.

## Paginazione con cursore

Gli ID sono ordinati per ora di creazione, quindi l'ultimo ID di una pagina è il cursore per la
successiva:

```php
$page = iterator_to_array($store->stream(
    Storh\RecordQuery::all()->after($lastSeenId)->limit(100)
), false);

$lastSeenId = [] === $page ? $lastSeenId : end($page)->id();
```

## Gestire i record danneggiati

Per impostazione predefinita, una scansione genera un errore al primo record illeggibile. Usate
`continue_on_error()` se la scansione deve saltarlo e segnalare l'errore
invece:

```php
$query = Storh\RecordQuery::all()->continue_on_error(
    static function (string $location, Throwable $error): void {
        error_log($location . ': ' . $error->getMessage());
    },
);
```

La posizione corrisponde all'ID del record per `DocStore` e a `segment-file:byte-offset`
per `SegmentedLog`. `repair()` serve per ripulire davvero i record danneggiati; consultate [CLI](https://storh.inline0.dev/it/docs/cli).
