STREAMING.md¶
Design notes — read the user guide first
For day-to-day use see Streaming guide. Shipped
policies include raise, collect, skip, log, callback, and quarantine
(0.6.0). Prefer Rejection policies.
RowGuard Streaming¶
Purpose¶
Streaming allows RowGuard to process arbitrarily large result sets without materializing every validated model in memory.
Instead of returning a complete QueryResult, the streaming API validates,
classifies, and yields rows incrementally.
Streaming is intended for:
ETL pipelines
Batch processing
Data migration
Analytics
Large exports
Long-running services
Philosophy¶
Streaming should preserve the same correctness guarantees as buffered execution.
Every processed row must still become either:
A validated Pydantic model, or
A rejected row handled by the configured rejection policy.
The only difference is when models are delivered.
Pipeline¶
Execution Plan
│
▼
Execute SQL
│
▼
Read Next Row
│
▼
Row Adapter
│
▼
Validation Engine
│
├── Valid Model ─────► yield
└── Rejected Row
│
▼
Reject Handler
Rows are processed independently.
Public API¶
with rowguard.stream(
session=session,
table=users,
model=UserRead,
) as stream:
for model in stream:
process(model)
Bare for model in stream also closes the underlying result when the loop
ends or breaks. Prefer the context manager when combining early exit with
post-stream inspection of statistics / rejected.
Shipped async API (0.4.0+; ORM async in 0.5):
async with rowguard.astream(...) as stream:
async for model in stream:
...
See Async architecture and the async guide.
StreamResult¶
Streaming should expose an object that is iterable and accumulates execution metadata.
Suggested interface:
stream = rowguard.stream(...)
for model in stream:
...
stats = stream.statistics
rejected = stream.rejected
The stream object should not pretend to be a completed QueryResult.
Rejection Policies¶
Streaming supports the same policies as buffered execution.
raise¶
Stop iteration immediately.
collect¶
Retain rejected rows until the stream completes.
skip¶
Continue without retaining the rejected row.
callback¶
Invoke the callback before reading the next row.
quarantine¶
Forward rejected rows to the configured quarantine provider.
Statistics¶
Streaming statistics should update continuously.
Suggested metrics:
rows_read
rows_valid
rows_rejected
execution_time
validation_time
throughput
Statistics become final when iteration completes.
Backpressure¶
Streaming should naturally respect consumer speed.
RowGuard should not prefetch large batches unless explicitly configured.
Future option:
batch_size=500
Resource Management¶
Streaming should cleanly release database resources.
Recommended usage:
with rowguard.stream(...) as stream:
for model in stream:
...
Async:
async with rowguard.astream(...) as stream:
async for model in stream:
...
Context managers help guarantee cursor cleanup.
Error Handling¶
Execution errors terminate the stream.
Validation failures follow the configured rejection policy.
Unexpected adapter or engine failures should close the stream and release resources.
Ordering¶
Streaming preserves database row order.
Rejected rows retain their original sequence number.
Memory Goals¶
Streaming should avoid retaining:
all validated models
duplicate row mappings
unnecessary diagnostics
Only configured rejection retention should consume additional memory.
Extension Points¶
Future plugins may provide:
progress reporting
throughput monitoring
adaptive batching
checkpointing
resumable streams
Testing¶
Streaming tests should verify:
ordering
resource cleanup
rejection handling
statistics
sync/async parity
cancellation
large result sets
MVP Scope¶
Initial release:
synchronous streaming
SQLAlchemy 2.x
validation per row
rejection policies
statistics
Deferred:
adaptive batching
resumable execution
distributed streaming
Design Principles¶
Constant-memory processing.
Preserve validation guarantees.
Release resources promptly.
Maintain deterministic ordering.
Match buffered semantics wherever practical.