сделал слои для наборов линз в апи

This commit is contained in:
Андрей Дувакин 2025-02-20 16:56:01 +05:00
parent 073ed5fc11
commit 8c9e3a05fa
15 changed files with 362 additions and 101 deletions

View File

@ -1,6 +1,6 @@
from typing import Sequence, Optional from typing import Sequence, Optional
from sqlalchemy import select, Row, RowMapping from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from app.domain.models import Lens from app.domain.models import Lens
@ -31,14 +31,7 @@ class LensesRepository:
await self.db.commit() await self.db.commit()
return lens return lens
async def delete(self, lens_id: int) -> Row[Lens] | RowMapping | None: async def delete(self, lens: Lens) -> Lens:
stmt = select(Lens).filter(Lens.id == lens_id)
result = await self.db.execute(stmt)
lens = result.scalars().first()
if lens:
await self.db.delete(lens) await self.db.delete(lens)
await self.db.commit() await self.db.commit()
return lens return lens
return None

View File

@ -1,6 +1,6 @@
from typing import Sequence from typing import Sequence, Optional
from sqlalchemy import select, Row, RowMapping from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from app.domain.models import Patient from app.domain.models import Patient
@ -15,7 +15,7 @@ class PatientsRepository:
result = await self.db.execute(stmt) result = await self.db.execute(stmt)
return result.scalars().all() return result.scalars().all()
async def get_by_id(self, patient_id: int) -> Patient: async def get_by_id(self, patient_id: int) -> Optional[Patient]:
stmt = select(Patient).filter(Patient.id == patient_id) stmt = select(Patient).filter(Patient.id == patient_id)
result = await self.db.execute(stmt) result = await self.db.execute(stmt)
return result.scalars().first() return result.scalars().first()
@ -31,14 +31,7 @@ class PatientsRepository:
await self.db.commit() await self.db.commit()
return patient return patient
async def delete(self, patient_id: int) -> Row[Patient] | RowMapping | None: async def delete(self, patient: Patient) -> Patient:
stmt = select(Patient).filter(Patient.id == patient_id)
result = await self.db.execute(stmt)
patient = result.scalars().first()
if patient:
await self.db.delete(patient) await self.db.delete(patient)
await self.db.commit() await self.db.commit()
return patient return patient
return None

View File

@ -0,0 +1,37 @@
from typing import Optional, Sequence
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.domain.models import Set
class SetsRepository:
def __init__(self, db: AsyncSession):
self.db = db
async def get_all(self) -> Sequence[Set]:
stmt = select(Set)
result = await self.db.execute(stmt)
return result.scalars().all()
async def get_by_id(self, set_id: int) -> Optional[Set]:
stmt = select(Set).filter(Set.id == set_id)
result = await self.db.execute(stmt)
return result.scalars().first()
async def create(self, _set: Set) -> Set:
self.db.add(_set)
await self.db.commit()
await self.db.refresh(_set)
return _set
async def update(self, _set: Set) -> Set:
await self.db.merge(_set)
await self.db.commit()
return _set
async def delete(self, _set: Set) -> Set:
await self.db.delete(_set)
await self.db.commit()
return _set

View File

