Architecture
Ryx is built in three layers, each with a clear responsibility.
Layer Diagramโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Python Layer (ryx/) โ
โ Model ยท QuerySet ยท Q ยท Fields ยท Validators ยท Signals โ
โ Transactions ยท Relations ยท Migrations ยท CLI โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ PyO3 Boundary (ryx-python crate) โ
โ QueryBuilder ยท TransactionHandle ยท Type Bridge ยท Async โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Modular Query Engine (ryx-query crate) โ
โ AST ยท Q-Trees ยท SQL Compiler ยท Lookup Registry โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Backend Logic (ryx-backend crate) โ
โ Executor ยท RowView ยท Decoding Logic โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Core Types (ryx-core crate) โ
โ Connection & Transaction Enums ยท Base Traits โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ sqlx 0.8.6 + tokio 1.40 โ
โ AnyPool ยท Async Drivers ยท Transactions โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ PostgreSQL ยท MySQL ยท SQLite โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Query Execution Flowโ
Python: Post.objects.filter(active=True).order_by("-views").limit(10)
โ
โผ
QuerySet builds QueryNode (immutable builder pattern)
โ
โผ
PyQueryBuilder.fetch_all() โ crosses PyO3 boundary (ryx-python)
โ
โผ
compiler::compile(&QueryNode) โ CompiledQuery { sql, values } (ryx-query)
โ
โผ
executor::fetch_all(compiled) โ sqlx::query(sql).bind(values).fetch_all(pool) (ryx-backend)
โ
โผ
decode_rows(AnyRow) โ Vec<RowView> (Zero-allocation) (ryx-backend)
โ
โผ
RowView โ PyDict (ryx-python)
โ
โผ
Model._from_row(row) โ List[Model]
Key Design Decisionsโ
Performance Firstโ
Ryx is designed for extreme throughput. It avoids expensive abstractions in the hot path:
- Enum Dispatch: Replaces
dyntraits to eliminate vtable lookups and enable inlining. - Zero-Allocation Rows: Replaces
HashMapwithRowViewto reduce allocator pressure. - GIL Minimization: Performs all DB operations and decoding in pure Rust.
For a detailed breakdown, see Performance Optimizations.
Immutable Buildersโ
Both Python QuerySet and Rust QueryNode use immutable builders โ every method returns a new instance:
// Rust: self by value, not &mut self
pub fn add_filter(self, field: &str, lookup: &str, value: SqlValue) -> Self { ... }
# Python: returns new QuerySet
def filter(self, **kwargs) -> "QuerySet":
clone = self._clone()
clone.builder.add_filter(...)
return clone
GIL Minimizationโ
The Rust executor holds no Python GIL during SQL execution:
- Decode
AnyRowโHashMap<String, JsonValue>(no GIL) - Convert
HashMapโPyDict(brief GIL hold at boundary) - Python wraps
PyDictโModelinstances
ContextVar Transaction Propagationโ
Active transactions use contextvars.ContextVar โ they propagate through async call stacks automatically:
async with ryx.transaction():
await some_function() # Uses the same transaction
await another_function() # Still in the same transaction
AnyPool Over Typed Poolsโ
sqlx::any::AnyPool provides a single code path for all backends:
- Pro: One codebase, runtime database selection
- Con: No compile-time query checking
- Trade-off: Worth it for a dynamic ORM
Next Stepsโ
โ Rust Core โ Deep dive into each Rust module