# SQLAlchemy source notes Repo: `sqlalchemy/sqlalchemy` Local checkout: `/home/ubuntu/repos/rodin-sources/sqlalchemy` ## Why this repo is useful - SQLAlchemy is a strong source for persistence-boundary patterns: explicit session lifetime, transaction visibility, and parallel sync/async APIs. - It is especially useful because the examples make lifecycle boundaries visible in ordinary calling code rather than hiding them in framework glue. ## Sync and async persistence APIs are parallel but distinct ### Repeated evidence - `examples/asyncio/async_orm.py:15-18` imports async-specific engine and session primitives. - `examples/asyncio/async_orm.py:51-67` builds an async engine and `async_sessionmaker(...)`, then enters an async session and transaction block explicitly. - `examples/inheritance/joined.py:7-17` imports sync engine/session primitives separately. - `examples/inheritance/joined.py:90-120` uses `Session(engine)` with explicit add/commit calls in the synchronous path. ### Why it matters Repeated signal: SQLAlchemy does not pretend sync and async persistence are the same execution model. The APIs are conceptually parallel, but the entrypoints stay distinct. ### Caveat / counterexample The useful pattern is not "keep two unrelated APIs." `examples/asyncio/async_orm.py:78-79` explicitly notes that async execution uses the same 2.0-style ORM execution concepts as the sync API. The separation is at runtime model and lifecycle, not at overall mental model. ## Session and transaction lifetime are made visible in calling code ### Repeated evidence - `examples/asyncio/async_orm.py:56-59` uses `engine.begin()` blocks for schema setup. - `examples/asyncio/async_orm.py:65-74` nests `session.begin()` inside `async_session()` so write scope is easy to see. - `examples/inheritance/joined.py:93-120` uses `with Session(engine) as session:` and makes the write boundary explicit with `session.add(...)` followed by `session.commit()`. - `examples/inheritance/joined.py:133-135` shows a later mutation followed by another explicit `session.commit()` rather than hidden autoflush-as-commit semantics. ### Why it matters Repeated signal: SQLAlchemy favors visible unit-of-work boundaries. You can usually point to the exact lines where a session starts, a transaction begins, and persistence becomes durable. ## Async examples surface async-specific caveats instead of hiding them ### Repeated evidence - `examples/asyncio/async_orm.py:61-63` calls out `expire_on_commit=False` and explains the post-commit attribute-expiration consequence directly. - `examples/asyncio/async_orm.py:75-80` notes that eager loading should be applied for relationship loading in the async example. - `examples/asyncio/async_orm.py:106-107` shows the explicit `AsyncAttrs` path for lazy-loaded relationships via `awaitable_attrs`. ### Why it matters Repeated signal: the async API is not just a renamed sync API. SQLAlchemy documents where async changes loading and object-lifetime behavior, which is exactly the kind of caveat future synthesis should preserve. ## Pattern candidates supported by this repo - keep sync and async persistence entrypoints distinct but conceptually parallel - make session and transaction scope visible in user code - use explicit commit boundaries for writes - preserve async-specific loading/lifecycle caveats rather than smoothing them over