Multi-Tenant Router

Route requests to dedicated SQLite configs per tenant slug.

uv run python docs/examples/patterns/multi_tenant/router.py

Source

 1"""Dispatch requests to dedicated SQLite configs per tenant."""
 2
 3from sqlspec.adapters.sqlite import SqliteConfig
 4from sqlspec.core import SQL
 5
 6__all__ = ("TenantRouter", "main")
 7
 8
 9TENANTS: "tuple[str, ...]" = ("acme", "orbital")
10
11
12class TenantRouter:
13    """Maintain isolated SqliteConfig instances for each tenant slug."""
14
15    def __init__(self, tenants: "tuple[str, ...]") -> None:
16        self._configs = {slug: SqliteConfig(pool_config={"database": ":memory:"}, bind_key=slug) for slug in tenants}
17
18    def insert_article(self, slug: str, title: str) -> None:
19        config = self._configs[slug]
20        with config.provide_session() as session:
21            session.execute(
22                """
23                CREATE TABLE IF NOT EXISTS articles (
24                    id INTEGER PRIMARY KEY AUTOINCREMENT,
25                    title TEXT NOT NULL
26                )
27                """
28            )
29            session.execute("INSERT INTO articles (title) VALUES (:title)", {"title": title})
30
31    def list_titles(self, slug: str) -> "list[str]":
32        config = self._configs[slug]
33        with config.provide_session() as session:
34            result = session.execute(SQL("SELECT title FROM articles ORDER BY id"))
35            return [row["title"] for row in result.all()]
36
37
38def main() -> None:
39    """Insert one record per tenant and print the isolated results."""
40    router = TenantRouter(TENANTS)
41    router.insert_article("acme", "Acme onboarding")
42    router.insert_article("orbital", "Orbital checklist")
43    payload: dict[str, list[str]] = {slug: router.list_titles(slug) for slug in TENANTS}
44    print(payload)
45
46
47if __name__ == "__main__":
48    main()