Home Expressions
Docs
Drivers Gateway SDKs Benchmarks
Changelog
GitHub
Blog Status Roadmap

The AST Data Protocol

One Typed AST. Infinite Possibilities.

QAIL keeps queries on a strictly-typed AST path from your application to the database wire. It removes repository boilerplate, preserves security invariants, and gives you instant AutoREST/WebSocket gateways or ultra-fast Rust and Zig runtimes when you need raw database performance.

1 Unified AST Shared contract from application down to the driver
Fewer Layers No mandatory repository layer just to express safe data access
Bare-Metal Zero-overhead Rust and pure-Zig native drivers
Rust cargo install qail
Zig zig fetch --save ...qail-zig/v0.8.3.tar.gz

Official Support: Rust, Zig, TypeScript, Swift, Kotlin · Latest stable: qail.rs v1.1.0 · qail-zig v0.8.3 · View performance reports at /benchmarks.

Live Query Shape Protocol path overview
QAIL AST Rust
let cmd = Qail::get("users")
    .select_all()
    .filter("active", Eq, true);
encode + bind
PostgreSQL Wire Protocol
SELECT * FROM users WHERE active = $1
Qdrant gRPC Filter
{ "must": [{ "key": "active", "match": true }] }
RustRust ZigZig

How It Looks in Real Code

Same requirement, three coding styles. ORM starts from objects, SQL starts from strings, and QAIL starts from typed AST commands.

Same Read Query
ORM (Object / Class)
class=class="cc-str">"cc-cm">// ORM (object/class first)
const users = await prisma.user.findMany({
  where: { active: true },
  select: { id: true, email: true },
  take: class="cc-num">10,
});
SQL (Manual Text)
-- SQL (manual text)
SELECT id, email
FROM users
WHERE active = $1
LIMIT $2;
QAIL (Typed AST)
let cmd = Qail::get(class="cc-str">"users")
    .columns([class="cc-str">"id", class="cc-str">"email"])
    .eq(class="cc-str">"active", true)
    .limit(class="cc-num">10);

let rows = driver.fetch_all(&cmd).await?;
Tenant / RLS Handling
ORM (Per Query Discipline)
class=class="cc-str">"cc-cm">// ORM: team must enforce tenant filter per query
const tenantId = auth.tenant_id;

const bookings = await prisma.booking.findMany({
  where: { tenant_id: tenantId, status: class="cc-str">"paid" },
  select: { id: true, total: true },
});
SQL (Session + WHERE Discipline)
-- SQL: explicit session + policy discipline
SET LOCAL app.current_tenant_id = $1;

SELECT id, total
FROM bookings
WHERE tenant_id = $1
  AND status = 'paid';
QAIL (Context + AST Guard)
let ctx = RlsContext::tenant(tenant_id);

let cmd = Qail::get(class="cc-str">"bookings")
    .columns([class="cc-str">"id", class="cc-str">"total"])
    .eq(class="cc-str">"status", class="cc-str">"paid")
    .with_rls(&ctx)?;

let rows = driver.fetch_all(&cmd).await?;

The backend layer you can delete

Stop Writing Repositories for Simple CRUD

In many backends, repository and service classes exist mostly to hide string SQL, ORM shape, tenant filters, and response expansion rules. QAIL moves those concerns into typed AST commands, policy checks, gateway expansion, and driver execution. You keep the domain logic that matters, and remove the pass-through data plumbing.

Traditional Stack

Controller → Service → Repository → ORM
// Typical backend layering
router.get("/bookings", auth, async (req) => {
  const rows = await bookingService.listPaid(req.tenant.id);
});

class BookingService {
  listPaid(tenantId) {
    return bookingRepository.findPaidByTenant(tenantId);
  }
}

class BookingRepository {
  findPaidByTenant(tenantId) {
    return db.booking.findMany({
      where: { tenant_id: tenantId, status: "paid" },
    });
  }
}

QAIL Stack

Route or Gateway → Typed AST → Driver
// QAIL path
router.get("/bookings", auth, async (req) => {
  let ctx = RlsContext::tenant(req.tenant_id);

  let cmd = Qail::get("bookings")
      .columns(["id", "total", "status"])
      .eq("status", "paid")
      .with_rls(&ctx)?;

  return driver.fetch_all(&cmd).await?;
});

What disappears

Repository Boilerplate

Repository classes that only wrap single SQL queries.

Pass-Through Services

Service methods that only pass parameters downward.

Manual RLS/WHERE Discipline

Manual tenant filter rules repeated across every query file.

API Route Boilerplate

Entire route handlers when AutoREST already maps to the same AST path.

The point is not "no architecture". Keep domain services for pricing, workflows, payments, authorization decisions, and side effects. Delete the repository layer when it is only translating safe data intent into another query shape.

Core Architecture

QAIL provides specialized, production-ready execution environments. Use qail.rs for multi-entry API gateways and vector integrations, or qail-zig for uncompromising low-level database driver performance. Review the full methodology in the transparent benchmarks.

The diagram below illustrates the shared AST pipeline flowing through the qail.rs architecture.

Core Engine

qail-core

Parser, transpiler, and type system. Queries are parsed into typed Abstract Syntax Trees (AST) with schema validation before dispatch.

Live AST Input
get users fields id, email
  where active = true
  limit 10
AST Compiler Diagnostic
{
  "action": "Get",
  "table": "users",
  "columns": ["id", "email"],
  "filters": [{"active": true}]
}
Postgres Driver

qail-pg

Protocol-native PostgreSQL execution. Compiles AST into binary protocol frames with automatic tenant isolation policies.

SQL Output Preview
SELECT id, email FROM users
WHERE active = true
  AND tenant_id = $1;
Vector Search

qdrant

Vector and semantic query translation. Maps filter conditions to Qdrant key-match RPC models using the same pipeline contract.

RPC Payload Preview
"filter": {
  "must": [
    { "key": "active", "match": { "value": true } }
  ]
}
REST & WebSocket

qail-gateway

Automatic API surface gateway. Exposes direct AST mappings, automatic relation expansion, and instant HTTP route definitions.

HTTP Request Preview
GET /api/users
  ?active.eq=true
  &limit=10
Benchmark Highlight

qail.rs now leads the latest canonical native-DSL PostgreSQL matrix against pgx on 14 of 15 throughput slices, all five p50 latency slices, and four of five p99 slices, while qail-zig leads the current matched Zig driver comparison against pg.zig on its own benchmark page. Review the full methodology and raw output in the benchmark index.


Every Entry Point → One Pipeline

Request adapters cleanly normalize REST parameters, text DSL expressions, and binary payloads into one strictly-typed AST. Validation, policy enforcement, query planning, and wire encoding all securely run through the same unified pipeline before database dispatch.

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

The qail.rs core platform targets two production databases with 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

Official SDK Integrations

Integrate effortlessly using our official drivers and client SDKs. We provide robust, type-safe tooling for Rust, Zig, TypeScript, Swift, and Kotlin out of the box.

PostgreSQL drivers → Gateway page → SDK page →


Migration Guardrails and Safety Checks

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

migration-check.log Guardrail Violation
$ 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.