useQueryRows
A statement's rows on the page's engine, suspending until they land — for what a page reads once, outside the crossfilter.
The schema above is read once and stays still while the histogram moves: no brush changes what columns a relation has.
Usage
import { useQueryRows } from "@kanzo-tech/ui/analytics";function Schema() {
const columns = useQueryRows<{ column_name: string }>("DESCRIBE telemetry");
return columns.map((c) => <Badge key={c.column_name}>{c.column_name}</Badge>);
}
<Suspense fallback={<Skeleton />}>
<Schema />
</Suspense>It needs a MosaicProvider above it, a Suspense
for the wait and an error boundary for a failure. The statement goes to the engine's own door,
engine.query, not the coordinator's queue, and the rows are objects keyed by column — rowsOf of
the answer — typed by the parameter you give it.
One answer per statement
It is React's use over one promise per engine and SQL text: every component asking the
same statement shares one answer, and asking it again later is answered without a query. So the
statement is the key — a read that should change names what changed in its SQL, a catalog, a table,
a filter value — and nothing else invalidates it. The last 256 statements an engine answered are
kept; a component reading one that was dropped asks again.
A read here is never stopped. A component suspended on it holds no effect, so React gives no
moment at which every reader has gone, and the statement runs to its end and is kept for the next
asker. A read that must stop with its part is useFieldStats's kind: a
TanStack Query query, whose signal aborts the statement when the last part that asked unmounts.
Failures
A failure is thrown as it was thrown to the nearest error boundary — its code, its message —
and not to the provider's onFailure, which would say it twice. It is not kept: the boundary's retry
asks again.
Not for anything that follows the brush
It reads the relation as it is. A number beside filtered charts is
useChartQuery, which connects a Mosaic client and is re-asked when
the crossfilter moves; a read through this one would report unfiltered totals beside them.
API Reference
function useQueryRows<Row = Record<string, unknown>>(query: Query | string): readonly Row[];