Skip to main content

Crate query_lang

Crate query_lang 

Source
Expand description

§query_lang

An incremental computation engine: a database that caches the results of derived queries, tracks what each result was computed from, and recomputes only what a change actually affects.

A compiler runs the same computation over and over as source is edited — parse a file, resolve its names, type-check its definitions, lower it to IR. Most edits touch a fraction of that work, yet a naive compiler redoes all of it on every keystroke. The query model, from Rust’s own salsa and rust-analyzer, turns each step into a query: a pure function whose result is memoized and whose dependencies are recorded as it runs. When an input changes, the engine invalidates only the queries that transitively read it, and reuses everything else. query-lang is that engine, and nothing more — it owns no compiler, no IR, no syntax; it is generic over the queries a consumer defines.

§The model

Three pieces:

  • A System is the definition of your queries: a Key type that names a query, a Value type it produces, and a compute function that derives one from the other.
  • A Database holds the System, stores your inputs, and caches the derived results. It is the engine: you set inputs and get results, and it handles caching, dependency tracking, and invalidation.
  • A get resolves a query. Called from application code it returns a result; called from inside a compute it reads a dependency, and the engine records that edge automatically.

An input is any key whose value you set directly; every other key is derived through compute. One Key type names both, so a query reads an input and another query the same way.

§Example

An input string, a query that parses it to a number, and a query that squares that number. Editing the input recomputes the chain; an edit that leaves the parsed number unchanged stops at the parse via early cutoff.

use query_lang::{Database, System, QueryError};

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
enum Key {
    Source,   // an input: the raw text
    Parsed,   // = Source parsed as i64
    Squared,  // = Parsed * Parsed
}

struct Pipeline;
impl System for Pipeline {
    type Key = Key;
    type Value = i64;
    fn compute(&self, db: &Database<Self>, key: &Key) -> Result<i64, QueryError> {
        match key {
            // `Source` is an input; this default only applies if it was unset.
            Key::Source => Ok(0),
            Key::Parsed => Ok(db.get(&Key::Source)?),
            Key::Squared => {
                let n = db.get(&Key::Parsed)?;
                Ok(n * n)
            }
        }
    }
}

let mut db = Database::new(Pipeline);
db.set(Key::Source, 12);
assert_eq!(db.get(&Key::Squared)?, 144);
assert_eq!(db.stats().computed, 2); // Source is a set input; Parsed and Squared ran

// Ask again with no edit: a hit, nothing recomputes.
assert_eq!(db.get(&Key::Squared)?, 144);
assert_eq!(db.stats().hits, 1);

§Features

  • std (default) — the standard library. Without it the crate is #![no_std] and needs only alloc; the engine itself uses no operating- system facilities either way.
  • serde — derives serde::Serialize for Revision and Stats so a database’s version and cache metrics can be logged or inspected.

§Stability

The public surface is frozen and stable as of 1.0.0: it follows Semantic Versioning, with no breaking changes before 2.0. The full surface, the semantic guarantees, and the SemVer promise are catalogued in docs/API.md.

Structs§

Database
An incremental query database: the store of inputs and the cache of derived results, with automatic dependency tracking and invalidation.
Revision
A monotonic version stamp for the database.
Stats
A snapshot of how a Database resolved its queries.

Enums§

QueryError
The error returned from Database::get and System::compute when a query cannot be resolved.

Traits§

System
The definition of a query system: how every derived query is computed.