Historical Queries
How omnihedron handles versioned table data with blockHeight and timestamp arguments
SubQuery indexers can store every version of a row, not just the latest. Each version is tagged with a _block_range column — a PostgreSQL int8range that says "this version was valid from block X to block Y."
How it works
When omnihedron introspects a table and finds a _block_range column, it marks that table as historical. Historical tables get an extra argument on their connection query.
Detection
At startup, omnihedron reads the historicalStateEnabled key from the _metadata table:
SELECT value FROM "{schema}"."_metadata"
WHERE key = 'historicalStateEnabled' LIMIT 1- If the value is
"timestamp"→ the argument is namedtimestamp - Otherwise → the argument is named
blockHeight
Querying
# Block height mode
{
transfers(blockHeight: "1729590000000") {
nodes { id amount }
}
}
# Timestamp mode (same syntax, different argument name)
{
transfers(timestamp: "1729590000000") {
nodes { id amount }
}
}Both generate identical SQL:
SELECT t."id", t."amount"
FROM "app"."transfers" AS t
WHERE t._block_range @> 1729590000000::bigint
ORDER BY t."id" ASC, t."_id" ASCThe _id ASC tiebreaker ensures deterministic ordering when multiple versions of different rows exist.
Default behaviour
When no blockHeight/timestamp argument is provided, omnihedron filters for the latest version:
WHERE t._block_range @> 9223372036854775807::bigintThis uses MAX_INT64 rather than upper_inf() to match PostGraphile's default behaviour.
Relations and block height
Block height propagates through relations. If you query:
{
transfers(blockHeight: "5000000") {
nodes {
id
account {
name
}
eventsByTransferId {
nodes { type }
}
}
}
}The blockHeight value is embedded in the response context and inherited by both forward and backward relation resolvers. The related tables (accounts, events) also get filtered with _block_range @> 5000000::bigint, so you get a consistent snapshot across all related data.
Relation filter subqueries
When using relation filters on historical tables, the _block_range condition is included in the EXISTS subquery:
WHERE EXISTS (
SELECT 1 FROM "app"."accounts" AS r
WHERE r.id = t.account_id
AND r._block_range @> $N::bigint
AND r."name" = $1
)