
- Set up project structure with FastAPI and SQLite - Create models for users, questions, and quizzes - Implement Alembic migrations with seed data - Add user authentication with JWT - Implement question management endpoints - Implement quiz creation and management - Add quiz-taking and scoring functionality - Set up API documentation and health check endpoint - Update README with comprehensive documentation
153 lines
4.0 KiB
Python
153 lines
4.0 KiB
Python
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() |