impl
Qail::typed(users::table).join_related(products::table)
```
### 🛡️ Protected Columns
Compile-time data governance — sensitive columns require capability proof:
```rust
let admin_cap = CapabilityProvider::mint_admin(); // After JWT verification
Qail::get(users::table)
.with_cap(&admin_cap)
.column(users::email) // Public — always allowed
.column_protected(users::password_hash) // Protected — requires cap
```
---
## Qail Gateway
Auto-REST API server with zero backend code. Point it at a Postgres database, get a full API:
```
GET /api/{table}?expand=users&sort=-created_at&limit=10
GET /api/{table}/:id
POST /api/{table}
PATCH /api/{table}/:id
DELETE /api/{table}/:id
GET /api/{table}/_explain # EXPLAIN ANALYZE
GET /api/{table}/aggregate # count, sum, avg, min, max
```
**A complete REST API layer for PostgreSQL:**
- ✅ Auto-REST CRUD for all tables
- ✅ FK-based JOIN expansion (`?expand=`) + nested expansion
- ✅ Full-text search (`?search=`)
- ✅ WebSocket subscriptions + live queries
- ✅ Event triggers (mutation → webhook with retry)
- ✅ JWT auth (HS256/RS256) + API key auth
- ✅ Native access policy + column permissions
- ✅ Query allow-listing + complexity limits
- ✅ Prometheus metrics + request tracing
- ✅ NDJSON streaming + cursor pagination
- ✅ OpenAPI spec generation
---
## Architecture
```
qail.rs/
├── core/ AST engine, parser, validator, typed system, RLS, migrations
├── pg/ PostgreSQL driver (binary wire protocol, connection pool)
├── gateway/ Auto-REST API server (Axum)
├── cli/ qail exec, pull, diff, migrate, types
├── qdrant/ Qdrant vector DB driver (optional)
├── workflow/ Workflow engine
└── sdk/ Direct SDKs (TypeScript, Swift, Kotlin, Dart)
```
---
## SDK Status
| Platform | Status | Distribution |
|----------|--------|--------------|
| TypeScript | ✅ Supported | `npm install @qail/client` |
| Swift | ✅ Supported | Source package in `sdk/swift` |
| Kotlin | ✅ Supported | Gradle module in `sdk/kotlin` |
| Dart | ✅ Supported | Pub package in `sdk/dart` |
| Node.js native binding | ⏸ Deferred | Not shipped yet |
`tenant_id` is the runtime contract across gateway and RLS paths. Legacy
`agent_id`/operator-style identity is treated as a secondary scope only when a
tenant scope is already present.
---
## N+1 Detection
Compile-time static analysis catches query-in-loop patterns before they reach production. Powered by QAIL semantic Rust scanning (no `syn` dependency on the runtime analyzer path).
### Rules
| Code | Severity | Trigger | Example |
|------|----------|---------|---------|
| N1-001 | ⚠ Warning | Query inside `for`/`while`/`loop` | `for x in items { conn.fetch_all(&q) }` |
| N1-002 | ⚠ Warning | Loop variable used in query args | `for id in ids { Qail::get("t").eq("id", id) }` |
| N1-003 | ⚠ Warning | Function with query called in loop | `for x in xs { load_user(conn, x) }` |
| N1-004 | ❌ Error | Query in nested loop (depth ≥ 2) | `for g in groups { for x in g { ... } }` |
### Suppression
```rust
// Disable on the next line
// qail-lint:disable-next-line N1-001
conn.fetch_all(&cmd).await?;
// Disable inline
conn.fetch_all(&cmd).await?; // qail-lint:disable-line N1-001
```
### Build Integration (`build.rs`)
Runs automatically via `validate()` when using Qail's build-time checks:
| Env Var | Values | Default |
|---------|--------|---------|
| `QAIL_NPLUS1` | `off` \| `warn` \| `deny` | `warn` |
| `QAIL_NPLUS1_MAX_WARNINGS` | integer | `50` |
| `QAIL_SCAN_DIRS` | comma-separated source roots | `src` |
Monorepo example:
```bash
# Scan multiple Rust roots during build validation + N+1 checks
QAIL_SCAN_DIRS="src,apps/api/src,crates/billing/src" cargo build
```
### CLI
```bash
qail check schema.qail --src ./src # Shows N+1 warnings
qail check schema.qail --src ./src --nplus1-deny # Fails on any N+1
```
### LSP
N+1 diagnostics appear automatically in your editor for `.rs` files with diagnostic codes `N1-001`..`N1-004`.
### Remediation
```rust
// ❌ N+1: one query per item
for id in &ids {
let user = conn.fetch_one(&Qail::get("users").eq("id", id)).await?;
}
// ✅ Batch: single query
let users = conn.fetch_all(
&Qail::get("users").in_vals("id", &ids)
).await?;
```
---
## Feature Status (March 2026)
| Category | Features |
|----------|----------|
| **Core SQL** | SELECT, INSERT, UPDATE, DELETE, UPSERT, RETURNING, COPY |
| **Joins** | INNER, LEFT, RIGHT, FULL, CROSS, LATERAL, self-joins |
| **Advanced** | CTEs, Subqueries, EXISTS, Window Functions, UNION/INTERSECT/EXCEPT |
| **Types** | JSON/JSONB, Arrays, UUID, Timestamps, Enums, Composite |
| **Security** | RLS, TypedQail, Protected Columns, Capability Witnesses |
| **Migrations** | AST-native diffing, drift detection, impact analysis |
| **Schema** | Views, Materialized Views, Functions, Triggers, Extensions, Sequences, Grants |
| **Performance** | Connection Pool, Query Cache (LRU+TTL), Prepared Statements, Binary Protocol |
| **Connection** | SSL/TLS, SCRAM-SHA-256, Unix Socket |
| **Operations** | EXPLAIN ANALYZE, Statement Timeout, LOCK TABLE, Batch Transactions |
### Connection Pool Maintenance
Activate background pool health maintenance (idle connection cleanup + `min_connections` backfill) by calling `spawn_pool_maintenance` after creating the pool:
```rust
let pool = qail_pg::PgPool::connect(config).await?;
qail_pg::spawn_pool_maintenance(pool.clone());
```
---
## Documentation
- 📖 [Full Documentation](https://qail.rs/docs)
- 📊 [Benchmarks](https://qail.rs/benchmarks)
- 📋 [Changelog](CHANGELOG.md)
- 💡 [The Manifesto](https://qail.rs/philosophy)
---
## License
Apache-2.0 © 2025-2026 Qail Contributors
Built with 🦀 Rust
qail.rs