# πͺ QAIL β The Horizontal Query Language
> **Stop writing strings. Hook your data.**
[](https://crates.io/crates/qail)
[](LICENSE)
[](https://www.rust-lang.org/)
---
## The Manifesto
SQL is **vertical**, verbose, and clunky inside modern codebases.
QAIL is **horizontal**, dense, and composable. It treats database queries like a pipeline, using symbols to **hook** data and pull it into your application.
```sql
-- The Old Way (SQL)
SELECT id, email, role FROM users WHERE active = true LIMIT 1;
```
```bash
# The QAIL Way
get::usersβ’@id@email@role[active=true][lim=1]
```
One line. Zero ceremony. **Maximum velocity.**
### The Philosophy
1. **Constraint**: Vertical space is precious. SQL blocks interrupt the flow of code reading. QAIL flows *with* your logic.
2. **Density**: Symbols (`@`, `β’`, `[]`) convey more information per pixel than keywords (`SELECT`, `FROM`, `WHERE`).
3. **The Star Rule**: If you need 50 columns, fetch the struct (`@*`). If you need 3, list them. Listing 20 columns manually is an anti-pattern. QAIL encourages "all or nothing" density.
**Is it still Horizontal?**
Yes. The *language* itself is horizontal because it uses symbols instead of keywords. But we give you the **Vertical Escape Hatch** (tabs/newlines) so you can organize complex logic however you see fit, without fighting the parser. Horizontal is the *identity*; Vertical is the *layout*.
---
## π Quick Reference
| `::` | The Gate | Defines the action | `SELECT`, `INSERT`, `UPDATE` |
| `β’` | The Pivot | Connects action to table| `FROM table` |
| `@` | The Hook | Selects specific columns| `col1, col2` |
| `[]` | The Cage | Constraints & Filters | `WHERE`, `LIMIT`, `SET` |
| `~` | The Fuse | Fuzzy / Partial Match | `ILIKE '%val%'` |
| `\|` | The Split | Logical OR | `OR` |
| `&` | The Bind | Logical AND | `AND` |
| `^!` | The Peak | Sort Descending | `ORDER BY ... DESC` |
| `^` | The Rise | Sort Ascending | `ORDER BY ... ASC` |
| `*` | The Star | All / Wildcard | `*` |
| `[*]` | The Deep | Array Unnest | `UNNEST(arr)` |
| `$` | The Var | Parameter Injection | `$1`, `$2` |
---
## π Installation
### CLI (Recommended)
```bash
cargo install qail
```
### As a Library
```toml
# Cargo.toml
[dependencies]
qail = "0.1"
```
---
## π‘ Usage
### CLI β The `qail` Command
```bash
# Fetch all users
qail 'get::usersβ’@*'
# Get specific columns with filter
qail 'get::ordersβ’@id@total@status[user_id=$1][lim=10]' --bind 42
# Update a record
qail 'set::usersβ’[verified=true][id=$1]' --bind 7
# Delete with condition
qail 'del::sessionsβ’[expired_at<now]'
# Transpile only (don't execute)
qail 'get::usersβ’@*[active=true]' --dry-run
```
### As a Library
```rust
use qail::prelude::*;
#[tokio::main]
async fn main() -> Result<(), QailError> {
let db = QailDB::connect("postgres://localhost/mydb").await?;
// Parse and execute
let users: Vec<User> = db
.query("get::usersβ’@id@email@role[active=true][lim=10]")
.fetch_all()
.await?;
// Or use the builder for type-safe composition
let query = qail::get("users")
.hook(&["id", "email", "role"])
.cage("active", true)
.limit(10);
let users: Vec<User> = db.run(query).fetch_all().await?;
Ok(())
}
```
---
## π Syntax Deep Dive
### A. Simple Fetch (`get::`)
```sql
-- SQL
SELECT id, email, role FROM users WHERE active = true LIMIT 1;
```
```bash
# QAIL
get::usersβ’@id@email@role[active=true][lim=1]
```
---
### B. Mutation (`set::`)
```sql
-- SQL
UPDATE user_verifications SET consumed_at = now() WHERE id = $1;
```
```bash
# QAIL
set::user_verificationsβ’[consumed_at=now][id=$1]
```
> **Note:** In `set::` mode, the **first `[]`** is the payload (SET), the **second `[]`** is the filter (WHERE).
---
### C. Deletion (`del::`)
```sql
-- SQL
DELETE FROM sessions WHERE expired_at < now();
```
```bash
# QAIL
del::sessionsβ’[expired_at<now]
```
---
### D. Complex Search with Fuzzy Match
```sql
-- SQL
SELECT * FROM ai_knowledge_base
WHERE active = true
AND (topic ILIKE $1 OR question ILIKE $1 OR EXISTS (SELECT 1 FROM unnest(keywords) k WHERE k ILIKE $1))
ORDER BY created_at DESC
LIMIT 5;
```
```bash
# QAIL
get::ai_knowledge_baseβ’@*[active=true][topic~$1|question~$1|keywords[*]~$1][^!created_at][lim=5]
# Or multi-line for readability:
get::ai_knowledge_baseβ’@*
[active=true]
[topic~$1 | question~$1 | keywords[*]~$1]
[^!created_at]
[lim=5]
```
---
### E. Joins (Coming Soon)
```bash
# Inner join
get::ordersβ’@*>>users.id=orders.user_idβ’@users.email[status=paid]
# Left join
get::productsβ’@*>|categories.id=products.cat_idβ’@categories.name
```
---
## βοΈ Configuration
Create a `.qailrc` or `qail.toml` in your project root:
```toml
[connection]
[output]
[safety]
confirm_mutations = true # Prompt before UPDATE/DELETE
dry_run_default = false
```
---
## ποΈ Architecture
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β QAIL Pipeline β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β "get::usersβ’@*[active=true]" β
β β β
β βΌ β
β βββββββββββββββββββββββ β
β β Parser (nom) β β Tokenize symbols β
β βββββββββββ¬ββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββ β
β β AST (QailCmd) β β Structured representation β
β βββββββββββ¬ββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββ β
β β Transpiler (SQL) β β Generate valid SQL β
β βββββββββββ¬ββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββ β
β β Engine (sqlx) β β Execute against DB β
β βββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
### Core Structs
```rust
pub struct QailCmd {
pub action: Action, // GET, SET, DEL, ADD
pub table: String,
pub columns: Vec<Column>,
pub cages: Vec<Cage>, // Filters, limits, sorts
pub bindings: Vec<Value>,
}
pub enum Action {
Get, // SELECT
Set, // UPDATE
Del, // DELETE
Add, // INSERT
}
pub struct Cage {
pub kind: CageKind, // Filter, Limit, Sort, Payload
pub conditions: Vec<Condition>,
}
pub struct Condition {
pub column: String,
pub op: Operator, // Eq, Ne, Gt, Lt, Fuzzy, In
pub value: Value,
}
```
---
## πΊοΈ Roadmap
### Phase 1: Parser β
- [x] Lexer for QAIL symbols
- [x] `nom` parser combinators
- [x] AST generation
### Phase 2: Transpiler π§
- [x] PostgreSQL codegen
- [ ] MySQL codegen
- [ ] SQLite codegen
- [ ] Query optimization hints
### Phase 3: Engine π
- [ ] Async execution (sqlx)
- [ ] Connection pooling
- [ ] Transaction support
- [ ] Prepared statement caching
### Phase 4: Ecosystem π
- [ ] VS Code extension (syntax highlighting)
- [ ] Language server (LSP)
- [ ] REPL mode
- [ ] Schema introspection
### E. The Flagship Comparison (Complex Joins)
**Scenario**: Find verified users who joined after 2024 and booked under the 'SUMMER' campaign.
```sql
-- SQL (7 lines, cognitive load high)
SELECT u.*
FROM users u
JOIN bookings b ON b.user_id = u.id
WHERE u.created_at >= '2024-01-01'
AND u.email_verified = true
AND b.campaign_code ILIKE '%SUMMER%'
ORDER BY u.created_at DESC
LIMIT 50;
```
```bash
# QAIL (1 line, cognitive load low)
get::users->bookingsβ’@*[created_at>='2024-01-01'][email_verified=true][bookings.campaign_code~'SUMMER'][^!created_at][lim=50]
```
---
## π€ Contributing
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
```bash
# Clone the repo
git clone https://github.com/your-username/qail.git
cd qail
# Run tests
cargo test
# Run with example
cargo run -- "get::usersβ’@*[lim=5]" --dry-run
```
---
## π License
MIT Β© 2025 QAIL Contributors
---
<p align="center">
<strong>Built with π¦ Rust and β caffeine</strong><br>
<a href="https://qail.rs">qail.rs</a>
</p>