Skip to content

BE-306: HashQL: PostgreSQL translation#8526

Open
indietyp wants to merge 7 commits intobm/be-457-hashql-mir-execution-pipeline-extensions-for-postgresfrom
bm/be-306-hashql-postgres-translation
Open

BE-306: HashQL: PostgreSQL translation#8526
indietyp wants to merge 7 commits intobm/be-457-hashql-mir-execution-pipeline-extensions-for-postgresfrom
bm/be-306-hashql-postgres-translation

Conversation

@indietyp
Copy link
Member

@indietyp indietyp commented Mar 8, 2026

🌟 What is the purpose of this PR?

Implements the postgres compilation backend for HashQL. Takes the MIR control flow graph (after execution analysis has assigned basic blocks to backends and partitioned them into islands) and compiles the Postgres-assigned islands into SQL SELECT statements.

🔍 What does this change?

Postgres compiler (eval/src/postgres/mod.rs):
Top-level entry point. Compiles a GraphRead body island-by-island into a PreparedQuery (a SelectStatement + deduplicated Parameters list). Each Postgres island becomes a CROSS JOIN LATERAL subquery returning a continuation composite value. The continuation carries filter (keep/reject/passthrough), block (next basic block), and locals/values (live-out data for the interpreter to resume from).

Filter compiler (eval/src/postgres/filter/):
Walks the MIR basic blocks within an island and compiles each statement into SQL expressions. Uses an explicit frame stack (not recursion) to handle SwitchInt terminators: each branch becomes a CASE WHEN arm, with the discriminant cast to ::int to avoid boolean/integer type mismatches in PostgreSQL. Out-of-island branches produce continuation values that encode which block to resume and what locals to carry.

Projections (eval/src/postgres/projections.rs):
Maps EntityPath variants to SQL column references or JSONB extraction expressions. Tracks which table joins are needed and only requests them when a path is actually referenced. Handles the split between "column-backed" paths (entity_uuid, web_id, etc.) and "JSONB-backed" paths (properties, type IDs).

Parameters (eval/src/postgres/parameters.rs):
Builds the $1, $2, ... parameter list for the prepared statement. Deduplicates by identity. Each Parameter variant represents a different source: Input (user-provided values), Symbol/Primitive/Int (query literals), Env (closure captures), TemporalAxis (execution context). The CompiledQuery return type exposes which indices correspond to which sources so the interpreter can bind them.

Continuation (eval/src/postgres/continuation.rs):
Builds the ROW(filter, block, locals, values)::continuation composite values that encode island exit state. Handles the three exit cases: passthrough (NULL continuation), filter-only (just a boolean), and full exit (block + live-out locals serialized as parallel int[]/jsonb[] arrays).

Traverse (eval/src/postgres/traverse.rs):
Compiles graph traversal requirements into SQL joins. Reads the island's provides set to determine which entity paths need table joins, then requests them from the database context layer.

Error infrastructure (eval/src/postgres/error.rs):
Diagnostic types for compilation errors (unsupported operations, type mismatches, missing paths) with span-accurate source locations.

Context (eval/src/context.rs):
DatabaseContext trait and implementation that the compiler uses to request table aliases, register joins, and access the schema. Bridges between the HashQL type system and the graph-store query builder.

Compiletest suite (compiletest/src/suite/eval_postgres.rs):
New compiletest suite that runs the full pipeline (parse, type-check, lower to MIR, run execution analysis, compile to SQL) and compares the output against blessed .stdout files. Also emits .aux.mir secondary outputs showing the MIR after execution analysis for debugging.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing

📜 Does this require a change to the docs?

The changes in this PR:

  • are internal and do not require a docs change

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

OFFSET 0 on lateral subqueries is a workaround for PostgreSQL inlining composites; see continuation.rs doc comments for details.

🛡 What tests cover this?

  • Filter compiler unit tests (filter/tests.rs, ~1000 lines) using insta snapshots covering: straight-line blocks, branching CFGs, diamond merges, island exits, projections, property access, parameter deduplication, lateral subquery generation
  • 30+ compiletest cases under eval/tests/ui/postgres/ covering end-to-end compilation: comparison operators, entity field access, input parameters, let bindings, if-expressions, nested branching, environment captures, list/dict/struct/tuple construction, multiple filters, mixed-source filters

❓ How to test this?

cargo nextest run -p hashql-eval
cargo run --package hashql-compiletest -- run

