Scaffold a Zig-Native DB Route
Create database routes that execute entirely in Zig — no Python, no GIL.
Supports CRUD auto-generation, custom SQL, and standalone TurboPG usage.
Steps
- Determine the table: Use
$ARGUMENTS[0] as the table name
- Determine the mode:
$ARGUMENTS[1] — crud (default), query for custom SQL, or standalone for TurboPG
- Ensure
configure_db is called before any db routes
CRUD mode (auto-generated SQL)
from turboapi import TurboAPI
from dhi import BaseModel, Field
app = TurboAPI()
app.configure_db("postgres://user:pass@localhost/mydb", pool_size=16)
class User(BaseModel):
name: str = Field(min_length=1, max_length=100)
email: str
age: int = Field(gt=0)
@app.db_get("/users/{user_id}", table="users", pk="id")
def get_user(): pass
@app.db_list("/users", table="users")
def list_users(): pass
@app.db_post("/users", table="users", model=User)
def create_user(): pass
@app.db_delete("/users/{user_id}", table="users", pk="id")
def delete_user(): pass
Custom query mode (any SQL — pgvector, JSONB, FTS, JOINs, CTEs)
# Full-text search
@app.db_query("GET", "/search", sql="""
SELECT id, title, ts_rank(tsv, plainto_tsquery('english', $1)) AS rank
FROM articles WHERE tsv @@ plainto_tsquery('english', $1)
ORDER BY rank DESC LIMIT $2
""", params=["q", "limit"])
def search(): pass
# pgvector nearest neighbors
@app.db_query("GET", "/similar/{item_id}", sql="""
SELECT id, name, 1 - (embedding <=> (SELECT embedding FROM items WHERE id = $1)) AS sim
FROM items ORDER BY embedding <=> (SELECT embedding FROM items WHERE id = $1) LIMIT $2
""", params=["item_id", "limit"])
def similar(): pass
# JSONB filter
@app.db_query("GET", "/admins", sql="""
SELECT id, name, metadata->>'plan' AS plan
FROM users WHERE metadata @> '{"role": "admin", "active": true}'
""")
def admins(): pass
# Multi-table JOIN + aggregation
@app.db_query("GET", "/users/{user_id}/stats", sql="""
SELECT u.name, count(DISTINCT p.id) AS posts, sum(o.total) AS revenue
FROM users u LEFT JOIN posts p ON u.id = p.user_id
LEFT JOIN orders o ON u.id = o.user_id WHERE u.id = $1
GROUP BY u.name
""", params=["user_id"], single=True)
def user_stats(): pass
# Array column query
@app.db_query("GET", "/posts/tagged", sql="""
SELECT id, title, tags FROM posts WHERE $1 = ANY(tags) LIMIT 10
""", params=["tag"])
def tagged(): pass
Standalone TurboPG mode (no TurboAPI needed)
from turbopg import Database
db = Database("postgres://user:pass@localhost/mydb")
users = db.query("SELECT * FROM users WHERE age > $1 LIMIT $2", [18, 10])
user = db.query_one("SELECT * FROM users WHERE id = $1", [42])
affected = db.execute("INSERT INTO users (name, email) VALUES ($1, $2)", ["Alice", "a@b.com"])
with Database("postgres://...") as db:
result = db.query("SELECT count(*) as n FROM users")
Performance notes
- Cached reads: ~130k req/s (30s TTL, per-table invalidation, thread-safe, LRU)
- Writes invalidate cache: POST/DELETE clear only the affected table's cache entries
- Prepared statements: auto-enabled, skip SQL parse on repeat queries
- Unix sockets: use
host=/var/run/postgresql for ~50% less latency
- SIMD: JSON string escaping uses @Vector(16, u8) for bulk copy
- pgvector: SIMD float32 batch decode, auto-detected in results
- All Postgres types: int, float, numeric, bool, JSON/JSONB, TEXT[], INT[], timestamps
Type support via pg.zig fork (justrach/pg.zig)
The forked pg.zig includes writeJsonRow() which handles every Postgres type:
- Integers (int2/int4/int8) → JSON numbers
- Floats (float4/float8) → JSON numbers
- Numeric/Decimal → f64
- Bool → true/false
- JSON → passthrough
- JSONB → nested JSON objects (not escaped strings)
- TEXT[] →
["a", "b"]
- INT[] →
[1, 2, 3]
- Timestamps → epoch strings
- pgvector →
[0.1, 0.2, 0.3]
1---2name: turbo-db-route3description: Scaffold Zig-native database routes using pg.zig + TurboPG. Use when adding database-backed CRUD endpoints, custom SQL queries (pgvector, JSONB, full-text search, JOINs, CTEs), or standalone TurboPG usage.4---56# Scaffold a Zig-Native DB Route78Create database routes that execute entirely in Zig — no Python, no GIL.9Supports CRUD auto-generation, custom SQL, and standalone TurboPG usage.1011## Steps12131. **Determine the table**: Use `$ARGUMENTS[0]` as the table name142. **Determine the mode**: `$ARGUMENTS[1]` — `crud` (default), `query` for custom SQL, or `standalone` for TurboPG153. **Ensure `configure_db` is called** before any db routes1617## CRUD mode (auto-generated SQL)1819```python20from turboapi import TurboAPI21from dhi import BaseModel, Field2223app = TurboAPI()24app.configure_db("postgres://user:pass@localhost/mydb", pool_size=16)2526class User(BaseModel):27 name: str = Field(min_length=1, max_length=100)28 email: str29 age: int = Field(gt=0)3031@app.db_get("/users/{user_id}", table="users", pk="id")32def get_user(): pass3334@app.db_list("/users", table="users")35def list_users(): pass3637@app.db_post("/users", table="users", model=User)38def create_user(): pass3940@app.db_delete("/users/{user_id}", table="users", pk="id")41def delete_user(): pass42```4344## Custom query mode (any SQL — pgvector, JSONB, FTS, JOINs, CTEs)4546```python47# Full-text search48@app.db_query("GET", "/search", sql="""49 SELECT id, title, ts_rank(tsv, plainto_tsquery('english', $1)) AS rank50 FROM articles WHERE tsv @@ plainto_tsquery('english', $1)51 ORDER BY rank DESC LIMIT $252""", params=["q", "limit"])53def search(): pass5455# pgvector nearest neighbors56@app.db_query("GET", "/similar/{item_id}", sql="""57 SELECT id, name, 1 - (embedding <=> (SELECT embedding FROM items WHERE id = $1)) AS sim58 FROM items ORDER BY embedding <=> (SELECT embedding FROM items WHERE id = $1) LIMIT $259""", params=["item_id", "limit"])60def similar(): pass6162# JSONB filter63@app.db_query("GET", "/admins", sql="""64 SELECT id, name, metadata->>'plan' AS plan65 FROM users WHERE metadata @> '{"role": "admin", "active": true}'66""")67def admins(): pass6869# Multi-table JOIN + aggregation70@app.db_query("GET", "/users/{user_id}/stats", sql="""71 SELECT u.name, count(DISTINCT p.id) AS posts, sum(o.total) AS revenue72 FROM users u LEFT JOIN posts p ON u.id = p.user_id73 LEFT JOIN orders o ON u.id = o.user_id WHERE u.id = $174 GROUP BY u.name75""", params=["user_id"], single=True)76def user_stats(): pass7778# Array column query79@app.db_query("GET", "/posts/tagged", sql="""80 SELECT id, title, tags FROM posts WHERE $1 = ANY(tags) LIMIT 1081""", params=["tag"])82def tagged(): pass83```8485## Standalone TurboPG mode (no TurboAPI needed)8687```python88from turbopg import Database8990db = Database("postgres://user:pass@localhost/mydb")9192users = db.query("SELECT * FROM users WHERE age > $1 LIMIT $2", [18, 10])93user = db.query_one("SELECT * FROM users WHERE id = $1", [42])94affected = db.execute("INSERT INTO users (name, email) VALUES ($1, $2)", ["Alice", "a@b.com"])9596with Database("postgres://...") as db:97 result = db.query("SELECT count(*) as n FROM users")98```99100## Performance notes101102- **Cached reads**: ~130k req/s (30s TTL, per-table invalidation, thread-safe, LRU)103- **Writes invalidate cache**: POST/DELETE clear only the affected table's cache entries104- **Prepared statements**: auto-enabled, skip SQL parse on repeat queries105- **Unix sockets**: use `host=/var/run/postgresql` for ~50% less latency106- **SIMD**: JSON string escaping uses @Vector(16, u8) for bulk copy107- **pgvector**: SIMD float32 batch decode, auto-detected in results108- **All Postgres types**: int, float, numeric, bool, JSON/JSONB, TEXT[], INT[], timestamps109110## Type support via pg.zig fork (justrach/pg.zig)111112The forked pg.zig includes `writeJsonRow()` which handles every Postgres type:113- Integers (int2/int4/int8) → JSON numbers114- Floats (float4/float8) → JSON numbers 115- Numeric/Decimal → f64116- Bool → true/false117- JSON → passthrough118- JSONB → nested JSON objects (not escaped strings)119- TEXT[] → `["a", "b"]`120- INT[] → `[1, 2, 3]`121- Timestamps → epoch strings122- pgvector → `[0.1, 0.2, 0.3]`