from __future__ import annotations from typing import Any from fastapi import HTTPException from backend.auth.dependencies import default_tenant_id _AUTH_USER_DIRECTORY_SCHEMA_CACHE_KEY = "_auth_user_directory_schema_ready" def _sql_text_literal(value: str) -> str: return "'" + value.replace("'", "''") + "'" async def ensure_user_directory_schema(app: Any) -> None: if getattr(app.state, _AUTH_USER_DIRECTORY_SCHEMA_CACHE_KEY, False): return pool = getattr(app.state, "db_pool", None) if pool is None: raise HTTPException(status_code=503, detail="Database unavailable.") tenant_fallback = default_tenant_id() tenant_default_literal = _sql_text_literal(tenant_fallback) async with pool.acquire() as conn: await conn.execute("ALTER TABLE users_and_roles ADD COLUMN IF NOT EXISTS tenant_id TEXT") await conn.execute( """ UPDATE users_and_roles SET tenant_id = $1 WHERE tenant_id IS NULL OR tenant_id = '' """, tenant_fallback, ) await conn.execute( f"ALTER TABLE users_and_roles ALTER COLUMN tenant_id SET DEFAULT {tenant_default_literal}" ) await conn.execute("ALTER TABLE users_and_roles ALTER COLUMN tenant_id SET NOT NULL") await conn.execute( "CREATE INDEX IF NOT EXISTS idx_users_tenant_active ON users_and_roles (tenant_id, is_active)" ) setattr(app.state, _AUTH_USER_DIRECTORY_SCHEMA_CACHE_KEY, True)