""" app/tenancy/routing.py ---------------------- RoutingSession — the per-request tenant-aware SQLAlchemy session. Subclasses Flask-SQLAlchemy's own Session so that all existing behaviour (default bind, __bind_key__ resolution) is preserved. The ONLY change: when a tenant engine has been selected for the current request (g.tenant_engine, set by the resolver middleware), every query binds to that engine instead. When no tenant engine is present — multi-tenancy disabled, an exempt path, a CLI invocation, or any non-request context — this falls through to the normal Flask-SQLAlchemy behaviour, i.e. the app's configured default database. This makes the routing layer completely inert until a tenant is actually resolved, so the existing single-tenant deployment is unaffected. """ from flask import g, has_app_context from flask_sqlalchemy.session import Session as _FlaskSQLAlchemySession class RoutingSession(_FlaskSQLAlchemySession): def get_bind(self, mapper=None, clause=None, bind=None, **kwargs): # Respect an explicitly supplied bind (engine-targeted operations). if bind is None and has_app_context(): tenant_engine = g.get('tenant_engine', None) if tenant_engine is not None: return tenant_engine return super().get_bind(mapper=mapper, clause=clause, bind=bind, **kwargs)