indietyp added 2 commits March 8, 2026 16:17
feat: checkpoint (II)

feat: checkpoint (III)

feat: snapshot vec

feat: add dedicated filter

feat: checkpoint

feat: filter implementation

feat: filter implementation (mostly) done

chore: environment capture note

chore: always postgres bigint

feat: target clone

feat: simplify lookup

feat: move storage up

feat: eval entity path

chore: checkpoint

chore: checkpoint

chore: find entrypoint

feat: eval context

feat: eval cleanup

chore: cleanup

feat: track index

feat: wire up filter

feat: add error reporting

chore: checkpoint

feat: add traverse, and first postgres compiler outline

feat: traverse bitmap

feat: move traversal out

feat: projections

feat: projections

fix: clippy

feat: subquery projection for lateral

feat: checkpoint

feat: test plan

feat: checkpoint

feat: checkpoint – failing tests ;-;

feat: checkpoint – failing tests ;-;

feat: checkpoint — passing tests

fix: import

fix: entity type

feat: checkpoint

feat: attribute a cost to terminator placement switches

fix: import

feat: checkpoint

feat: checkpoint

chore: lint
@cursor
Copy link

cursor bot commented Mar 8, 2026

PR Summary

High Risk
Introduces a new MIR→SQL compilation backend and changes query/type infrastructure, which can affect correctness and performance of database queries. Although parameterized and well-tested, it touches compiler invariants, liveness/island execution analysis integration, and SQL generation paths.

Overview
Adds a PostgreSQL compilation backend for HashQL by lowering GraphRead filter bodies (post-execution-analysis “islands”) into parameterized SQL SELECT statements, using CROSS JOIN LATERAL continuation subqueries to encode filter decisions and island exits (next block + live-out locals/values).

Extends hashql-eval with a new EvalContext (incl. traversal liveness/live-out computation), SQL parameter deduplication, lazy join/projection planning, entity-path→column mapping, and Postgres-specific diagnostics. Adds extensive snapshot coverage: a new eval/postgres compiletest suite plus insta-based unit tests and UI fixtures for generated SQL/MIR.

Also updates the Postgres query AST to support boolean types and adjusts workspace dependencies/diagrams to include the new Postgres/MIR integration.

Written by Cursor Bugbot for commit 5037fe8. This will update automatically on new commits. Configure here.

@vercel
Copy link

vercel bot commented Mar 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment Mar 8, 2026 6:35pm
petrinaut Ready Ready Preview Mar 8, 2026 6:35pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
hashdotdesign Ignored Ignored Preview Mar 8, 2026 6:35pm
hashdotdesign-tokens Ignored Ignored Preview Mar 8, 2026 6:35pm

@github-actions github-actions bot removed the area/infra Relates to version control, CI, CD or IaC (area) label Mar 8, 2026
@augmentcode
Copy link

augmentcode bot commented Mar 8, 2026

🤖 Augment PR Summary

Summary: Adds a PostgreSQL compilation backend for HashQL by lowering MIR execution islands into SQL SELECT statements with continuation-based control flow.

Key changes:

  • Introduces eval/src/postgres/ with a top-level PostgresCompiler that compiles GraphRead filters island-by-island into lateral subqueries returning a typed continuation composite.
  • Adds a CFG-to-SQL filter compiler (postgres/filter) that builds CASE WHEN trees iteratively (explicit frame stack) and emits island-exit continuations carrying live-out locals.
  • Implements parameter deduplication (postgres/parameters.rs) and lazy join planning/projection mapping (postgres/projections.rs, postgres/traverse.rs).
  • Adds new eval-level EvalContext + live-out dataflow computation used by the Postgres backend.
  • Extends diagnostics to include Postgres backend categories (postgres/error.rs + eval/src/error.rs integration).
  • Adds a new compiletest suite (compiletest/src/suite/eval_postgres.rs) and a sizable set of end-to-end UI test fixtures under eval/tests/ui/postgres/, plus MIR snapshot tests for hard-to-produce MIR shapes.

Technical notes: Compiled filter islands are materialized with CROSS JOIN LATERAL and OFFSET 0 to prevent Postgres from inlining/duplicating CASE trees; selected entity paths are driven by the island provides set and only trigger joins when referenced.

🤖 Was this summary useful? React with 👍 or 👎

Copy link

@augmentcode augmentcode bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 2 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

