Skip to content

Commit 8e7ae45

Browse files
authored
refactor: simplify belgie database dependency wiring (#100)
1 parent 83215ca commit 8e7ae45

File tree

40 files changed

+336
-774
lines changed

40 files changed

+336
-774
lines changed

README.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,27 @@ class OAuthState(Base):
108108
### 2) Configure Belgie
109109

110110
```python
111+
from collections.abc import AsyncGenerator
112+
113+
from sqlalchemy.engine import URL
114+
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
115+
111116
from belgie import Belgie, BelgieSettings
112-
from belgie.oauth.google import GoogleOAuth
113-
from belgie.alchemy import SqliteSettings
114117
from belgie.alchemy import BelgieAdapter
118+
from belgie.oauth.google import GoogleOAuth
115119

116120
settings = BelgieSettings(
117121
secret="your-secret-key",
118122
base_url="http://localhost:8000",
119123
)
120124

121-
database = SqliteSettings(database="./app.db")
125+
engine = create_async_engine(URL.create("sqlite+aiosqlite", database="./app.db"))
126+
session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
127+
128+
129+
async def get_db() -> AsyncGenerator[AsyncSession, None]:
130+
async with session_maker() as session:
131+
yield session
122132

123133
adapter = BelgieAdapter(
124134
user=User,
@@ -130,7 +140,7 @@ adapter = BelgieAdapter(
130140
auth = Belgie(
131141
settings=settings,
132142
adapter=adapter,
133-
database=database,
143+
database=get_db,
134144
)
135145

136146
google_oauth_plugin = auth.add_plugin(

docs/configuration.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,18 @@ BELGIE_URLS_SIGNOUT_REDIRECT=/
177177
### Python Configuration
178178

179179
```python
180+
from collections.abc import AsyncGenerator
181+
182+
from sqlalchemy.engine import URL
183+
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
184+
180185
from belgie import (
181186
Belgie,
182187
BelgieSettings,
183188
CookieSettings,
184189
SessionSettings,
185190
URLSettings,
186191
)
187-
from belgie.alchemy import SqliteSettings
188192
from belgie.alchemy import BelgieAdapter
189193
from belgie.oauth.google import GoogleOAuth
190194

@@ -206,10 +210,17 @@ settings = BelgieSettings(
206210
),
207211
)
208212

209-
database = SqliteSettings(database="./app.db")
213+
engine = create_async_engine(URL.create("sqlite+aiosqlite", database="./app.db"))
214+
session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
215+
216+
217+
async def get_db() -> AsyncGenerator[AsyncSession, None]:
218+
async with session_maker() as session:
219+
yield session
220+
210221
adapter = BelgieAdapter(...)
211222

