Async typed query builder and runtime for SQLite STRICT tables
Project description
snekql
snekql is a Python async-first query builder and query runtime for SQL. It gives applications explicit SQL-shaped operations, typed model declarations, runtime validation, startup schema checks, and transaction- based execution without becoming an ORM.
Quick start
from __future__ import annotations
from datetime import datetime
from pathlib import Path
from snekql import (
MISSING,
CurrentTimestamp,
Database,
DateTime,
Fetched,
Integer,
Model,
Pending,
Text,
insert,
select,
)
class User[S = Pending](Model[S, "User[Fetched]"]):
id: User.GenCol[int] = Integer(
primary_key=True,
auto_increment=True,
default=MISSING,
)
email: User.Col[str] = Text(nullable=False)
status: User.Col[str] = Text(nullable=False, default="active")
created_at: User.GenCol[datetime] = DateTime(
server_default=CurrentTimestamp(),
default=MISSING,
)
async def main() -> None:
db = await Database.initialize(
database=Path("app.db"),
models=[User],
schema_policy="strict",
pool_size=5,
acquire_timeout=30.0,
)
try:
async with db.transaction(timeout=5.0) as tx:
await tx.execute(insert(User(email="alice@example.com")))
user = await tx.fetch_one(
select(User).where(User.email.eq("alice@example.com")),
)
if user is not None:
print(user.email)
finally:
await db.close()
Model declaration
Models directly subclass Model[S, "ModelName[Fetched]"]. Application-created
instances are Pending; database reads return Fetched instances.
class AuditLog[S = Pending](Model[S, "AuditLog[Fetched]"]):
__tablename__ = "audit_log"
id: AuditLog.GenCol[int] = Integer(
primary_key=True,
auto_increment=True,
default=MISSING,
)
message: AuditLog.Col[str] = Text(nullable=False)
created_at: AuditLog.GenCol[datetime] = DateTime(
server_default=CurrentTimestamp(),
default=MISSING,
)
Rules to remember:
Col[T]is a normal persisted column.GenCol[T]is server/generated; pending values may beMISSING, fetched values areT.- If
__tablename__is omitted, class names become snake_case table names. - Models are immutable after construction/materialization.
- Fetched models are produced by database reads only.
Storage classes
IntegerRealTextBlobJsonstoresJSONtext.Booleanstores0/1in anINTEGERcolumn.DateTimestores UTC text asYYYY-MM-DDTHH:MM:SS.SSSZ.
CurrentTimestamp() is the only v1 server default and is valid only on
DateTime GenCol fields.
Queries
Queries are immutable. Chaining returns new query objects.
from snekql import delete, insert, select, update
select(User).all()
select(User.email).where(User.status.eq("active"))
select(User.email, User.status).where(User.email.like("%@example.com"))
insert(User(email="alice@example.com"))
update(User).set(User.status.to("disabled")).where(
User.email.eq("alice@example.com"),
)
delete(User).where(User.email.eq("retired@example.com"))
delete(User).all() # explicit full-table delete
Filtering is explicit: select, update, and delete must choose exactly one
of .where(...) or .all() before execution. Predicates use methods such as
.eq(...), .ne(...), .is_null(), .in_(...), .like(...); Python
comparison operators are not part of the v1 API.
Runtime
Database.initialize(...) is the only public construction path.
db = await Database.initialize(database=Path("app.db"), models=[User])
memory_db = await Database.initialize(database=":memory:")
Use transactions for all work:
async with db.transaction() as tx:
rows = await tx.fetch_all(select(User).all())
first_email = await tx.fetch_one(select(User.email).all())
await tx.execute(update(User).set(User.status.to("inactive")).all())
Runtime methods:
fetch_all(select(...))returns all result rows.fetch_one(select(...))returns the first row orNone.execute(insert/update/delete)returnsNone.close()is async and idempotent after a successful close.
Schema startup
When initialized with models=[...], snekql:
- Preserves model order.
- Rejects duplicate resolved table names.
- Creates missing
STRICTtables. - Verifies existing tables by comparing deterministic generated DDL with SQLite metadata.
- Treats drift according to
schema_policy:"strict"raises,"warn"logs and continues.
Error model
Every intentional package-originated exception is a SnekqlError subclass.
Use SnekqlError to catch all snekql failures, or catch narrower subclasses:
ModelDeclarationError,ModelValidationError,FrozenModelErrorQueryConstructionError,QueryCompilationErrorDatabaseClosedError,PoolTimeoutError,TransactionClosedError,ExecutionErrorSchemaVerificationError
ExecutionError preserves sql and params for debugging.
Public API
Agent navigation map:
snekql/model.py: model metaclass, table metadata, pending/fetched materialization.snekql/storage.py: column descriptors, SQLite storage metadata, value codecs.snekql/expressions.py: predicates, ordering, update assignments.snekql/query.py: query builders and SQL compilation.snekql/runtime.py:Database,Transaction, execution methods.snekql/_pool.py: internal async SQLite connection pool.snekql/schema.py:STRICTDDL generation and schema verification.snekql/errors.py: public exception hierarchy.tests/test_public_typing.py: type-checker prototypes for the public API.PRD.md: full v1 product contract.CONTEXT.md: project language and terminology.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file snekql-0.1.0.tar.gz.
File metadata
- Download URL: snekql-0.1.0.tar.gz
- Upload date:
- Size: 55.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c58b04e70d83a801fcc630bc69aa54223d9775d458bc55481bc5d7b5d44ce6b8
|
|
| MD5 |
66dc0e7d947dbd44bb5ae3722700091f
|
|
| BLAKE2b-256 |
9e27d9e770c16b089812165783d7f139b135c729b0e32a2863889a38a0930539
|
File details
Details for the file snekql-0.1.0-py3-none-any.whl.
File metadata
- Download URL: snekql-0.1.0-py3-none-any.whl
- Upload date:
- Size: 26.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
efb727b46d155a9b49309aa355b01adc7c79357a40b0dbdc7b81aaae319e1436
|
|
| MD5 |
427919ceb0d9d333e1de4b567b8f2087
|
|
| BLAKE2b-256 |
8aeff82211cc2c487de3e08e08f936722b5d35fc5abdbdf8922641534823feaa
|