"""This module handles CRUD operations for todo-items in the database, based on pydanctic schemas.""" from datetime import datetime from sqlalchemy.orm import Session from todo.models import todos as todomodel from todo.models import users as usermodel from todo.schemas import todos as todoschema from todo.utils.exceptions import NotFoundException, InvalidFilterParameterException from todo.dependencies.common import SortOrder from todo.dependencies.todos import SortableTodoItemField def create_todo(db: Session, todo: todoschema.TodoItemCreate, user_id: int) -> todoschema.TodoItem: """Creates the specified todo-item for the user with the specified id in the database.""" db_user = db.query(usermodel.User).filter(usermodel.User.id == user_id).first() if not db_user: raise NotFoundException(f"User with id '{user_id}' not found.") db_todo = todomodel.TodoItem( user_id=user_id, title=todo.title, description=todo.description ) db.add(db_todo) db.commit() db.refresh(db_todo) return todoschema.TodoItem.from_orm(db_todo) def read_todo(db: Session, todo_id: int) -> todoschema.TodoItem: """Queries the db for a todo-item with the specified id and returns it.""" db_todo = db.query(todomodel.TodoItem).filter(todomodel.TodoItem.id == todo_id).first() if not db_todo: raise NotFoundException(f"Todo item with id '{todo_id}' not found.") return todoschema.TodoItem.from_orm(db_todo) def read_todos_for_user( db: Session, user_id: int, skip: int = 0, limit: int = 100, sortby: SortableTodoItemField = SortableTodoItemField('updated'), sortorder: SortOrder = SortOrder['desc'], ) -> list[todoschema.TodoItem]: """Returns a range of todo-items of the user with the specified user_id from the database.""" for parameter in [skip, limit]: if not isinstance(parameter, int): raise InvalidFilterParameterException(f"Parameter '{parameter}' must be an integer.") if parameter < 0: raise InvalidFilterParameterException(f"Parameter '{parameter}' cannot be smaller than zero.") db_user = db.query(usermodel.User).filter(usermodel.User.id == user_id).first() if not db_user: raise NotFoundException(f"User with id '{user_id}' not found.") db_todos = db.query(todomodel.TodoItem).filter(todomodel.TodoItem.user_id == user_id).order_by(sortorder.call(sortby.field)).offset(skip).limit(limit).all() return [todoschema.TodoItem.from_orm(db_todo) for db_todo in db_todos] def read_todos_count_for_user(db: Session, user_id: int) -> int: """Returns the total number of todo-items of the user with the specified user_id.""" db_user = db.query(usermodel.User).filter(usermodel.User.id == user_id).first() if not db_user: raise NotFoundException(f"User with id '{user_id}' not found.") return db.query(todomodel.TodoItem).filter(todomodel.TodoItem.user_id == user_id).count() def update_todo(db: Session, todo: todoschema.TodoItemUpdate, todo_id: int) -> todoschema.TodoItem: """Updates the todo-item with the provided id with all non-None fields from the input todo-item.""" db_todo = db.query(todomodel.TodoItem).filter(todomodel.TodoItem.id == todo_id).first() if not db_todo: raise NotFoundException(f"Todo item with id '{todo_id}' not found.") db_todo_orm_obj = todoschema.TodoItem.from_orm(db_todo) for key in ['title', 'description', 'done']: value = getattr(todo, key) if value is not None: setattr(db_todo, key, value) # If we just newly finished a TODO, record the time it was finished if todo.done and not db_todo_orm_obj.done: setattr(db_todo, "finished", datetime.now(db_todo_orm_obj.updated.tzinfo)) db.commit() db.refresh(db_todo) return todoschema.TodoItem.from_orm(db_todo) def delete_todo(db: Session, todo_id: int) -> todoschema.TodoItem: """Deletes the todo-item with the provided id from the db.""" db_todo = db.query(todomodel.TodoItem).filter(todomodel.TodoItem.id == todo_id).first() if not db_todo: raise NotFoundException(f"Todo item with id '{todo_id}' not found.") todo_copy = todoschema.TodoItem.from_orm(db_todo) db.delete(db_todo) db.commit() todo_copy.updated = datetime.now(todo_copy.updated.tzinfo) return todo_copy