3.3 KiB
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-18imports async-specific engine and session primitives.examples/asyncio/async_orm.py:51-67builds an async engine andasync_sessionmaker(...), then enters an async session and transaction block explicitly.examples/inheritance/joined.py:7-17imports sync engine/session primitives separately.examples/inheritance/joined.py:90-120usesSession(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-59usesengine.begin()blocks for schema setup.examples/asyncio/async_orm.py:65-74nestssession.begin()insideasync_session()so write scope is easy to see.examples/inheritance/joined.py:93-120useswith Session(engine) as session:and makes the write boundary explicit withsession.add(...)followed bysession.commit().examples/inheritance/joined.py:133-135shows a later mutation followed by another explicitsession.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-63calls outexpire_on_commit=Falseand explains the post-commit attribute-expiration consequence directly.examples/asyncio/async_orm.py:75-80notes that eager loading should be applied for relationship loading in the async example.examples/asyncio/async_orm.py:106-107shows the explicitAsyncAttrspath for lazy-loaded relationships viaawaitable_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