from typing import List, Optional from sqlalchemy.orm import Session from app.models.question import ( BibleBook, Question, QuestionCategory, QuestionDifficulty, QuestionOption, ) from app.schemas.question import ( QuestionCreate, QuestionUpdate, ) def get_by_id(db: Session, question_id: int) -> Optional[Question]: """ Get question by ID """ return db.query(Question).filter(Question.id == question_id).first() def get_multi( db: Session, *, skip: int = 0, limit: int = 100, category_id: Optional[int] = None, difficulty_id: Optional[int] = None, bible_book_id: Optional[int] = None, ) -> List[Question]: """ Get multiple questions with optional filters """ query = db.query(Question) if category_id is not None: query = query.filter(Question.category_id == category_id) if difficulty_id is not None: query = query.filter(Question.difficulty_id == difficulty_id) if bible_book_id is not None: query = query.filter(Question.bible_book_id == bible_book_id) return query.offset(skip).limit(limit).all() def create(db: Session, *, obj_in: QuestionCreate) -> Question: """ Create new question with options """ # Extract options from input options_data = obj_in.options obj_in_dict = obj_in.dict(exclude={"options"}) # Create question db_obj = Question(**obj_in_dict) db.add(db_obj) db.flush() # Flush to get the ID without committing # Create options for the question for option_data in options_data: option = QuestionOption( question_id=db_obj.id, **option_data.dict(), ) db.add(option) db.commit() db.refresh(db_obj) return db_obj def update( db: Session, *, db_obj: Question, obj_in: QuestionUpdate ) -> Question: """ Update question and options """ # Update question fields update_data = obj_in.dict(exclude={"options"}, exclude_unset=True) for field, value in update_data.items(): setattr(db_obj, field, value) # Update options if provided if obj_in.options is not None: # Update existing options or create new ones existing_options = {opt.id: opt for opt in db_obj.options} for option_data in obj_in.options: if hasattr(option_data, "id") and option_data.id in existing_options: # Update existing option option = existing_options[option_data.id] for field, value in option_data.dict(exclude_unset=True).items(): setattr(option, field, value) else: # Create new option option = QuestionOption( question_id=db_obj.id, **option_data.dict(exclude={"id"}, exclude_unset=True), ) db.add(option) db.add(db_obj) db.commit() db.refresh(db_obj) return db_obj def remove(db: Session, *, question_id: int) -> None: """ Delete question (and its options via cascade) """ question = db.query(Question).filter(Question.id == question_id).first() if question: db.delete(question) db.commit() # Functions for managing categories, difficulties, and bible books def get_all_categories(db: Session) -> List[QuestionCategory]: """ Get all question categories """ return db.query(QuestionCategory).all() def get_all_difficulties(db: Session) -> List[QuestionDifficulty]: """ Get all question difficulties """ return db.query(QuestionDifficulty).all() def get_all_bible_books(db: Session) -> List[BibleBook]: """ Get all Bible books """ return db.query(BibleBook).all() def get_bible_books_by_testament(db: Session, testament: str) -> List[BibleBook]: """ Get Bible books by testament (Old or New) """ return db.query(BibleBook).filter(BibleBook.testament == testament).all()