@codspeed-hq
Copy link

codspeed-hq bot commented Mar 8, 2026

Merging this PR will not alter performance

✅ 80 untouched benchmarks


Comparing bm/be-306-hashql-postgres-translation (5037fe8) with bm/be-457-hashql-mir-execution-pipeline-extensions-for-postgres (db87959)

Open in CodSpeed

@indietyp indietyp force-pushed the bm/be-306-hashql-postgres-translation branch from 33a9dcc to 8c07a05 Compare March 8, 2026 16:15
@indietyp indietyp force-pushed the bm/be-457-hashql-mir-execution-pipeline-extensions-for-postgres branch from 5d95ba7 to 1aa0f1c Compare March 8, 2026 16:15
@codecov
Copy link

codecov bot commented Mar 8, 2026

Codecov Report

❌ Patch coverage is 94.61182% with 93 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.23%. Comparing base (db87959) to head (5037fe8).

Files with missing lines Patch % Lines
libs/@local/hashql/eval/src/postgres/filter/mod.rs 89.30% 43 Missing and 5 partials ⚠️
libs/@local/hashql/eval/src/postgres/error.rs 0.00% 22 Missing ⚠️
...bs/@local/hashql/eval/src/postgres/filter/tests.rs 98.22% 5 Missing and 3 partials ⚠️
libs/@local/hashql/eval/src/postgres/mod.rs 96.95% 4 Missing and 1 partial ⚠️
libs/@local/hashql/eval/src/postgres/traverse.rs 96.00% 5 Missing ⚠️
libs/@local/hashql/eval/src/context.rs 95.55% 1 Missing and 1 partial ⚠️
libs/@local/hashql/eval/src/postgres/parameters.rs 98.26% 2 Missing ⚠️
libs/@local/hashql/eval/src/error.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@                                         Coverage Diff                                         @@
##           bm/be-457-hashql-mir-execution-pipeline-extensions-for-postgres    #8526      +/-   ##
===================================================================================================
+ Coverage                                                            62.89%   63.23%   +0.34%     
===================================================================================================
  Files                                                                 1320     1329       +9     
  Lines                                                               135182   137063    +1881     
  Branches                                                              5514     5540      +26     
