Skip to main content
Query planning is the process of transforming a query graph into an optimized expression tree that can be executed by the TypeScript interpreter.

Query Graph Structure

The query graph is a directed graph where:
  • Nodes represent operations (queries, computations, control flow)
  • Edges represent dependencies (data flow, execution order)

Node Types

Edge Types

Translation Process

The translate function is the entry point:
From query-compiler/src/translate.rs

Node Translation

The NodeTranslator walks the graph and generates expressions:
1

Mark Node as Visited

Prevent infinite loops in cyclic graphs:
2

Extract Node Content

Get the actual node data:
3

Dispatch by Node Type

Different node types require different translation logic:

Query Translation

Translating a database query node:

Conditional Translation

Translating an if node creates a conditional expression:

Data Dependencies

Data dependencies flow through the graph via bindings:
When a node needs specific fields from a parent:
Creates field-level bindings:

Query Building

The QueryBuilder trait abstracts SQL generation:
Database-specific builders implement this trait:

In-Memory Processing

Some operations happen in-memory after data is fetched:
These are wrapped in a Process expression:

Application-Level Joins

When relation joins can’t be done in SQL:
The interpreter:
  1. Executes parent query
  2. Extracts join keys from parent results
  3. Executes child query with WHERE key IN (...)
  4. Merges results in-memory based on on conditions

Result Node Structure

The result structure describes how to shape the final output:
This enables the data mapper to transform flat database results into nested JSON.

Optimizations

The planner applies several optimizations:

Subquery Elimination

Flatten nested queries where possible to reduce round-trips.

Projection Pushdown

Only select fields that are actually needed.

Predicate Pushdown

Push WHERE clauses as deep as possible.

Join Coalescing

Combine multiple joins when safe to do so.

Benchmarking Query Planning

Benchmark the compilation process:
From the Makefile:

Query Graph Benchmarks

Benchmark just the graph building phase:

Profiling

Profile a specific query:
This runs the profile_query example which you can customize for your specific use case.

Playground

Explore query planning interactively:
The playground lets you:
  • Input a Prisma schema
  • Write a GraphQL query
  • See the generated expression tree
  • Export Graphviz diagrams (if dot is installed)
Dependencies from query-compiler-playground/Cargo.toml:

Next Steps

Overview

Return to architecture overview

WASM Build

Build the WebAssembly module