
# Abfragen

`RecordQuery` ist der Streaming-Filter für `stream()`. Er deckt Zugriffsmuster mit vielen Anhängevorgängen ab: nach einem Cursor fortfahren, ein Zeitfenster lesen, nach Feldgleichheit filtern und die Ergebnisse auf ein Limit beschränken. Für komplexere Bedingungen, Sortierung und indexgestützte Abfragen verwende den [Abfrage-Builder](https://storh.inline0.dev/de/docs/query-builder). Für alles, was ein einfacher `foreach` über einen Stream leisten kann, ist `RecordQuery` das effizientere Werkzeug.

`RecordQuery` ist unveränderlich. Jeder Modifikator gibt eine geklonte Abfrage zurück:

```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()` und `time_range_ms()` verwenden die Reihenfolge von UUID und benötigen deshalb kein Zeitstempelfeld in den Datensatzdaten. Bei `SegmentedLog` vermeiden sie außerdem unnötige Arbeit: Segmente, deren ID-Bereich außerhalb des Zeitfensters liegt, werden gar nicht erst geöffnet, und sparsame Indizes pro Segment springen nahe an den ersten passenden Datensatz.

`where_equal()` vergleicht ein Datenfeld der obersten Ebene mit `===` und akzeptiert skalare Werte oder `null`. Ein `null`-Filter findet Datensätze, bei denen das Feld vorhanden und null ist; Datensätze ohne dieses Feld werden nicht gefunden.

## Cursor-Paginierung

IDs werden nach Erstellungszeit sortiert. Daher dient die letzte ID einer Seite als Cursor für die nächste:

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

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

## Beschädigte Datensätze übergehen

Standardmäßig bricht ein Scan beim ersten unlesbaren Datensatz ab. Verwende `continue_on_error()`, wenn der Scan ihn überspringen und den Fehler stattdessen melden soll:

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

Bei `DocStore` und `segment-file:byte-offset` entspricht der Speicherort der Datensatz-ID; bei `SegmentedLog` `repair()` ist das Werkzeug, um beschädigte Datensätze tatsächlich zu bereinigen. Siehe [CLI](https://storh.inline0.dev/de/docs/cli).
