qail-macro

Crates.ioqail-macro
lib.rsqail-macro
version0.8.10
created_at2025-12-20 18:32:12.872375+00
updated_at2025-12-23 15:19:34.752698+00
descriptionProcedural macros for QAIL - compile-time validated database queries
homepage
repositoryhttps://github.com/qail-rs/qail
max_upload_size
id1996829
size41,242
Scope Sage (VerysignVL)

documentation

README

🪝 QAIL — The Universal Query Transpiler

Safe but Free. Write queries once. Run them everywhere. Zero lock-in.

Crates.io npm License


Why QAIL?

For years, developers have been trapped between two choices:

  1. Raw SQL — Maximum freedom, but dangerous strings scattered across your codebase.
  2. ORMs / Query Builders — Maximum safety, but a "prison" of boilerplate and language lock-in.

QAIL is the third way.

"I originally built QAIL for internal use to solve my own headaches. But I realized that other engineers shouldn't have to suffer through the same 'Database Dilemma'. That's why I decided to open-source it." — The Creator

We moved validation from the networking layer to the grammar level. By treating queries as a compiled language instead of raw strings, QAIL provides compile-time safety with the freedom of raw SQL.

  • No language lock-in — Same syntax in Rust, Node.js, Go, Python, PHP
  • No heavy dependencies — Pure logic, zero networking code
  • No "big bang" migration — Adopt incrementally, one query at a time
  • Works with your existing driver — SQLx, pg, PDO, psycopg2, etc.
-- SQL (The Assembly)
SELECT id, email FROM users WHERE active = true LIMIT 10;
# QAIL (The Source Code)
get::users:'id'email [ 'active == true, 0..10 ]

One line. Zero ceremony. Runs everywhere.


🚀 Installation

Rust (Native)

cargo install qail
[dependencies]
qail-core = "0.8"

Node.js / Browser (WASM)

npm i qail-wasm

💡 Usage

Rust

use qail_core::prelude::*;

// Parse and transpile
let sql = parse("get::users:'id'email [ 'active == true ]")?.to_sql();
// Returns: "SELECT id, email FROM users WHERE active = true"

// Use with your existing driver (sqlx, diesel, etc.)
let users = sqlx::query_as::<_, User>(&sql)
    .fetch_all(&pool)
    .await?;

JavaScript / TypeScript

import { parseAndTranspile } from 'qail-wasm';

const sql = parseAndTranspile("get::users:'id'email [ 'active == true ]");
// Returns: "SELECT id, email FROM users WHERE active = true"

// Use with your existing driver (pg, mysql2, etc.)
const result = await client.query(sql);

📖 Quick Reference

Symbol Name Function Example
:: The Gate Action (get/set/del/add) get::
: The Link Connect table to columns users:'id
' The Label Mark a column 'email'name
'_ The Wildcard All columns users:'_
[ ] The Cage Constraints block [ 'active == true ]
== The Equal Equality check 'status == "active"
~ The Fuse Fuzzy match (ILIKE) 'name ~ "john"
| The Split Logical OR 'a == 1 | 'b == 2
& The Bind Logical AND 'a == 1 & 'b == 2
+/- Sort Order ASC/DESC -created_at
N..M The Range Pagination 0..10
$ The Var Parameter placeholder $1
! The Unique DISTINCT get!::
<- Left Join LEFT JOIN users<-profiles
-> Inner Join INNER JOIN users->orders

📚 Examples

Basic SELECT

get::users:'id'email [ 'active == true ]
# → SELECT id, email FROM users WHERE active = true

All Columns

get::users:'_
# → SELECT * FROM users

Sorting & Pagination

get::users:'_ [ -created_at, 0..10 ]
# → SELECT * FROM users ORDER BY created_at DESC LIMIT 10

Fuzzy Search

get::users:'id'name [ 'name ~ "john" ]
# → SELECT id, name FROM users WHERE name ILIKE '%john%'

UPDATE

set::users:[ status = "active" ] [ 'id == $1 ]
# → UPDATE users SET status = 'active' WHERE id = $1

DELETE

del::users:[ 'id == $1 ]
# → DELETE FROM users WHERE id = $1

JOINs

get::users<-profiles:'name'avatar
# → SELECT name, avatar FROM users LEFT JOIN profiles ON ...

📦 Schema Management (Migrations)

Create and modify tables with the same concise syntax.

Create Table (make::)

make::users:'id:uuid^pk'email:varchar^unique^comment("User email")
# → CREATE TABLE users (id UUID PRIMARY KEY, email VARCHAR(255) UNIQUE);
# → COMMENT ON COLUMN users.email IS 'User email'

Constraints & Defaults

make::posts:'id:uuid^pk'status:varchar^def("draft")'views:int^def(0)
# → CREATE TABLE posts (
#     id UUID PRIMARY KEY,
#     status VARCHAR(255) DEFAULT 'draft',
#     views INT DEFAULT 0
# )

Composite Constraints

make::bookings:'user_id:uuid'slot_id:uuid^unique(user_id, slot_id)
# → CREATE TABLE bookings (..., UNIQUE (user_id, slot_id))

Create Index (index::)

index::idx_email^on(users:'email)^unique
# → CREATE UNIQUE INDEX idx_email ON users (email)

🌐 One Syntax. Every Stack.

QAIL provides multiple integration paths:

Platform Package Description
Rust qail-core Native crate, zero overhead
Node.js / Browser qail-wasm WebAssembly module (~50KB)
C / C++ libqail Universal C-API for FFI
Python, Go, PHP, Java via C-API/FFI Native bindings available

The C-API Advantage

Instead of building separate bindings for each language, we expose a Universal C-API (libqail). Any language with FFI support can call QAIL directly.

Installation (Linux/macOS):

  1. Download libqail-v0.8.0.tar.gz from Releases.
  2. Install header and library:
    sudo cp include/qail.h /usr/local/include/
    sudo cp lib/libqail_ffi.so /usr/local/lib/  # .dylib on macOS
    sudo ldconfig # Linux only
    

Usage (C/C++): Compile with -lqail_ffi:

#include <qail.h>
// ...
// char* sql = qail_transpile("get::users:'_");

Usage (Python):

from ctypes import cdll
lib = cdll.LoadLibrary("libqail_ffi.so") # or .dylib
# ...

Usage (Go):

/*
#cgo LDFLAGS: -lqail_ffi
#include <qail.h>
*/
import "C"
// ...

🤝 Contributing

We welcome contributions!

git clone https://github.com/qail-rs/qail.git
cd qail
cargo test

📄 License

MIT © 2025 QAIL Contributors


Built with 🦀 Rust
qail.rs

Commit count: 0

cargo fmt