config di lifespan

main
Сергей Ванюшкин 2024-03-31 21:07:59 +03:00
parent 327ab86d1f
commit c809f14fdc
12 changed files with 115 additions and 9 deletions

View File

@ -10,11 +10,14 @@ from api.infrastructure.dependencies.adapters import (
new_session,
new_unit_of_work,
)
from api.infrastructure.dependencies.configs import app_settings
from api.infrastructure.dependencies.repositories import get_user_repository
from api.infrastructure.dependencies.usecases import provide_create_user
from api.infrastructure.settings import Settings
def init_dependencies(app: FastAPI) -> None:
app.dependency_overrides[Settings] = app_settings
app.dependency_overrides[AsyncEngine] = create_engine
app.dependency_overrides[async_sessionmaker[AsyncSession]] = create_session_maker
app.dependency_overrides[AsyncSession] = new_session

View File

@ -1,3 +1,6 @@
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from fastapi import FastAPI
from api.app_builder.dependencies import init_dependencies
@ -5,8 +8,16 @@ from api.app_builder.dependencies import init_dependencies
from .routers import init_routers
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator:
print("init lifespan")
yield
def app_factory() -> FastAPI:
app = FastAPI()
app = FastAPI(
lifespan=lifespan,
)
init_dependencies(app)
init_routers(app)

View File

@ -12,6 +12,7 @@ from sqlalchemy.ext.asyncio import (
from api.application.abstractions import UnitOfWork
from api.infrastructure.dependencies.stub import Stub
from api.infrastructure.persistence.uow import SqlAlchemyUnitOfWork
from api.infrastructure.settings import Settings
def new_unit_of_work(
@ -20,15 +21,16 @@ def new_unit_of_work(
return SqlAlchemyUnitOfWork(session)
def create_engine() -> AsyncEngine:
return create_async_engine("postgresql+asyncpg://postgresql+asyncpg//demo_user:user_pass@db:5432/serviceman_db")
def create_engine(
settings: Annotated[Settings, Depends(Stub(Settings))],
) -> AsyncEngine:
return create_async_engine(settings.db.db_url)
def create_session_maker(
engine: Annotated[AsyncEngine, Depends(Stub(AsyncEngine))],
) -> async_sessionmaker[AsyncSession]:
maker = async_sessionmaker(engine, expire_on_commit=False)
print("session_maker id:", id(maker))
return maker

View File

@ -0,0 +1,30 @@
import os
from functools import lru_cache
import yaml # type: ignore
from api.infrastructure.persistence.db_setings import DBSettings
from api.infrastructure.settings import Settings
def yaml_loader(file: str) -> dict[str, dict[str, str]]:
with open(file) as f:
yaml_data: dict = yaml.safe_load(f)
return yaml_data
@lru_cache
def app_settings() -> Settings:
config_data = yaml_loader(
file=os.getenv("CONFIG_PATH", "./config/api_config.yml"),
)
return Settings(
db=DBSettings(
pg_user=config_data["db"]["user"],
pg_pass=config_data["db"]["password"],
pg_host=config_data["db"]["host"],
pg_port=int(config_data["db"]["port"]),
pg_db=config_data["db"]["database"],
),
)

View File

@ -5,10 +5,11 @@ from fastapi import Depends
from api.application.abstractions.uow import UnitOfWork
from api.application.usecase.create_user import CreateUser
from api.domain.user.repository import UserRepository
from api.infrastructure.dependencies.stub import Stub
def provide_create_user(
user_repository: Annotated[UserRepository, Depends()],
user_repository: Annotated[UserRepository, Depends(Stub(UserRepository))],
uow: Annotated[UnitOfWork, Depends()],
) -> CreateUser:
return CreateUser(uow=uow, user_repository=user_repository)

View File

@ -0,0 +1,20 @@
from dataclasses import dataclass
@dataclass(frozen=True)
class DBSettings:
pg_user: str
pg_pass: str
pg_host: str
pg_port: int
pg_db: str
@property
def db_url(self) -> str:
return "postgresql+asyncpg://{}:{}@{}:{}/{}".format(
self.pg_user,
self.pg_pass,
self.pg_host,
self.pg_port,
self.pg_db,
)

View File

@ -0,0 +1,5 @@
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
...

View File

@ -0,0 +1,18 @@
import uuid
from sqlalchemy import UUID
from sqlalchemy.orm import Mapped, mapped_column
from api.infrastructure.persistence.models.base import Base
class UserModel(Base):
__tablename__ = "user"
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
primary_key=True,
)
name: Mapped[str]
email: Mapped[str] = mapped_column(unique=True)
hashed_password: Mapped[str]

View File

@ -1,6 +1,8 @@
from sqlalchemy import insert
from sqlalchemy.ext.asyncio import AsyncSession
from api.domain.user import User, UserRepository
from api.infrastructure.persistence.models.user import UserModel
class SqlAlchemyUserRepository(UserRepository):
@ -8,7 +10,13 @@ class SqlAlchemyUserRepository(UserRepository):
self.session = session
async def create_user(self, user: User) -> None:
pass
stmt = insert(UserModel).values(
id=user.id,
name=user.name,
email=user.email,
hashed_password=user.password,
)
await self.session.execute(stmt)
async def get_user(self, filter: dict) -> User | None:
pass

View File

@ -0,0 +1,8 @@
from dataclasses import dataclass
from api.infrastructure.persistence.db_setings import DBSettings
@dataclass()
class Settings:
db: DBSettings

View File

@ -14,8 +14,8 @@ async def get_all_users() -> list[UserResponse]:
return []
@user_router.post("/")
async def create_task(
@user_router.post("/", status_code=201)
async def create_user(
request: UserCreateRequest,
usecase: Annotated[CreateUser, Depends(Stub(CreateUser))],
) -> None:

View File

@ -1,5 +1,5 @@
db:
host: "localhost"
host: "db"
port: 5432
database: "serviceman_db"
user: "demo_user"