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 = {
17            slug: SqliteConfig(connection_config={"database": ":memory:"}, bind_key=slug) for slug in tenants
18        }
19
20    def insert_article(self, slug: str, title: str) -> None:
21        config = self._configs[slug]
22        with config.provide_session() as session:
23            session.execute(
24                """
25                CREATE TABLE IF NOT EXISTS articles (
26                    id INTEGER PRIMARY KEY AUTOINCREMENT,
27                    title TEXT NOT NULL
28                )
29                """
30            )
31            session.execute("INSERT INTO articles (title) VALUES (:title)", {"title": title})
32
33    def list_titles(self, slug: str) -> "list[str]":
34        config = self._configs[slug]
35        with config.provide_session() as session:
36            result = session.execute(SQL("SELECT title FROM articles ORDER BY id"))
37            return [row["title"] for row in result.all()]
38
39
40def main() -> None:
41    """Insert one record per tenant and print the isolated results."""
42    router = TenantRouter(TENANTS)
43    router.insert_article("acme", "Acme onboarding")
44    router.insert_article("orbital", "Orbital checklist")
45    payload: dict[str, list[str]] = {slug: router.list_titles(slug) for slug in TENANTS}
46    print(payload)
47
48
49if __name__ == "__main__":
50    main()