gitignore
parent
83bea97f41
commit
fb7e64f738
|
@ -60,7 +60,7 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne
|
||||||
# are written from script.py.mako
|
# are written from script.py.mako
|
||||||
# output_encoding = utf-8
|
# output_encoding = utf-8
|
||||||
|
|
||||||
sqlalchemy.url = postgresql://demo_user:user_pass@db:5432/serviceman_db
|
sqlalchemy.url = postgresql://demo_user:user_pass@localhost:5432/serviceman_db
|
||||||
|
|
||||||
|
|
||||||
[post_write_hooks]
|
[post_write_hooks]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
from api.router.user import router as user_router
|
from api.routers.user import router as user_router
|
||||||
|
|
||||||
|
|
||||||
def create_app() -> FastAPI:
|
def create_app() -> FastAPI:
|
||||||
|
|
|
@ -3,7 +3,7 @@ import os
|
||||||
import yaml # type: ignore
|
import yaml # type: ignore
|
||||||
from pydantic_settings import BaseSettings
|
from pydantic_settings import BaseSettings
|
||||||
|
|
||||||
with open(os.getenv("CONFIG_PATH", "")) as f:
|
with open(os.getenv("CONFIG_PATH", "./config/api_config.yml")) as f:
|
||||||
config_data: dict = yaml.safe_load(f)
|
config_data: dict = yaml.safe_load(f)
|
||||||
|
|
||||||
if os.getenv("INDOCKER"):
|
if os.getenv("INDOCKER"):
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
from sqlalchemy.ext.asyncio import (AsyncSession, async_sessionmaker,
|
||||||
|
create_async_engine)
|
||||||
|
|
||||||
from api.config import get_settings
|
from api.config import get_settings
|
||||||
from api.service.user import UserService
|
from api.services.user import UserService
|
||||||
from api.uow.uow_base import UnitOfWork
|
from api.uow.uow_base import UnitOfWork
|
||||||
|
|
||||||
async_engine = create_async_engine(
|
async_engine = create_async_engine(
|
||||||
url=get_settings().get_db_url,
|
url=get_settings().get_db_url,
|
||||||
echo=True,
|
echo=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
async_session_factory = async_sessionmaker(
|
async_session_factory = async_sessionmaker(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from .base import Base
|
from .base_model import Base
|
||||||
from .user import User
|
from .user_model import UserModel
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
"Base",
|
"Base",
|
||||||
"User",
|
"UserModel",
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,8 @@ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
||||||
|
|
||||||
|
|
||||||
class Base(DeclarativeBase):
|
class Base(DeclarativeBase):
|
||||||
|
__abstract__ = True
|
||||||
|
|
||||||
id: Mapped[uuid.UUID] = mapped_column(
|
id: Mapped[uuid.UUID] = mapped_column(
|
||||||
UUID(as_uuid=True),
|
UUID(as_uuid=True),
|
||||||
primary_key=True,
|
primary_key=True,
|
|
@ -1,12 +1,12 @@
|
||||||
from sqlalchemy import Boolean, Column, String
|
from sqlalchemy import Boolean, Column, String
|
||||||
from sqlalchemy.orm import Mapped
|
from sqlalchemy.orm import Mapped
|
||||||
|
|
||||||
from api.schemas.user_schema import UserSchema
|
from api.schemas import UserReadDTO
|
||||||
|
|
||||||
from .base import Base
|
from . import Base
|
||||||
|
|
||||||
|
|
||||||
class User(Base):
|
class UserModel(Base):
|
||||||
__tablename__ = "users"
|
__tablename__ = "users"
|
||||||
|
|
||||||
name: Mapped[str]
|
name: Mapped[str]
|
||||||
|
@ -22,8 +22,8 @@ class User(Base):
|
||||||
f"is_active={self.is_active})>"
|
f"is_active={self.is_active})>"
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_read_model(self) -> UserSchema:
|
def to_read_model(self) -> UserReadDTO:
|
||||||
return UserSchema(
|
return UserReadDTO(
|
||||||
id=self.id,
|
id=self.id,
|
||||||
name=self.name,
|
name=self.name,
|
||||||
)
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
from .repository import AbstractRepository
|
||||||
|
from .user import UserRepository
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"AbstractRepository",
|
||||||
|
"UserRepository",
|
||||||
|
)
|
|
@ -0,0 +1,23 @@
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractRepository(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
async def add_one(self, data: dict):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def find_all(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def find_one(self, filter: dict):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def update_one(self, filter: dict, data: dict):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def delete_one(self, filter: dict):
|
||||||
|
raise NotImplementedError()
|
|
@ -0,0 +1,30 @@
|
||||||
|
from sqlalchemy import insert, select
|
||||||
|
from sqlalchemy.ext.asyncio.session import AsyncSession
|
||||||
|
|
||||||
|
from api.models import UserModel
|
||||||
|
from api.repositories import AbstractRepository
|
||||||
|
|
||||||
|
|
||||||
|
class UserRepository(AbstractRepository):
|
||||||
|
def __init__(self, session: AsyncSession):
|
||||||
|
self.session = session
|
||||||
|
|
||||||
|
async def add_one(self, data: dict):
|
||||||
|
stmt = insert(UserModel).values(**data)
|
||||||
|
res = await self.session.execute(stmt)
|
||||||
|
return res.scalar_one()
|
||||||
|
|
||||||
|
async def find_all(self):
|
||||||
|
stmt = select(UserModel)
|
||||||
|
res = await self.session.execute(stmt)
|
||||||
|
res = [row[0].to_read_model() for row in res.all()]
|
||||||
|
return res
|
||||||
|
|
||||||
|
async def find_one(self, filter: dict):
|
||||||
|
return
|
||||||
|
|
||||||
|
async def update_one(self, filter: dict, data: dict):
|
||||||
|
return
|
||||||
|
|
||||||
|
async def delete_one(self, filter: dict):
|
||||||
|
return
|
|
@ -1,6 +0,0 @@
|
||||||
import api.models as models
|
|
||||||
from api.uow.repository import SQLAlchemyRepository
|
|
||||||
|
|
||||||
|
|
||||||
class UserRepository(SQLAlchemyRepository):
|
|
||||||
model = models.User
|
|
|
@ -1,16 +1,16 @@
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
|
|
||||||
from api.di import get_user_service
|
from api.di import get_user_service
|
||||||
from api.schemas.user_schema import UserSchema
|
from api.schemas import UserReadDTO
|
||||||
from api.service.user import UserService
|
from api.services import UserService
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.get("/users", response_model=list[UserSchema])
|
@router.get("/users", response_model=list[UserReadDTO])
|
||||||
async def get_user_list(
|
async def get_user_list(
|
||||||
user_service: UserService = Depends(get_user_service),
|
user_service: UserService = Depends(get_user_service),
|
||||||
) -> list[UserSchema]:
|
) -> list[UserReadDTO]:
|
||||||
return await user_service.get_all_users()
|
return await user_service.get_all_users()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from .base_schema import ReadDTO, WriteDTO
|
||||||
|
from .user_schema import UserReadDTO, UserWriteDTO
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"WriteDTO",
|
||||||
|
"ReadDTO",
|
||||||
|
"UserWriteDTO",
|
||||||
|
"UserReadDTO",
|
||||||
|
)
|
|
@ -0,0 +1,13 @@
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class WriteDTO(BaseModel):
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
from_attributes = True
|
||||||
|
|
||||||
|
|
||||||
|
class ReadDTO(WriteDTO):
|
||||||
|
id: UUID
|
|
@ -1,11 +1,9 @@
|
||||||
from uuid import UUID
|
from . import ReadDTO, WriteDTO
|
||||||
|
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
|
|
||||||
class UserSchema(BaseModel):
|
class UserWriteDTO(WriteDTO):
|
||||||
id: UUID
|
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
class Config:
|
|
||||||
from_attributes = True
|
class UserReadDTO(ReadDTO, UserWriteDTO):
|
||||||
|
pass
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
from .user import UserService
|
||||||
|
|
||||||
|
__all__ = ("UserService",)
|
|
@ -1,26 +0,0 @@
|
||||||
from typing import Generic, TypeVar
|
|
||||||
|
|
||||||
from sqlalchemy import insert, select
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
|
|
||||||
import api.models as models
|
|
||||||
|
|
||||||
ModelType = TypeVar("ModelType", bound=models.Base)
|
|
||||||
|
|
||||||
|
|
||||||
class SQLAlchemyRepository(Generic[ModelType]):
|
|
||||||
model: type[ModelType]
|
|
||||||
|
|
||||||
def __init__(self, session: AsyncSession):
|
|
||||||
self.session = session
|
|
||||||
|
|
||||||
async def add_one(self, data: dict) -> ModelType:
|
|
||||||
stmt = insert(self.model).values(**data)
|
|
||||||
res = await self.session.execute(stmt)
|
|
||||||
return res.scalar_one()
|
|
||||||
|
|
||||||
async def find_all(self) -> list[ModelType]:
|
|
||||||
stmt = select(self.model)
|
|
||||||
res = await self.session.execute(stmt)
|
|
||||||
res = [row[0].to_read_model() for row in res.all()]
|
|
||||||
return res
|
|
|
@ -1,4 +1,4 @@
|
||||||
from api.repository.user import UserRepository
|
from api.repositories import UserRepository
|
||||||
|
|
||||||
|
|
||||||
class UnitOfWork:
|
class UnitOfWork:
|
||||||
|
@ -9,6 +9,8 @@ class UnitOfWork:
|
||||||
self.session = self.session_factory()
|
self.session = self.session_factory()
|
||||||
|
|
||||||
self.users = UserRepository(self.session)
|
self.users = UserRepository(self.session)
|
||||||
|
print("session id:", id(self.session))
|
||||||
|
print("UoW obj id:", id(self))
|
||||||
|
|
||||||
async def __aexit__(self, *args):
|
async def __aexit__(self, *args):
|
||||||
await self.session.rollback()
|
await self.session.rollback()
|
||||||
|
|
Loading…
Reference in New Issue