feat(backend): add service layer

This commit is contained in:
2025-04-20 16:56:56 +01:00
parent cccdad8768
commit 999296006c
5 changed files with 319 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
from uuid import UUID
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from src.models import Category, Difficulty, Pattern, Question
from src.models.question import QuestionPattern
class QuestionService:
def __init__(self, db: AsyncSession) -> None:
self.db = db
async def get_questions(
self,
*,
page: int = 1,
limit: int = 20,
difficulties: list[Difficulty] | None = None,
category_slug: str | None = None,
pattern_slug: str | None = None,
search: str | None = None,
) -> tuple[list[Question], int]:
query = (
select(Question)
.options(
selectinload(Question.categories),
selectinload(Question.patterns),
selectinload(Question.question_patterns).selectinload(QuestionPattern.pattern),
)
.order_by(Question.created_at.desc())
)
count_query = select(func.count(Question.id))
if difficulties:
query = query.where(Question.difficulty.in_(difficulties))
count_query = count_query.where(Question.difficulty.in_(difficulties))
if category_slug:
query = query.join(Question.categories).where(Category.slug == category_slug)
count_query = count_query.join(Question.categories).where(
Category.slug == category_slug
)
if pattern_slug:
query = query.join(Question.patterns).where(Pattern.slug == pattern_slug)
count_query = count_query.join(Question.patterns).where(Pattern.slug == pattern_slug)
if search:
search_filter = Question.title.ilike(f"%{search}%")
query = query.where(search_filter)
count_query = count_query.where(search_filter)
total_result = await self.db.execute(count_query)
total = total_result.scalar() or 0
offset = (page - 1) * limit
query = query.offset(offset).limit(limit)
result = await self.db.execute(query)
questions = list(result.scalars().unique().all())
return questions, total
async def get_question_by_slug(self, slug: str) -> Question | None:
query = (
select(Question)
.options(
selectinload(Question.categories),
selectinload(Question.patterns),
selectinload(Question.question_patterns).selectinload(QuestionPattern.pattern),
selectinload(Question.explanation),
selectinload(Question.solutions),
)
.where(Question.slug == slug)
)
result = await self.db.execute(query)
return result.scalar_one_or_none()
async def get_question_by_id(self, question_id: UUID) -> Question | None:
query = (
select(Question)
.options(
selectinload(Question.categories),
selectinload(Question.patterns),
selectinload(Question.question_patterns).selectinload(QuestionPattern.pattern),
selectinload(Question.explanation),
selectinload(Question.solutions),
)
.where(Question.id == question_id)
)
result = await self.db.execute(query)
return result.scalar_one_or_none()