Connection & Registry¶
Functions for managing database connections and the global model registry. connect() registers a (optionally named) connection pool; reset_engine() tears everything down; the registry helpers control schema creation and the identity map. Sessionized routing is exposed via ferro.engines.session(name) / ferro.Session. See the Connections & Databases guide.
Session
dataclass
¶
Source code in src/ferro/session.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | |
Attributes¶
connection_name = None
class-attribute
instance-attribute
¶
session_id = None
class-attribute
instance-attribute
¶
Functions¶
__aenter__()
async
¶
Source code in src/ferro/session.py
__aexit__(exc_type, exc, tb)
async
¶
close()
async
¶
Close this session and release its runtime state.
Safe to call from a different asyncio context than __aenter__.
Repeated calls are no-ops.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the ambient session in this asyncio context does not match this handle (same-context lifecycle misuse), or if session-scoped transactions are still open. |
Source code in src/ferro/session.py
query(model_cls)
¶
__init__(connection_name=None, session_id=None, _token=None, _enter_context=None, _enter_task=None, _close_lock=None)
¶
connect(url, auto_migrate=False, name=None, default=False, pool=None, *, identity_map=True, migrate_updates=False, migrate_destructive=False)
async
¶
Establish a connection to the database.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The database connection string (e.g., "sqlite:example.db?mode=rwc"). |
required |
auto_migrate
|
bool
|
If True, automatically create tables for all registered models.
Existing tables are left completely untouched — whatever their shape —
unless |
False
|
name
|
str | None
|
Optional connection name. Omitted connections register as "default". |
None
|
default
|
bool
|
If True, make this named connection the default for unqualified operations. |
False
|
pool
|
PoolConfig | None
|
Optional per-connection pool configuration. |
None
|
identity_map
|
bool
|
If True (default), sessions opened on this connection keep an identity
map so the same primary key maps to a single Python instance within a session.
Identity maps are session-scoped: operations outside a session never cache or
dedup instances. If False, loads on this connection return fresh instances even
inside a session (lower memory use; no |
True
|
migrate_updates
|
bool
|
If True, additionally update existing tables to match the
registered models. Implies
After any schema change, the connection pool is refreshed so no cached statement can observe the pre-migration schema. |
False
|
migrate_destructive
|
bool
|
If True, additionally drop live columns that no
longer exist on the model (never whole tables). Implies
|
False
|
Raises:
| Type | Description |
|---|---|
ValueError
|
A connection with this name (or a default connection,
when |
For schema changes beyond these (renames, primary-key changes, complex
transforms), use the Alembic bridge — see docs/guide/migrations.md.
Source code in src/ferro/__init__.py
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | |
PoolConfig
¶
Bases: BaseModel
Connection pool settings for a named Ferro connection.
Source code in src/ferro/__init__.py
set_default_connection(name)
¶
Source code in src/ferro/_core.pyi
create_tables(using=None)
async
¶
Manually create the missing tables for registered models on a connected
engine. A table that already exists is left completely untouched; altering
existing tables belongs to migrate(updates=True).
Compiles and pushes the current registry SchemaIR to the Rust runtime
before delegating to the Rust create entrypoint, so a model defined after
connect() (and thus absent from the connect-time snapshot) is still
created. The runtime emits each CREATE TABLE from this SchemaIR via the
shared emitter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
using
|
Named connection to create tables on, or None for the default. |
None
|
Source code in src/ferro/__init__.py
migrate(using=None, updates=True, destructive=False)
async
¶
Manually run the auto-migrate pass against a connected engine.
Compiles and pushes the current registry SchemaIR to the Rust runtime, then delegates to the Rust migrate entrypoint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
using
|
Named connection to migrate, or None for the default. |
None
|
|
updates
|
If True (default), add missing columns and reconcile
type, nullability, and foreign-key definition drift (see |
True
|
|
destructive
|
If True, also drop live columns absent from the model. Implies |
False
|
Source code in src/ferro/__init__.py
clear_registry()
¶
Reset the compiled/registered schema state.
Delegates to the Rust core (which clears the Rust model registry and the
pushed SchemaIR modelset) and additionally clears the Python join-table
registry. That registry must be reset here because
connect/create_tables/migrate compile the full registry via
compile_registry_schema_ir(): a join table left behind by a prior run
would be re-created with foreign keys to tables that no longer exist —
tolerated by SQLite but rejected by Postgres (relation ... does not
exist). (#153)
The Python model registry is intentionally not cleared here: clearing
the Rust registry while keeping the declared Python models is what allows
cold re-hydration after reset_engine (see
tests/test_enum_cold_hydration.py). Callers that want a full
Python-side reset use REGISTRY.reset_for_test().
Each purged join table's compiled SchemaIR envelope is evicted with it —
Registry.clear_join_tables owns that agreement (#153): a lingering
join envelope would let a future assemble step resurrect the stale join
table.
Source code in src/ferro/__init__.py
evict_instance(model, pk, *, using=None, session=None)
¶
Remove one instance from the active scope's identity map.
model is a model class, its qualified identity, or an unambiguous
bare class name (ambiguity raises with the candidates listed).
Public wrapper around the FFI evict_instance (FF-D D3): resolves the
route once via resolve_operation_scope, then passes it through. Model
instance methods (save/delete/refresh) call the FFI symbol
directly with their already-resolved route instead of going through this
wrapper, so a route is never resolved twice for one operation.