ormDB

Graph Queries Explained: How ormDB Fetches Object Graphs

Understand ormDB's graph-fetch query model, entity blocks, edge traversals, and how they replace SQL JOINs for relational data retrieval.

Difficulty: intermediateTime: 15 minutes

What Graph Fetches Are

ormDB is a relational database engine written in Rust that replaces PostgreSQL, MySQL, and SQLite. Instead of SQL, ormDB’s native query language uses entity blocks and relation traversals to fetch entire object graphs in a single round-trip.

A graph fetch describes the shape of the data you want. You name an entity, specify which fields to return, and declare which relations to traverse. Each relation opens a new entity block with its own fields, filters, and nested relations. The result is a nested object tree that matches the shape of your query exactly.

Anatomy of a Graph Fetch

A graph fetch has three components: entity blocks, edge declarations, and field selections.

graph_fetch User {
  id,
  name,
  email,
  posts [where: { status: "published" }, order_by: { created_at: desc }, limit: 10] {
    id,
    title,
    created_at,
    comments [order_by: { created_at: asc }] {
      id,
      body,
      author {
        id,
        name
      }
    },
    tags {
      id,
      label
    }
  }
}

Entity blocks (User, posts, comments, author, tags) define which entities to query. Each block is a scope with its own field list and optional filters.

Edge declarations are the relation names (posts, comments, author, tags). These correspond to the relations defined in your schema. ormDB knows the foreign keys and join conditions from the schema definition, not from the query.

Field selections (id, name, title, etc.) control which columns are returned. Use * to select all fields. Field selection happens at every level of the graph independently.

How ormDB Resolves a Graph Fetch

When ormDB receives a graph fetch, it does not decompose it into sequential queries. The engine builds an execution plan that:

  1. Identifies all entity blocks and their filters
  2. Determines the relation edges and their cardinalities
  3. Executes the fetch as a coordinated internal operation
  4. Assembles the nested result tree directly in memory
  5. Returns the complete graph over the zero-copy wire protocol (rkyv) for optimal performance

There is no intermediate row-based representation. The data flows from storage to your application as a structured object tree.

Comparison with SQL

The same data in SQL requires either multiple queries or a complex JOIN:

-- SQL approach: flat rows with duplication
SELECT u.id, u.name, p.id, p.title, c.id, c.body, t.id, t.label
FROM users u
LEFT JOIN posts p ON p.author_id = u.id
LEFT JOIN comments c ON c.post_id = p.id
LEFT JOIN tags t ON t.post_id = p.id
WHERE p.status = 'published'
ORDER BY p.created_at DESC;

This returns flat rows. A user with 3 posts, each with 2 comments and 2 tags, produces 12 rows with duplicated user and post data. Your ORM must then deduplicate and reassemble the object tree. This is the root cause of the N+1 query problem.

ormDB returns the nested tree directly. Each user appears once. Each post appears once under its user. Each comment appears once under its post. No duplication. No reassembly.

Filters, Ordering, and Limits at Every Level

Each entity block accepts its own query parameters:

graph_fetch Order [where: { status: "active" }, limit: 100] {
  *,
  line_items [order_by: { position: asc }] {
    *,
    product {
      id,
      name,
      price
    }
  },
  customer {
    id,
    name,
    email
  }
}

Filters at one level do not affect other levels. Limiting orders to 100 does not limit line items per order. Each entity block is independently scoped.

From ORM to Graph Fetch

Your ORM adapter translates ORM calls into graph fetches automatically. When you write Prisma’s include, Drizzle’s with, or Django’s prefetch_related, the adapter constructs the corresponding graph-fetch request. You get native graph-fetch performance without learning a new query language.

Frequently Asked Questions

Is ormDB a graph database?

No. ormDB is a relational database engine. It stores data in entities (tables) with typed columns and foreign key relations. The term 'graph fetch' refers to how queries traverse relations to return nested object trees, not to a graph storage model like Neo4j.

How does a graph fetch differ from a SQL JOIN?

A SQL JOIN flattens related data into rows, duplicating parent data for each child match. A graph fetch returns a nested object tree where each entity appears once with its related entities nested underneath. No duplication, no post-processing.

Can I filter at each level of the graph?

Yes. Each entity block in a graph fetch supports where clauses, ordering, and limits. You can filter posts by status, order comments by date, and limit tags to 5, all within a single graph-fetch request.

What happens if a relation has no matching records?

Empty relations return empty arrays. The graph fetch still completes in a single round-trip. There is no performance penalty for relations that happen to be empty for some entities.

How does ormDB handle circular relations?

Graph fetches require explicit depth. You specify exactly which relations to traverse and how deep. ormDB does not follow circular references indefinitely. The query shape defines the traversal boundary.

Can I combine graph fetches with aggregations?

Yes. Entity blocks support count, sum, avg, min, and max aggregations alongside relation traversals. You can fetch users with their post count and their most recent 5 posts in a single request.

Related Content

Try ormDB today

Open source, MIT licensed. Install and start building.