HomeQuery LabExpressionsDocsDriversBlogStatusRoadmapChangelog GitHub

Protocol-First Data Layer

Typed query AST from app to database.

QAIL builds queries as typed objects and encodes them as protocol bytes. No hand-built SQL interpolation on the AST path, with RLS and validation still enforced where they belong.

1 AST for API, driver, and database
146.9us loopback median (`RTT=0`, canonical 50-row payload)
RLS Native policy context remains in PostgreSQL
Rust cargo install qail
Zig zig fetch --save ...qail-zig/v0.2.0.tar.gz

First-party drivers and SDKs: Rust, Zig, TypeScript, Swift, Kotlin · Node.js native binding deferred · Latest stable: v0.27.0 (March 25, 2026)

Live Query Shape Protocol path overview
QAIL AST
Qail::get("users")
    .select_all()
    .filter("active", Eq, true)
encode + bind
POSTGRESQL SELECT * FROM users WHERE active = $1
QDRANT { "must": [{ "key": "active", "match": true }] }
RustRust ZigZig

Benchmark Snapshot: Pattern Cost vs RTT

Same endpoint objective, same canonical 50-row payload (`id`, `name`, `origin_harbor`, `dest_harbor`), same PostgreSQL dataset. Query shape: 2x LEFT JOIN (`odyssey_connections` + `harbors`). Snapshot run: March 25, 2026 (`--release`, 200 iterations, equivalence gate enabled).

Loopback (`BATTLE_SIMULATED_RTT_US=0`)
Approach Median p95 DB queries
GraphQL + DataLoader 146.8us 168.0us 2
QAIL AST (uncached) 146.9us 163.7us 1
REST + `?expand=` 164.5us 186.3us 1
GraphQL naive (N+1) 4.74ms 4.88ms 101
Simulated RTT (`BATTLE_SIMULATED_RTT_US=1000`)
Approach Median p95 DB queries
QAIL AST (uncached) 1237.8us 1252.5us 1
REST + `?expand=` 1248.4us 1262.5us 1
GraphQL + DataLoader 2287.0us 2507.0us 2
GraphQL naive (N+1) 111.56ms 112.19ms 101

Signal: loopback hides round-trip differences; as RTT increases, one-query plans outperform multi-query fan-out.

View full methodology and raw output →

The QAIL Stack

One core engine (qail-core) with three execution branches on the same typed AST.

qail-core

Core Engine

Parser, transpiler, and type system. Queries stay as typed data structures with schema validation before runtime execution.

get users fields id, email
  where active = true
  order by created_at desc
  limit 10

qail-pg

PostgreSQL Driver

Protocol-native PostgreSQL execution path with typed bind values, RLS context propagation, and deterministic query planning.

let driver = PgDriver::connect_env().await?;
driver.fetch_all(&cmd).await?

qdrant

Vector Driver

Typed vector and filter operations mapped to Qdrant RPC with one AST execution contract shared with SQL paths.

driver.search_points(&cmd).await?;
driver.filter_points(&cmd).await?

qail-gateway

API Runtime

HTTP and WebSocket surface over the same AST path, with policy checks, FK expansion, and structured response shaping.

GET /api/bookings
    ?status.eq=confirmed
    &sort=created_at:desc
    &expand=routes,payments
    &limit=20

Every Entry Point → One Pipeline

Request adapters normalize REST parameters, text DSL, and binary payloads into one typed AST. Validation, policy rewriting, planning, and encoding run through the same execution path before driver dispatch.

REST Adapter
GET /api/users?active=true
Text Adapter
get users where active = true
Binary Adapter
postcard::to_allocvec(&cmd)
Normalized AST
Qail { action: Get, table: "users", cages: [Filter(active = true)] }
Policy + Validation Stage
rewrite: active = true AND tenant_id = $ctx.tenant_id
Planner + Encoder Stage
compile AST to driver-specific protocol frames and typed bind values
PostgreSQL Driver Path
Parse / Bind / Execute
Qdrant Driver Path
Filter + Vector Search RPC

Supported Databases

Two production databases, one typed AST, plus built-in cache for hot paths.

PostgreSQL

PostgreSQL

Relational • Transactions • ACID

Production
Qdrant

Qdrant

Vector • AI/ML • Semantic Search

Production

QAIL Vector Driver →

Native Cache

Moka • TTL • Zero Latency

Built-in

Language Drivers

Production drivers: Zig and Rust. Direct SDKs: TypeScript (@qail/client), Swift, and Kotlin. Node.js native binding is deferred.

View all drivers → Dedicated SDK page →

Migration Guardrails and Safety Checks

Deterministic migration execution with policy validation, signed receipts, and explicit unsafe override controls.

migration-check.log
$ qail migrate down --target 20260324 --wait-for-lock

ABORTED: guardrail violation

check.non_tty_confirmation = failed
check.receipt_signature    = failed
check.schema_drift         = passed

next_step: verify receipt integrity and rerun with --force --confirm <token>

Static Query Impact Scan

Parses `.rs`, `.ts`, `.js`, and `.py` sources to detect references to columns affected by a migration.

Exact Diagnostic Output

Emits file and line-level diagnostics so affected call-sites can be fixed before migration execution.

Explicit Override Path

Requires --force plus maintainer confirmation before bypassing failed guardrails.

The data layer you don't write.

One AST. Protocol bytes. Compile-time safety. Built-in RLS.