Skip to content

Query model

A Ramose query is inert, serializable data. Building one performs no read. The TypeScript builder and QueryDocumentV1 are two authoring surfaces for the same normalized query plan.

const openTasks = db.query
.from(Task)
.where({ done: false })
.orderBy(Task.createdAt, "desc")

An entity root returns that concrete type. A trait root returns every readable composer. The root establishes the focus whose identity keeps rows distinct.

Filters constrain candidate rows. Equality, ranges, sets, boolean combinations, relation paths, and nested existence all compile into the portable query. Indexed equality and range constraints reduce work early; late string predicates and broad negative conditions usually scan more.

Authorization is not a query rewrite. Ramose first constructs the principal’s filtered immutable database, then runs the same query engine. Hidden facts cannot participate in joins, ordering, negation, aggregates, or limits.

Without an explicit projection, an entity query returns a friendly entity row. A projection selects only what the consumer needs and may shape relations:

const cards = db.query.from(Task).select({
id: Task.id,
title: Task.title,
assignee: Task.assignee.select({ id: User.id, name: User.name }).optional,
})

Entity-focused client results become live handles with .data, .local, and .mutate. A projection that drops the entity focus, or an aggregate, returns plain serializable values.

Queries return many by default. .one() expresses zero-or-one; .oneOrFail() requires exactly one. Never fetch many and choose the first when identity is part of correctness.

App and MCP execution differ intentionally

Section titled “App and MCP execution differ intentionally”

Observed app queries execute over the complete authorized local database. The server synchronizes database changes, not UI query definitions. That means a new query can run offline and several screens can reuse one local replica.

MCP and server-side reads submit QueryDocumentV1 to the server. They use budgets, explicit page bounds, and opaque cursors. Shared fixtures guarantee that builder and document forms agree.

The dominant costs are candidate facts examined, intermediate rows produced by joins, projection width, nested collection size, recursion, and sorting before a limit. Query budgets fail explicitly instead of returning partial data.

Pagination is part of the query contract. Prefer stable indexed order plus cursor pagination for user-facing feeds. Aggregates operate within the configured database and one authorized view.