The AST Protocol
One query language. Every layer.
QAIL lets you build queries as typed objects (AST), then sends protocol bytes to PostgreSQL. This removes app-side SQL string interpolation on the AST path and keeps RLS and validation centralized.
Plain English: your app builds a typed query object, not a hand-built SQL string. PostgreSQL still does normal parse/plan/execute on the server.
Qail::get("users")
.select_all()
.filter("active", Eq, true) SELECT * FROM users WHERE active = true { "must": [{ "key": "active", "match": true }] } cargo install qail zig fetch --save ...qail-zig/v0.2.0.tar.gz Native Rust โข Universal C-API โข FFI Bindings
Same query. Same database. Same 50-row result set with 3 JOINs.
100 iterations, release build, buffer cache warmed.
Snapshot run: February 2026.
QAIL executes one planned query on this path. Naive resolver/endpoint patterns can explode to 151 round-trips without join batching.
Four layers. One AST flows through all of them.
Parser, transpiler, type system. Queries are typed data structures, not hand-built SQL strings in app code. Schema validation at compile time.
get users fields id, email
where active = true
order by created_at desc
limit 10 Protocol-level PostgreSQL driver with typed values and built-in RLS context per connection.
let driver = PgDriver::connect_env().await?;
driver.set_rls_context(
RlsContext::operator("op-456")
).await?;
driver.fetch_all(&cmd).await? Zero-code API from your schema. Auto-REST with FK expansion, policy engine, WebSocket subscriptions, binary AST wire format.
GET /api/bookings
?status.eq=confirmed
&sort=created_at:desc
&expand=routes,payments
&limit=20 Declarative multi-step orchestration. Database queries, notifications, and events in typed state machines.
Workflow::new("booking")
.step("validate", validate_fn)
.step("charge", payment_fn)
.step("confirm", confirm_fn)
.on_error(rollback_fn) REST params, text queries, or binary AST all converge to the same AST. Policy injection and schema validation happen once. SQL text output is optional for tooling/debug views.
GET /api/users?active=true get users where active = true postcard::to_allocvec(&cmd) Qail { action: Get, table: "users", cages: [Filter(active = true)] } + injects AND operator_id = 'op-456' Encode AST โ Parse / Bind / Execute + typed bind values One AST. Two powerhouses. Cache built-in.
Relational โข Transactions โข ACID
Vector โข AI/ML โข Semantic Search
Moka โข TTL โข Zero Latency
Native packages for your language. All powered by one Rust core.
Pure Zig โข TLS โข Pool v0.2.0 cargo add qail-core Cargo 31K q/s โข 2.6x Eloquent GitHub 126K q/s โข 4.2x GORM GitHub 130K rows/s COPY GitHub FFI โข Native Addon GitHub The only migration tool that reads your code before it touches your data.
Searches .rs, .ts, .js, .py for queries that reference changing columns
Shows exactly where your code needs updating before migration
Use --force to override when you know better
One AST. Protocol bytes. Compile-time safety. Built-in RLS.