Protocol-First Data Layer
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.
cargo install qail 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)
Qail::get("users")
.select_all()
.filter("active", Eq, true) SELECT * FROM users WHERE active = $1 { "must": [{ "key": "active", "match": true }] } 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).
Signal: loopback hides round-trip differences; as RTT increases, one-query plans outperform multi-query fan-out.
One core engine (qail-core) with three execution branches on the same typed AST.
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 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? 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? 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 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.
GET /api/users?active=true get users where active = true postcard::to_allocvec(&cmd) Qail { action: Get, table: "users", cages: [Filter(active = true)] } rewrite: active = true AND tenant_id = $ctx.tenant_id compile AST to driver-specific protocol frames and typed bind values Parse / Bind / Execute Filter + Vector Search RPC Two production databases, one typed AST, plus built-in cache for hot paths.
Relational • Transactions • ACID
ProductionMoka • TTL • Zero Latency
Built-inProduction drivers: Zig and Rust. Direct SDKs: TypeScript (@qail/client), Swift, and Kotlin. Node.js native binding is deferred.
Deterministic migration execution with policy validation, signed receipts, and explicit unsafe override controls.
Parses `.rs`, `.ts`, `.js`, and `.py` sources to detect references to columns affected by a migration.
Emits file and line-level diagnostics so affected call-sites can be fixed before migration execution.
Requires --force plus maintainer confirmation before bypassing failed guardrails.
One AST. Protocol bytes. Compile-time safety. Built-in RLS.