===================================================================================================
+ Hits                                                                 85025    86678    +1653     
- Misses                                                               49242    49460     +218     
- Partials                                                               915      925      +10     
Flag Coverage Δ
apps.hash-ai-worker-ts 1.40% <ø> (ø)
apps.hash-api 0.00% <ø> (ø)
local.hash-graph-sdk 7.73% <ø> (ø)
local.hash-isomorphic-utils 0.00% <ø> (ø)
rust.hash-graph-api 2.64% <ø> (ø)
rust.hashql-compiletest 29.69% <ø> (ø)
rust.hashql-eval 80.88% <94.61%> (+11.25%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@indietyp indietyp force-pushed the bm/be-306-hashql-postgres-translation branch from 8c07a05 to 667967a Compare March 8, 2026 16:56
@indietyp indietyp force-pushed the bm/be-457-hashql-mir-execution-pipeline-extensions-for-postgres branch from 1aa0f1c to 87024df Compare March 8, 2026 16:56
@indietyp indietyp force-pushed the bm/be-306-hashql-postgres-translation branch from 667967a to ad5227a Compare March 8, 2026 17:03
@indietyp indietyp force-pushed the bm/be-457-hashql-mir-execution-pipeline-extensions-for-postgres branch from 87024df to 269a31f Compare March 8, 2026 17:03
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2026

Benchmark results

@rust/hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$29.0 \mathrm{ms} \pm 167 \mathrm{μs}\left({\color{gray}3.35 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.65 \mathrm{ms} \pm 17.3 \mathrm{μs}\left({\color{gray}3.50 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1001 $$13.0 \mathrm{ms} \pm 89.1 \mathrm{μs}\left({\color{gray}-1.835 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$44.8 \mathrm{ms} \pm 316 \mathrm{μs}\left({\color{gray}0.985 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$15.6 \mathrm{ms} \pm 95.6 \mathrm{μs}\left({\color{gray}2.64 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1526 $$25.3 \mathrm{ms} \pm 191 \mathrm{μs}\left({\color{gray}1.32 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$29.9 \mathrm{ms} \pm 169 \mathrm{μs}\left({\color{gray}3.89 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.99 \mathrm{ms} \pm 21.0 \mathrm{μs}\left({\color{gray}3.91 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$14.1 \mathrm{ms} \pm 122 \mathrm{μs}\left({\color{gray}2.33 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.95 \mathrm{ms} \pm 19.9 \mathrm{μs}\left({\color{gray}1.01 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.14 \mathrm{ms} \pm 13.0 \mathrm{μs}\left({\color{gray}0.727 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 51 $$3.49 \mathrm{ms} \pm 16.2 \mathrm{μs}\left({\color{gray}0.720 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.43 \mathrm{ms} \pm 31.9 \mathrm{μs}\left({\color{gray}1.36 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.78 \mathrm{ms} \pm 22.8 \mathrm{μs}\left({\color{gray}1.53 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 107 $$4.36 \mathrm{ms} \pm 26.7 \mathrm{μs}\left({\color{gray}0.673 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.71 \mathrm{ms} \pm 40.8 \mathrm{μs}\left({\color{gray}1.82 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.58 \mathrm{ms} \pm 15.2 \mathrm{μs}\left({\color{gray}0.330 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$4.27 \mathrm{ms} \pm 26.3 \mathrm{μs}\left({\color{gray}1.40 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.86 \mathrm{ms} \pm 13.4 \mathrm{μs}\left({\color{gray}0.040 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.80 \mathrm{ms} \pm 12.7 \mathrm{μs}\left({\color{gray}-0.224 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1 $$2.92 \mathrm{ms} \pm 12.3 \mathrm{μs}\left({\color{gray}0.412 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$3.19 \mathrm{ms} \pm 16.0 \mathrm{μs}\left({\color{gray}-0.077 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.99 \mathrm{ms} \pm 13.3 \mathrm{μs}\left({\color{gray}0.145 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$3.29 \mathrm{ms} \pm 16.3 \mathrm{μs}\left({\color{gray}-0.136 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$3.23 \mathrm{ms} \pm 15.4 \mathrm{μs}\left({\color{gray}0.800 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.92 \mathrm{ms} \pm 12.1 \mathrm{μs}\left({\color{gray}0.627 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 25 $$3.11 \mathrm{ms} \pm 16.6 \mathrm{μs}\left({\color{gray}0.643 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.73 \mathrm{ms} \pm 21.5 \mathrm{μs}\left({\color{gray}1.45 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.20 \mathrm{ms} \pm 18.2 \mathrm{μs}\left({\color{gray}0.189 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 26 $$3.44 \mathrm{ms} \pm 17.5 \mathrm{μs}\left({\color{gray}0.110 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.61 \mathrm{ms} \pm 15.0 \mathrm{μs}\left({\color{gray}0.394 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.19 \mathrm{ms} \pm 13.9 \mathrm{μs}\left({\color{gray}0.499 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.50 \mathrm{ms} \pm 17.2 \mathrm{μs}\left({\color{gray}1.06 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$42.8 \mathrm{ms} \pm 216 \mathrm{μs}\left({\color{gray}2.27 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$80.3 \mathrm{ms} \pm 472 \mathrm{μs}\left({\color{gray}0.838 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$46.8 \mathrm{ms} \pm 241 \mathrm{μs}\left({\color{gray}-2.816 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$50.4 \mathrm{ms} \pm 336 \mathrm{μs}\left({\color{gray}3.70 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$58.6 \mathrm{ms} \pm 268 \mathrm{μs}\left({\color{gray}3.54 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$44.0 \mathrm{ms} \pm 192 \mathrm{μs}\left({\color{gray}0.161 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$427 \mathrm{ms} \pm 765 \mathrm{μs}\left({\color{gray}2.39 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$101 \mathrm{ms} \pm 437 \mathrm{μs}\left({\color{gray}1.80 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$88.6 \mathrm{ms} \pm 462 \mathrm{μs}\left({\color{gray}1.61 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$329 \mathrm{ms} \pm 961 \mathrm{μs}\left({\color{red}9.74 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$16.2 \mathrm{ms} \pm 61.2 \mathrm{μs}\left({\color{gray}-1.657 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$16.1 \mathrm{ms} \pm 78.6 \mathrm{μs}\left({\color{gray}-0.761 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$16.4 \mathrm{ms} \pm 78.9 \mathrm{μs}\left({\color{gray}-0.501 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$15.9 \mathrm{ms} \pm 81.8 \mathrm{μs}\left({\color{gray}-1.069 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$19.3 \mathrm{ms} \pm 121 \mathrm{μs}\left({\color{gray}-0.596 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$16.0 \mathrm{ms} \pm 79.7 \mathrm{μs}\left({\color{gray}-1.884 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$15.9 \mathrm{ms} \pm 71.5 \mathrm{μs}\left({\color{gray}-0.806 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$16.0 \mathrm{ms} \pm 74.7 \mathrm{μs}\left({\color{gray}-0.047 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$16.6 \mathrm{ms} \pm 85.0 \mathrm{μs}\left({\color{gray}-0.733 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$24.8 \mathrm{ms} \pm 161 \mathrm{μs}\left({\color{gray}3.96 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity

Function Value Mean Flame graphs
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1 $$31.3 \mathrm{ms} \pm 246 \mathrm{μs}\left({\color{gray}-2.804 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$31.3 \mathrm{ms} \pm 286 \mathrm{μs}\left({\color{gray}-2.397 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$31.3 \mathrm{ms} \pm 248 \mathrm{μs}\left({\color{gray}-4.782 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$31.4 \mathrm{ms} \pm 329 \mathrm{μs}\left({\color{gray}-4.220 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$31.4 \mathrm{ms} \pm 264 \mathrm{μs}\left({\color{gray}-1.583 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$30.6 \mathrm{ms} \pm 274 \mathrm{μs}\left({\color{lightgreen}-6.819 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$30.3 \mathrm{ms} \pm 344 \mathrm{μs}\left({\color{lightgreen}-5.167 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$32.9 \mathrm{ms} \pm 273 \mathrm{μs}\left({\color{gray}1.25 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$31.6 \mathrm{ms} \pm 276 \mathrm{μs}\left({\color{lightgreen}-6.171 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity_type

Function Value Mean Flame graphs
get_entity_type_by_id Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba $$8.75 \mathrm{ms} \pm 41.5 \mathrm{μs}\left({\color{gray}-2.182 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$90.1 \mathrm{ms} \pm 488 \mathrm{μs}\left({\color{gray}-3.027 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$143 \mathrm{ms} \pm 590 \mathrm{μs}\left({\color{gray}-2.711 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$97.7 \mathrm{ms} \pm 537 \mathrm{μs}\left({\color{gray}-2.485 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$105 \mathrm{ms} \pm 505 \mathrm{μs}\left({\color{gray}-2.938 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$114 \mathrm{ms} \pm 504 \mathrm{μs}\left({\color{gray}-3.879 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$122 \mathrm{ms} \pm 531 \mathrm{μs}\left({\color{gray}-2.977 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$89.1 \mathrm{ms} \pm 386 \mathrm{μs}\left({\color{gray}-1.635 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$119 \mathrm{ms} \pm 594 \mathrm{μs}\left({\color{gray}0.652 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$96.1 \mathrm{ms} \pm 437 \mathrm{μs}\left({\color{gray}-0.337 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$105 \mathrm{ms} \pm 559 \mathrm{μs}\left({\color{gray}0.220 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$107 \mathrm{ms} \pm 464 \mathrm{μs}\left({\color{gray}-1.361 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$107 \mathrm{ms} \pm 483 \mathrm{μs}\left({\color{gray}-0.424 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$131 \mathrm{ms} \pm 564 \mathrm{μs}\left({\color{gray}2.85 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$134 \mathrm{ms} \pm 525 \mathrm{μs}\left({\color{gray}4.94 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$105 \mathrm{ms} \pm 469 \mathrm{μs}\left({\color{gray}-2.621 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$573 \mathrm{ms} \pm 2.47 \mathrm{ms}\left({\color{lightgreen}-6.468 \mathrm{\%}}\right) $$ Flame Graph

@graphite-app graphite-app bot requested review from a team March 9, 2026 09:43
@@ -0,0 +1,7 @@
---
source: libs/@local/hashql/eval/src/postgres/filter/tests.rs
expression: report.to_string()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we please change this expression to the actual query? Then it's far easier to review the tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash* Affects HASH (a `hash-*` app) area/apps > hash-graph area/apps area/deps Relates to third-party dependencies (area) area/libs Relates to first-party libraries/crates/packages (area) area/tests New or updated tests type/eng > backend Owned by the @backend team

Development

Successfully merging this pull request may close these issues.

2 participants