212-
belgie = Belgie(settings=settings, adapter=adapter, database=database)
223+
belgie = Belgie(settings=settings, adapter=adapter, database=get_db)
213224
belgie.add_plugin(
214225
GoogleOAuth(
215226
client_id="your-client-id",

docs/quickstart.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,12 @@ class OAuthState(Base):
7878
### 2. Configure Authentication
7979

8080
```python
81+
from collections.abc import AsyncGenerator
82+
83+
from sqlalchemy.engine import URL
84+
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
85+
8186
from belgie import Belgie, BelgieSettings
82-
from belgie.alchemy import SqliteSettings
8387
from belgie.alchemy import BelgieAdapter
8488
from belgie.oauth.google import GoogleOAuth
8589

@@ -90,7 +94,13 @@ settings = BelgieSettings(
9094
)
9195

9296
# Configure database
93-
database = SqliteSettings(database="./app.db")
97+
engine = create_async_engine(URL.create("sqlite+aiosqlite", database="./app.db"))
98+
session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
99+
100+
101+
async def get_db() -> AsyncGenerator[AsyncSession, None]:
102+
async with session_maker() as session:
103+
yield session
94104

95105
# Create adapter
96106
adapter = BelgieAdapter(
@@ -104,7 +114,7 @@ adapter = BelgieAdapter(
104114
auth = Belgie(
105115
settings=settings,
106116
adapter=adapter,
107-
database=database,
117+
database=get_db,
108118
)
109119
google_oauth_plugin = auth.add_plugin(
110120
GoogleOAuth(

docs/scopes.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,26 @@ your app is requesting and can approve or deny access.
2323
Configure scopes in your `GoogleOAuth`:
2424

2525
```python
26+
from collections.abc import AsyncGenerator
27+
28+
from sqlalchemy.engine import URL
29+
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
30+
2631
from belgie import Belgie, BelgieSettings
27-
from belgie.alchemy import SqliteSettings
2832
from belgie.alchemy import BelgieAdapter
2933
from belgie.oauth.google import GoogleOAuth
3034

3135
settings = BelgieSettings(secret="your-secret", base_url="http://localhost:8000")
32-
database = SqliteSettings(database="./app.db")
36+
engine = create_async_engine(URL.create("sqlite+aiosqlite", database="./app.db"))
37+
session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
38+
39+
40+
async def get_db() -> AsyncGenerator[AsyncSession, None]:
41+
async with session_maker() as session:
42+
yield session
43+
3344
adapter = BelgieAdapter(...)
34-
belgie = Belgie(settings=settings, adapter=adapter, database=database)
45+
belgie = Belgie(settings=settings, adapter=adapter, database=get_db)
3546
belgie.add_plugin(
3647
GoogleOAuth(
3748
client_id="your-client-id",

examples/auth/main.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
from collections.abc import AsyncIterator
1+
from collections.abc import AsyncGenerator, AsyncIterator
22
from contextlib import asynccontextmanager
33
from typing import Annotated
44

55
from brussels.base import DataclassBase
66
from fastapi import Depends, FastAPI, Security
77
from fastapi.responses import RedirectResponse
8+
from sqlalchemy.engine import URL
9+
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
810

911
from belgie import (
1012
Belgie,
@@ -13,19 +15,28 @@
1315
SessionSettings,
1416
URLSettings,
1517
)
16-
from belgie.alchemy import BelgieAdapter, SqliteSettings
18+
from belgie.alchemy import BelgieAdapter
1719
from belgie.oauth.google import GoogleOAuth, GoogleOAuthClient
1820
from examples.alchemy.auth_models import Account, OAuthState, Session, User
1921

20-
db_settings = SqliteSettings(database="./belgie_auth_example.db", echo=True)
22+
engine = create_async_engine(
23+
URL.create("sqlite+aiosqlite", database="./belgie_auth_example.db"),
24+
echo=True,
25+
)
26+
session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
27+
28+
29+
async def get_db() -> AsyncGenerator[AsyncSession, None]:
30+
async with session_maker() as session:
31+
yield session
2132

2233

2334
@asynccontextmanager
2435
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
25-
async with db_settings.engine.begin() as conn:
36+
async with engine.begin() as conn:
2637
await conn.run_sync(DataclassBase.metadata.create_all)
2738
yield
28-
await db_settings.engine.dispose()
39+
await engine.dispose()
2940

3041

3142
app = FastAPI(title="Belgie Example App", lifespan=lifespan)
@@ -58,7 +69,7 @@ async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
5869
belgie = Belgie(
5970
settings=settings,
6071
adapter=adapter,
61-
database=db_settings,
72+
database=get_db,
6273
)
6374
google_oauth_plugin = belgie.add_plugin(
6475
GoogleOAuth(

examples/mcp/main.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,17 @@
1212
from fastapi.responses import RedirectResponse
1313
from mcp.server.mcpserver import MCPServer
1414
from sqlalchemy import JSON, ForeignKey, Text, UniqueConstraint
15+
from sqlalchemy.engine import URL
16+
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
1517
from sqlalchemy.orm import Mapped, mapped_column, relationship
1618

1719
from belgie import Belgie, BelgieClient, BelgieSettings, CookieSettings, SessionSettings, URLSettings
18-
from belgie.alchemy import BelgieAdapter, SqliteSettings
20+
from belgie.alchemy import BelgieAdapter
1921
from belgie.mcp import Mcp, get_user_from_access_token
2022
from belgie.oauth.server import OAuthResource, OAuthServer
2123

2224
if TYPE_CHECKING:
23-
from collections.abc import AsyncIterator
25+
from collections.abc import AsyncGenerator, AsyncIterator
2426

2527

2628
class User(DataclassBase, PrimaryKeyMixin, TimestampMixin):
@@ -120,18 +122,27 @@ class OAuthState(DataclassBase, PrimaryKeyMixin, TimestampMixin):
120122
DB_PATH = "./belgie_mcp_example.db"
121123

122124

123-
db_settings = SqliteSettings(database=DB_PATH, echo=True)
125+
engine = create_async_engine(
126+
URL.create("sqlite+aiosqlite", database=DB_PATH),
127+
echo=True,
128+
)
129+
session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
130+
131+
132+
async def get_db() -> AsyncGenerator[AsyncSession, None]:
133+
async with session_maker() as session:
134+
yield session
124135

125136

126137
@asynccontextmanager
127138
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
128-
async with db_settings.engine.begin() as conn:
139+
async with engine.begin() as conn:
129140
await conn.run_sync(DataclassBase.metadata.create_all)
130141

131142
async with mcp_server.session_manager.run():
132143
yield
133144

134-
await db_settings.engine.dispose()
145+
await engine.dispose()
135146

136147

137148
app = FastAPI(title="Belgie MCP OAuth Example", lifespan=lifespan)
@@ -164,7 +175,7 @@ async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
164175
belgie = Belgie(
165176
settings=settings,
166177
adapter=adapter,
167-
database=db_settings,
178+
database=get_db,
168179
)
169180

170181
oauth_settings = OAuthServer(

examples/oauth/main.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
from collections.abc import AsyncIterator
1+
from collections.abc import AsyncGenerator, AsyncIterator
22
from contextlib import asynccontextmanager
33

44
from brussels.base import DataclassBase
55
from fastapi import FastAPI
6+
from sqlalchemy.engine import URL
7+
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
68

79
from belgie import (
810
Belgie,
@@ -11,22 +13,31 @@
1113
SessionSettings,
1214
URLSettings,
1315
)
14-
from belgie.alchemy import BelgieAdapter, SqliteSettings
16+
from belgie.alchemy import BelgieAdapter
1517
from belgie.oauth.server import OAuthServer
1618
from examples.alchemy.auth_models import Account, OAuthState, Session, User
1719

1820
DB_PATH = "./belgie_oauth_example.db"
1921

2022

21-
db_settings = SqliteSettings(database=DB_PATH, echo=True)
23+
engine = create_async_engine(
24+
URL.create("sqlite+aiosqlite", database=DB_PATH),
25+
echo=True,
26+
)
27+
session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
28+
29+
30+
async def get_db() -> AsyncGenerator[AsyncSession, None]:
31+
async with session_maker() as session:
32+
yield session
2233

2334

2435
@asynccontextmanager
2536
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
26-
async with db_settings.engine.begin() as conn:
37+
async with engine.begin() as conn:
2738
await conn.run_sync(DataclassBase.metadata.create_all)
2839
yield
29-
await db_settings.engine.dispose()
40+
await engine.dispose()
3041

3142

3243
app = FastAPI(title="Belgie OAuth Server Example", lifespan=lifespan)
@@ -59,7 +70,7 @@ async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
5970
belgie = Belgie(
6071
settings=settings,
6172
adapter=adapter,
62-
database=db_settings,
73+
database=get_db,
6374
)
6475

6576
oauth_settings = OAuthServer(

examples/oauth_client_plugin/main.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,38 @@
1-
from collections.abc import AsyncIterator
1+
from collections.abc import AsyncGenerator, AsyncIterator
22
from contextlib import asynccontextmanager
33
from typing import Annotated
44

55
from brussels.base import DataclassBase
66
from fastapi import Depends, FastAPI, Security
77
from fastapi.responses import RedirectResponse
8+
from sqlalchemy.engine import URL
9+
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
810

911
from belgie import Belgie, BelgieSettings, CookieSettings, SessionSettings, URLSettings
10-
from belgie.alchemy import BelgieAdapter, SqliteSettings
12+
from belgie.alchemy import BelgieAdapter
1113
from belgie.oauth.google import GoogleOAuth, GoogleOAuthClient
1214
from examples.alchemy.auth_models import Account, OAuthState, Session, User
1315

1416
DB_PATH = "./belgie_oauth_client_example.db"
1517

16-
db_settings = SqliteSettings(database=DB_PATH, echo=True)
18+
engine = create_async_engine(
19+
URL.create("sqlite+aiosqlite", database=DB_PATH),
20+
echo=True,
21+
)
22+
session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
23+
24+
25+
async def get_db() -> AsyncGenerator[AsyncSession, None]:
26+
async with session_maker() as session:
27+
yield session
1728

1829

1930
@asynccontextmanager
2031
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
21-
async with db_settings.engine.begin() as conn:
32+
async with engine.begin() as conn:
2233
await conn.run_sync(DataclassBase.metadata.create_all)
2334
yield
24-
await db_settings.engine.dispose()
35+
await engine.dispose()
2536

2637

2738
app = FastAPI(title="Belgie OAuth Client Plugin Example", lifespan=lifespan)
@@ -54,7 +65,7 @@ async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
5465
belgie = Belgie(
5566
settings=settings,
5667
adapter=adapter,
57-
database=db_settings,
68+
database=get_db,
5869
)
5970

6071
google_oauth_plugin = belgie.add_plugin(

0 commit comments

Comments
 (0)