From d722504e553d12dc13f94f3f6be20f15fdf6cd79 Mon Sep 17 00:00:00 2001 From: grillazz Date: Sat, 23 Aug 2025 17:53:18 +0200 Subject: [PATCH] wip: crud refactor --- app/api/stuff.py | 2 +- app/database.py | 1 + app/main.py | 16 +++++++++++++- app/models/base.py | 38 +++++++++------------------------ app/schemas/stuff.py | 4 +++- tests/api/test_chaotic_stuff.py | 0 6 files changed, 30 insertions(+), 31 deletions(-) create mode 100644 tests/api/test_chaotic_stuff.py diff --git a/app/api/stuff.py b/app/api/stuff.py index 7ff8ee6..83fedf3 100644 --- a/app/api/stuff.py +++ b/app/api/stuff.py @@ -116,5 +116,5 @@ async def update_stuff( db_session: AsyncSession = Depends(get_db), ): stuff = await Stuff.find(db_session, name) - await stuff.update(db_session, **payload.model_dump()) + await stuff.update(**payload.model_dump()) return stuff diff --git a/app/database.py b/app/database.py index 872085c..bb5ef08 100644 --- a/app/database.py +++ b/app/database.py @@ -28,6 +28,7 @@ async def get_db() -> AsyncGenerator: # logger.debug(f"ASYNC Pool: {engine.pool.status()}") try: yield session + await session.commit() except Exception as e: await logger.aerror(f"Error getting database session: {e}") raise diff --git a/app/main.py b/app/main.py index dab1176..8a63090 100644 --- a/app/main.py +++ b/app/main.py @@ -3,9 +3,10 @@ from pathlib import Path import asyncpg from fastapi import Depends, FastAPI, Request -from fastapi.responses import HTMLResponse +from fastapi.responses import HTMLResponse, JSONResponse from fastapi.templating import Jinja2Templates from rotoger import AppStructLogger +from sqlalchemy.exc import SQLAlchemyError from app.api.health import router as health_router from app.api.ml import router as ml_router @@ -61,6 +62,19 @@ def create_app() -> FastAPI: dependencies=[Depends(AuthBearer())], ) + @app.exception_handler(SQLAlchemyError) + async def sqlalchemy_exception_handler(request: Request, exc: SQLAlchemyError): + await logger.aerror( + "A database error occurred", + sql_error=repr(exc), + request_url=request.url.path, + request_body=request.body, + ) + return JSONResponse( + status_code=500, + content={"message": "A database error occurred. Please try again later."}, + ) + @app.get("/index", response_class=HTMLResponse) def get_index(request: Request): return templates.TemplateResponse("index.html", {"request": request}) diff --git a/app/models/base.py b/app/models/base.py index b8665a1..f04cef9 100644 --- a/app/models/base.py +++ b/app/models/base.py @@ -20,64 +20,46 @@ class Base(DeclarativeBase): return self.__name__.lower() async def save(self, db_session: AsyncSession): - """ - - :param db_session: - :return: - """ try: db_session.add(self) - await db_session.commit() + await db_session.flush() await db_session.refresh(self) return self except SQLAlchemyError as ex: await logger.aerror(f"Error inserting instance of {self}: {repr(ex)}") - raise HTTPException( - status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=repr(ex) - ) from ex + raise # This will make the exception handler catch it async def delete(self, db_session: AsyncSession): - """ - - :param db_session: - :return: - """ try: await db_session.delete(self) - await db_session.commit() return True except SQLAlchemyError as ex: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=repr(ex) ) from ex - async def update(self, db: AsyncSession, **kwargs): - """ - - :param db: - :param kwargs - :return: - """ + async def update(self, **kwargs): try: for k, v in kwargs.items(): setattr(self, k, v) - return await db.commit() + return True except SQLAlchemyError as ex: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=repr(ex) ) from ex - async def save_or_update(self, db: AsyncSession): + async def save_or_update(self, db_session: AsyncSession): try: - db.add(self) - return await db.commit() + db_session.add(self) + await db_session.flush() + return True except IntegrityError as exception: if isinstance(exception.orig, UniqueViolationError): - return await db.merge(self) + return await db_session.merge(self) else: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=repr(exception), ) from exception finally: - await db.close() + await db_session.close() diff --git a/app/schemas/stuff.py b/app/schemas/stuff.py index 18b3700..2a9d3c9 100644 --- a/app/schemas/stuff.py +++ b/app/schemas/stuff.py @@ -7,7 +7,9 @@ config = ConfigDict(from_attributes=True) class RandomStuff(BaseModel): - chaos: dict[str, Any] = Field(..., description="JSON data for chaos field") + chaos: dict[str, Any] = Field( + ..., description="Pretty chaotic JSON data can be added here..." + ) class StuffSchema(BaseModel): diff --git a/tests/api/test_chaotic_stuff.py b/tests/api/test_chaotic_stuff.py new file mode 100644 index 0000000..e69de29