jit
ReferenceOperators

Query operators

Filters, projection, aggregation, mutation, lazy operators and output backends.

Conditions

The condition builder supports eq, neq, gt, gte, lt, lte, and, or, and not.

const query = JIT.query(Users)
  .params({ minimum: JIT.number(), role: JIT.string() })
  .filter((q, params) =>
    q.and(q.eq("role", params.role), q.gte("score", params.minimum)),
  );

Runtime parameters are read from the typed params object. JIT.const(value) marks a compiler literal. Ordinary values become external bindings and are not interpolated into generated source.

Eager operators

OperatorOutput/behavior
.filter(predicate)keeps matching elements
.select(...keys)projects a typed object
.unique(key)first value for each key
.keyed(key)Map keyed by one field
.groupBy(key)record of arrays
.orderBy(key, direction)global sort
.sum/.count/.avg/.min/.maxscalar aggregate
.delete()immutable filtered collection
.update(patch)immutable update of matching items

Filters and projection share a generated loop. Aggregates avoid output arrays. orderBy necessarily stores accepted elements before sorting.

Query .keyed(key) is an output collector that builds a new Map per invocation. It is different from schema .keyed(key), which annotates entity identity and indexed equality. The entity and index guide compares both APIs and their cache behavior.

Incremental operators

OperatorRetained stateCan stop early?
.take(n)counteryes
.takeWhile(predicate)flagyes
.drop(n)counterno
.dropWhile(predicate)flagno
.flatMap(key)current nested iterableconsumer can stop
.unique(key)Set of distinct keysconsumer can stop
.chunk(n)at most n outputsconsumer can stop
.window(n)circular buffer of n itemsconsumer can stop
.pairwise()previous itemconsumer can stop
.scan({ initial, update })accumulatorconsumer can stop
.groupAdjacentBy(key)current groupconsumer can stop

unique is lazy, not constant-memory. groupAdjacentBy is constant in the number of groups but assumes equal keys are adjacent. window emits independent arrays so retaining one result is safe.

Output backends

const plan = JIT.query(Users)
  .filter((q) => q.eq("active", true))
  .select("id", "name")
  .take(10);

plan.compile(); // eager result array
plan.compileIterator(); // synchronous iterator
plan.compileAsyncIterator(); // async source/backpressure
plan.compileVisitor(); // callback sink, returns emitted count

Use eager arrays when most/all results are consumed and callers need random access. Use iterator for partial consumption or unbounded sources. Use async iterator for cursors, queues and streams. Use visitor for the lowest allocation hot sink when callback control is acceptable.

Physical fusion

Consecutive filter, select, take, drop, takeWhile, dropWhile, and unique nodes compile into one stage. The array backend uses an indexed loop. The direct visitor backend removes generator suspension and iterator result records entirely.

Cardinality-changing operators get isolated stages so their state stays local. explain(mode) reports barriers and retained structures:

plan.explain("generator");
// {
//   materializes: false,
//   earlyTermination: true,
//   retainedState: [],
//   barriers: []
// }

orderBy reports materializes: true. Lazy delivery cannot remove the global sort buffer. Consider a preordered source, ordered index, or bounded top-k algorithm when memory must remain bounded.

Binary queries

JIT.query(rowset) reuses the same condition AST for fixed-offset scans. It supports filter, projection and numeric aggregates. Only touched typed views and dictionaries are bound in generated source. String/literal filters resolve to integer dictionary IDs before the loop.

On this page