Validation-first SQLAlchemy queries with Pydantic row validation.
Project description
RowGuard
Validation-first database queries for SQLAlchemy and Pydantic.
RowGuard executes SQLAlchemy queries, validates every returned row against a Pydantic model, and explicitly handles rows that fail validation.
Status
0.3.0 — synchronous streaming via stream() / StreamResult, context-managed
cleanup, SQLAlchemy stream_results / yield_per, and progress observers.
Async streaming remains deferred to 0.4.0; ORM remains deferred to 0.5.0.
Install
pip install rowguard
Requires Python 3.10+, Pydantic v2, SQLAlchemy 2.x, and SQLRules.
Quickstart
from typing import Annotated
from pydantic import BaseModel, Field
from sqlalchemy import Column, Integer, MetaData, String, Table, create_engine
from sqlalchemy.orm import Session
import rowguard
class UserRead(BaseModel):
id: int
name: str
age: Annotated[int, Field(ge=18)]
metadata = MetaData()
users = Table(
"users",
metadata,
Column("id", Integer, primary_key=True),
Column("name", String),
Column("age", Integer),
)
engine = create_engine("sqlite+pysqlite:///:memory:")
metadata.create_all(engine)
with engine.begin() as connection:
connection.execute(
users.insert(),
[
{"id": 1, "name": "Ada", "age": 37},
{"id": 2, "name": "Legacy", "age": 12},
],
)
with Session(engine) as session:
# Disable SQLRules pushdown so invalid rows reach Pydantic and appear in rejected.
result = rowguard.select(
session=session,
table=users,
model=UserRead,
on_reject="collect",
use_sqlrules=False,
)
print(result.models)
print(result.rejected)
with rowguard.stream(
session=session,
table=users,
model=UserRead,
on_reject="skip",
use_sqlrules=False,
) as stream:
for model in stream:
print(model)
With use_sqlrules=True (the default), supported constraints such as age >= 18
are pushed into SQL, so invalid candidate rows may never be returned.
Public API (0.3.0)
| Function | Purpose |
|---|---|
select(...) |
Build and execute a table query with validation |
execute(...) |
Validate rows from an existing Select |
validate_rows(...) |
Validate mappings without SQL |
compile_plan(...) |
Compile an ExecutionPlan without executing |
stream(...) |
Stream validated models without buffering accepted rows |
Rejection policies: raise (default), collect, skip.
Optional planning knobs: compiled_rules= (precompiled SQLRules), strict=
(Pydantic), field_map= / column_map= (validated at plan time).
Streaming knobs: yield_per=, observers= (StreamObserver / BaseStreamObserver).
Architecture
Pydantic Model
│
▼
SQLRules
│
▼
SQLAlchemy Query
│
▼
Database
│
▼
Row Adapter
│
▼
Pydantic Validation
│
├── Accepted Model
└── Rejected Row
Documentation
- SPEC.md — product specification
- API.md — public API
- ARCHITECTURE.md — layered design
- ROADMAP.md — release plan
- docs/ — detailed design notes
Development
pip install -e ".[dev,async]"
make all # ruff + mypy + pytest --cov
python examples/basic.py
python examples/streaming.py
License
MIT
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 rowguard-0.3.0.tar.gz.
File metadata
- Download URL: rowguard-0.3.0.tar.gz
- Upload date:
- Size: 190.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c73efe3b31c45c4779140fcfa604e19c2efaf0cb2b754f345edcc45c47d838d9
|
|
| MD5 |
7ad9e3f94a261babdc422d6059252308
|
|
| BLAKE2b-256 |
bc37df5eada94f32babbb655d49a5311d5dd8e227efdd3b51dad32213220c674
|
File details
Details for the file rowguard-0.3.0-py3-none-any.whl.
File metadata
- Download URL: rowguard-0.3.0-py3-none-any.whl
- Upload date:
- Size: 30.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f014197013e967c1a205bdba66e742814d9f9db5736cbfd783920f90bb6fa8d
|
|
| MD5 |
c15552a0cd5f05dbdddb46f9241693b4
|
|
| BLAKE2b-256 |
081e587f6be390f8d2990439b0243f16e1cc382b827826c50b832ed91b8b2d34
|