@ -56,7 +56,7 @@ async def update_lens(
@router.delete( @router.delete(
"/lenses/{lens_id}/", "/lenses/{lens_id}/",
response_model=bool, response_model=LensEntity,
summary="Delete lens", summary="Delete lens",
description="Deletes an existing lens", description="Deletes an existing lens",
) )

View File

@ -56,7 +56,7 @@ async def update_patient(
@router.delete( @router.delete(
"/patients/{patient_id}/", "/patients/{patient_id}/",
response_model=bool, response_model=PatientEntity,
summary="Delete a patient", summary="Delete a patient",
description="Deletes a patient", description="Deletes a patient",
) )

View File

@ -0,0 +1,69 @@
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from app.database.session import get_db
from app.domain.entities.set import SetEntity
from app.infrastructure.dependencies import get_current_user
from app.infrastructure.sets_service import SetsService
router = APIRouter()
@router.get(
'/sets/',
response_model=list[SetEntity],
summary='Get all sets',
description='Returns a list of all sets',
)
async def get_all_sets(
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
sets_service = SetsService(db)
return await sets_service.get_all_sets()
@router.post(
'/sets/',
response_model=SetEntity,
summary='Create a new set',
description='Create a new set',
)
async def create_set(
_set: SetEntity,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
sets_service = SetsService(db)
return await sets_service.create_set(_set)
@router.put(
'/sets/{set_id}/',
response_model=SetEntity,
summary='Update a set',
description='Update a set,'
)
async def update_set(
set_id: int,
_set: SetEntity,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
sets_service = SetsService(db)
return sets_service.update_set(set_id, _set)
@router.delete(
'/sets/{set_id}/',
response_model=SetEntity,
summary='Delete set',
description='Delete an existing set',
)
async def delete_set(
set_id: int,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
sets_service = SetsService(db)
return await sets_service.delete_set(set_id)

View File

@ -0,0 +1,30 @@
"""Убрал поле Количество у таблицы наборов
Revision ID: 0249759985c3
Revises: 27fa11120115
Create Date: 2025-02-20 10:59:11.341413
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '0249759985c3'
down_revision: Union[str, None] = '27fa11120115'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('sets', 'count')
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('sets', sa.Column('count', sa.INTEGER(), autoincrement=False, nullable=False))
# ### end Alembic commands ###

View File

@ -13,6 +13,6 @@ class LensEntity(BaseModel):
diameter: float diameter: float
periphery_toricity: float periphery_toricity: float
side: str side: str
issued: bool issued: bool = False
type_id: int type_id: int

View File

@ -0,0 +1,8 @@
from typing import Optional
from pydantic import BaseModel
class SetEntity(BaseModel):
id: Optional[int] = None
title: str

View File

@ -0,0 +1,18 @@
from typing import Optional
from pydantic import BaseModel
class SetContentEntity(BaseModel):
id: Optional[int] = None
tor: float
trial: float
esa: float
fvc: float
preset_refraction: float
diameter: float
periphery_toricity: float
side: str
count: int
set_id: int

View File

@ -8,7 +8,6 @@ class Set(BaseModel):
__tablename__ = 'sets' __tablename__ = 'sets'
title = Column(VARCHAR(150), nullable=False, unique=True) title = Column(VARCHAR(150), nullable=False, unique=True)
count = Column(Integer, nullable=False)
contents = relationship('SetContent', back_populates='set') contents = relationship('SetContent', back_populates='set')
lens = relationship('SetLens', back_populates='set') lens = relationship('SetLens', back_populates='set')

View File

@ -1,4 +1,4 @@
from typing import Optional from typing import Optional, Any, Coroutine
from fastapi import HTTPException from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
@ -8,6 +8,7 @@ from app.application.lens_types_repository import LensTypesRepository
from app.application.lenses_repository import LensesRepository from app.application.lenses_repository import LensesRepository
from app.domain.entities.lens import LensEntity from app.domain.entities.lens import LensEntity
from app.domain.models import Lens from app.domain.models import Lens
from app.domain.models.lens import SideEnum
class LensesService: class LensesService:
@ -35,7 +36,7 @@ class LensesService:
] ]
async def create_lens(self, lens: LensEntity) -> LensEntity: async def create_lens(self, lens: LensEntity) -> LensEntity:
lens_type = self.lens_types_repository.get_by_id(lens.type_id) lens_type = await self.lens_types_repository.get_by_id(lens.type_id)
if not lens_type: if not lens_type:
raise HTTPException( raise HTTPException(
@ -43,6 +44,14 @@ class LensesService:
detail='The lens type with this ID was not found' detail='The lens type with this ID was not found'
) )
try:
side_enum = SideEnum(lens.side)
except ValueError:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Invalid side value: {lens.side}. Must be 'левая' or 'правая'."
)
lens_model = Lens( lens_model = Lens(
tor=lens.tor, tor=lens.tor,
trial=lens.trial, trial=lens.trial,
@ -51,20 +60,22 @@ class LensesService:
preset_refraction=lens.preset_refraction, preset_refraction=lens.preset_refraction,
diameter=lens.diameter, diameter=lens.diameter,
periphery_toricity=lens.periphery_toricity, periphery_toricity=lens.periphery_toricity,
side=lens.side, side=side_enum,
type_id=lens.type_id, type_id=lens.type_id,
) )
await self.lenses_repository.create(lens_model) await self.lenses_repository.create(lens_model)
return LensEntity( return LensEntity(
id=lens_model.id, id=lens_model.id,
tor=lens_model.tor, tor=lens_model.tor,
trial=lens_model.trial, trial=lens_model.trial,
esa=lens_model.esa, esa=lens_model.esa,
fvc=lens_model.fvs, fvc=lens_model.fvc,
preset_refraction=lens_model.preset_refraction, preset_refraction=lens_model.preset_refraction,
diameter=lens_model.diameter, diameter=lens_model.diameter,
periphery_toricity=lens_model.periphery_toricity, periphery_toricity=lens_model.periphery_toricity,
side=lens_model.side, side=lens_model.side.value,
issued=lens_model.issued, issued=lens_model.issued,
type_id=lens_model.type_id, type_id=lens_model.type_id,
) )
@ -72,7 +83,17 @@ class LensesService:
async def update_lens(self, lens_id: int, lens: LensEntity) -> LensEntity: async def update_lens(self, lens_id: int, lens: LensEntity) -> LensEntity:
lens_model = await self.lenses_repository.get_by_id(lens_id) lens_model = await self.lenses_repository.get_by_id(lens_id)
if lens_model: if not lens_model:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Lens not found")
try:
side_enum = SideEnum(lens.side)
except ValueError:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Invalid side value: {lens.side}. Must be 'левая' or 'правая'."
)
lens_model.tor = lens.tor lens_model.tor = lens.tor
lens_model.trial = lens.trial lens_model.trial = lens.trial
lens_model.esa = lens.esa lens_model.esa = lens.esa
@ -80,30 +101,44 @@ class LensesService:
lens_model.preset_refraction = lens.preset_refraction lens_model.preset_refraction = lens.preset_refraction
lens_model.diameter = lens.diameter lens_model.diameter = lens.diameter
lens_model.periphery_toricity = lens.periphery_toricity lens_model.periphery_toricity = lens.periphery_toricity
lens_model.side = lens.side lens_model.side = side_enum
lens_model.issued = lens.issued lens_model.issued = lens.issued
lens_model.type_id = lens.type_id lens_model.type_id = lens.type_id
await self.lenses_repository.update(lens_model) await self.lenses_repository.update(lens_model)
return LensEntity( return LensEntity(
id=lens_model.id, id=lens_model.id,
tor=lens_model.tor, tor=lens_model.tor,
trial=lens_model.trial, trial=lens_model.trial,
esa=lens_model.esa, esa=lens_model.esa,
fvc=lens_model.fvs, fvc=lens_model.fvc,
preset_refraction=lens_model.preset_refraction, preset_refraction=lens_model.preset_refraction,
diameter=lens_model.diameter, diameter=lens_model.diameter,
periphery_toricity=lens_model.periphery_toricity, periphery_toricity=lens_model.periphery_toricity,
side=lens_model.side, side=lens_model.side.value,
issued=lens_model.issued, issued=lens_model.issued,
type_id=lens_model.type_id, type_id=lens_model.type_id,
) )
async def delete_lens(self, lens_id: int) -> Optional[LensEntity]:
lens = await self.lenses_repository.get_by_id(lens_id)
if not lens:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Lens not found") raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Lens not found")
async def delete_lens(self, lens_id: int) -> Optional[bool]: result = await self.lenses_repository.delete(lens)
result = await self.lenses_repository.delete(lens_id) is not None
if not result: return LensEntity(
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Lens not found") id=result.id,
tor=result.tor,
return result trial=result.trial,
esa=result.esa,
fvc=result.fvc,
preset_refraction=result.preset_refraction,
diameter=result.diameter,
periphery_toricity=result.periphery_toricity,
side=result.side.value,
issued=result.issued,
type_id=result.type_id,
)

View File

@ -59,7 +59,10 @@ class PatientsService:
async def update_patient(self, patient_id: int, patient: PatientEntity) -> Optional[PatientEntity]: async def update_patient(self, patient_id: int, patient: PatientEntity) -> Optional[PatientEntity]:
patient_model = await self.patient_repository.get_by_id(patient_id) patient_model = await self.patient_repository.get_by_id(patient_id)
if patient_model:
if not patient_model:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Patient not found")
patient_model.first_name = patient.first_name patient_model.first_name = patient.first_name
patient_model.last_name = patient.last_name patient_model.last_name = patient.last_name
patient_model.patronymic = patient.patronymic patient_model.patronymic = patient.patronymic
@ -83,12 +86,24 @@ class PatientsService:
correction=patient_model.correction, correction=patient_model.correction,
) )
async def delete_patient(self, patient_id: int) -> Optional[PatientEntity]:
patient = await self.patient_repository.get_by_id(patient_id)
if not patient:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Patient not found") raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Patient not found")
async def delete_patient(self, patient_id: int) -> Optional[bool]: result = await self.patient_repository.delete(patient)
result = await self.patient_repository.delete(patient_id) is not None
if not result: return PatientEntity(
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Patient not found") id=result.id,
first_name=result.first_name,
return result last_name=result.last_name,
patronymic=result.patronymic,
birthday=result.birthday,
address=result.address,
email=result.email,
phone=result.phone,
diagnosis=result.diagnosis,
correction=result.correction,
)

View File

@ -0,0 +1,62 @@
from typing import Optional
from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from starlette import status
from app.application.sets_repository import SetsRepository
from app.domain.entities.set import SetEntity
from app.domain.models import Set
class SetsService:
def __init__(self, db: AsyncSession):
self.sets_repository = SetsRepository(db)
async def get_all_sets(self) -> list[SetEntity]:
sets = await self.sets_repository.get_all()
return [
SetEntity(
id=_set.id,
title=_set.title,
)
for _set in sets
]
async def create_set(self, _set: SetEntity) -> SetEntity:
set_model = Set(
title=_set.title,
)
await self.sets_repository.create(set_model)
return SetEntity(
id=set_model.id,
title=set_model.id,
)
async def update_set(self, set_id: int, _set: SetEntity) -> SetEntity:
set_model = await self.sets_repository.get_by_id(set_id)
if not set_model:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Set not found")
set_model.title = _set.title
await self.sets_repository.update(set_model)
return SetEntity(
id=set_model.id,
title=set_model.title,
)
async def delete_set(self, set_id: int) -> Optional[SetEntity]:
_set = await self.sets_repository.get_by_id(set_id)
if not _set:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Set not found")
result = await self.sets_repository.delete(_set)
return SetEntity(
id=result.id,
title=result.title,
)

View File

@ -2,10 +2,11 @@ from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware from starlette.middleware.cors import CORSMiddleware
from app.controllers.auth_router import router as auth_router from app.controllers.auth_router import router as auth_router
from app.controllers.register_routes import router as register_router
from app.controllers.patients_router import router as patients_router
from app.controllers.lenses_router import router as lenses_router
from app.controllers.lens_types_router import router as lens_types_router from app.controllers.lens_types_router import router as lens_types_router
from app.controllers.lenses_router import router as lenses_router
from app.controllers.patients_router import router as patients_router
from app.controllers.register_routes import router as register_router
from app.controllers.sets_router import router as sets_router
from app.settings import settings from app.settings import settings
@ -25,6 +26,7 @@ def start_app():
api_app.include_router(patients_router, prefix=settings.APP_PREFIX, tags=['patients']) api_app.include_router(patients_router, prefix=settings.APP_PREFIX, tags=['patients'])
api_app.include_router(lenses_router, prefix=settings.APP_PREFIX, tags=['lenses']) api_app.include_router(lenses_router, prefix=settings.APP_PREFIX, tags=['lenses'])
api_app.include_router(lens_types_router, prefix=settings.APP_PREFIX, tags=['lens_types']) api_app.include_router(lens_types_router, prefix=settings.APP_PREFIX, tags=['lens_types'])
api_app.include_router(sets_router, prefix=settings.APP_PREFIX, tags=['sets'])
return api_app return api_app