From ca45718f42f3cb507539f9f928b061fa12e74a8f Mon Sep 17 00:00:00 2001 From: Automated Action Date: Fri, 16 May 2025 06:50:37 +0000 Subject: [PATCH] Fix database path and improve error handling for robust API functionality --- app/api/deps.py | 11 ++----- app/crud/base.py | 79 ++++++++++++++++++++++++++++++++++----------- app/schemas/task.py | 24 ++++++++++++++ main.py | 19 +++++------ 4 files changed, 97 insertions(+), 36 deletions(-) diff --git a/app/api/deps.py b/app/api/deps.py index 7b60e48..b7be88f 100644 --- a/app/api/deps.py +++ b/app/api/deps.py @@ -1,11 +1,4 @@ from typing import Generator -from app.db.session import SessionLocal - - -def get_db() -> Generator: - db = SessionLocal() - try: - yield db - finally: - db.close() \ No newline at end of file +# Use the improved get_db function from session.py +from app.db.session import get_db \ No newline at end of file diff --git a/app/crud/base.py b/app/crud/base.py index 0abcaf6..70a8904 100644 --- a/app/crud/base.py +++ b/app/crud/base.py @@ -53,26 +53,69 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]): db_obj: ModelType, obj_in: Union[UpdateSchemaType, Dict[str, Any]] ) -> ModelType: - obj_data = jsonable_encoder(db_obj) - if isinstance(obj_in, dict): - update_data = obj_in - else: - # Handle both Pydantic v1 and v2 - if hasattr(obj_in, "model_dump"): - update_data = obj_in.model_dump(exclude_unset=True) + try: + # Log update operation + print(f"Updating {self.model.__name__} with id: {db_obj.id}") + + # Get the existing data + obj_data = jsonable_encoder(db_obj) + + # Process the update data + if isinstance(obj_in, dict): + update_data = obj_in else: - update_data = obj_in.dict(exclude_unset=True) - for field in obj_data: - if field in update_data: - setattr(db_obj, field, update_data[field]) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj + # Handle both Pydantic v1 and v2 + if hasattr(obj_in, "model_dump"): + update_data = obj_in.model_dump(exclude_unset=True) + else: + update_data = obj_in.dict(exclude_unset=True) + + # Log the changes being made + changes = {k: v for k, v in update_data.items() if k in obj_data} + print(f"Fields to update: {changes}") + + # Apply the updates + for field in obj_data: + if field in update_data: + setattr(db_obj, field, update_data[field]) + + # Save changes + db.add(db_obj) + db.commit() + db.refresh(db_obj) + + print(f"Successfully updated {self.model.__name__} with id: {db_obj.id}") + return db_obj + + except Exception as e: + db.rollback() + error_msg = f"Error updating {self.model.__name__}: {str(e)}" + print(error_msg) + import traceback + print(traceback.format_exc()) + raise Exception(error_msg) from e def remove(self, db: Session, *, id: int) -> ModelType: - obj = db.query(self.model).filter(self.model.id == id).first() - if obj: + try: + # Get the object first + obj = db.query(self.model).filter(self.model.id == id).first() + if not obj: + print(f"{self.model.__name__} with id {id} not found for deletion") + return None + + print(f"Deleting {self.model.__name__} with id: {id}") + + # Delete the object db.delete(obj) db.commit() - return obj \ No newline at end of file + + print(f"Successfully deleted {self.model.__name__} with id: {id}") + return obj + + except Exception as e: + db.rollback() + error_msg = f"Error deleting {self.model.__name__}: {str(e)}" + print(error_msg) + import traceback + print(traceback.format_exc()) + raise Exception(error_msg) from e \ No newline at end of file diff --git a/app/schemas/task.py b/app/schemas/task.py index bc477bc..7021af6 100644 --- a/app/schemas/task.py +++ b/app/schemas/task.py @@ -13,6 +13,12 @@ class TaskBase(BaseModel): status: TaskStatus = TaskStatus.TODO due_date: Optional[datetime] = None completed: bool = False + + model_config = { + "json_encoders": { + datetime: lambda dt: dt.isoformat(), + } + } class TaskCreate(TaskBase): @@ -26,6 +32,24 @@ class TaskUpdate(BaseModel): status: Optional[TaskStatus] = None due_date: Optional[datetime] = None completed: Optional[bool] = None + + model_config = { + "json_encoders": { + datetime: lambda dt: dt.isoformat(), + }, + "populate_by_name": True, + "json_schema_extra": { + "examples": [ + { + "title": "Updated Task Title", + "description": "Updated task description", + "priority": "high", + "status": "in_progress", + "completed": False + } + ] + } + } class TaskInDBBase(TaskBase): diff --git a/main.py b/main.py index 44395f7..1cf033c 100644 --- a/main.py +++ b/main.py @@ -17,15 +17,15 @@ from app.db import init_db # Initialize the database on startup print("Starting database initialization...") try: - # Get absolute path of the database file - from pathlib import Path - db_path = Path("/app/storage/db/db.sqlite").absolute() - print(f"Database path: {db_path}") + # Get absolute path of the database file from your config + from app.db.session import db_file + print(f"Database path: {db_file}") - # Check directory permissions - db_dir = Path("/app/storage/db") - print(f"Database directory exists: {db_dir.exists()}") - print(f"Database directory is writable: {os.access(db_dir, os.W_OK)}") + # Check directory permissions for the configured DB_DIR + from app.core.config import DB_DIR + print(f"Database directory: {DB_DIR}") + print(f"Database directory exists: {DB_DIR.exists()}") + print(f"Database directory is writable: {os.access(DB_DIR, os.W_OK)}") # Initialize the database and create test task init_db.init_db() @@ -168,6 +168,7 @@ def test_db_connection(): import os import sqlite3 import traceback + import datetime from sqlalchemy import text from app.db.session import engine, db_file from app.core.config import DB_DIR @@ -262,7 +263,7 @@ def test_db_connection(): return { "status": "ok", - "timestamp": datetime.utcnow().isoformat(), + "timestamp": datetime.datetime.utcnow().isoformat(), "file_info": file_info, "sqlite_test": sqlite_test, "sqlalchemy_test": sqlalchemy_test,