| 68 | |
| 69 | |
| 70 | def _get_difficult_cards( |
| 71 | session: Session, |
| 72 | collection_id: uuid.UUID, |
| 73 | min_attempts: int = 2, |
| 74 | limit: int = 5, |
| 75 | ) -> list[CardBasicStats]: |
| 76 | statement = ( |
| 77 | select( |
| 78 | Card.id, |
| 79 | Card.front, |
| 80 | func.count(PracticeCard.id).label("total_attempts"), |
| 81 | func.sum(case((PracticeCard.is_correct, 1), else_=0)).label( |
| 82 | "correct_answers" |
| 83 | ), |
| 84 | ) |
| 85 | .join(PracticeCard, Card.id == PracticeCard.card_id) |
| 86 | .join(PracticeSession, PracticeCard.session_id == PracticeSession.id) |
| 87 | .where( |
| 88 | Card.collection_id == collection_id, |
| 89 | PracticeSession.is_completed, |
| 90 | PracticeCard.is_practiced, |
| 91 | PracticeCard.is_correct.is_not(None), |
| 92 | ) |
| 93 | .group_by(Card.id, Card.front) |
| 94 | .having(func.count(PracticeCard.id) >= min_attempts) |
| 95 | .order_by( |
| 96 | func.sum(case((PracticeCard.is_correct, 1), else_=0)).cast(Float) |
| 97 | / func.count(PracticeCard.id) |
| 98 | ) |
| 99 | .limit(limit) |
| 100 | ) |
| 101 | |
| 102 | results = session.exec(statement).all() |
| 103 | return [ |
| 104 | CardBasicStats( |
| 105 | id=card_id, |
| 106 | front=front[:100], |
| 107 | total_attempts=total_attempts, |
| 108 | correct_answers=correct_answers, |
| 109 | ) |
| 110 | for card_id, front, total_attempts, correct_answers in results |
| 111 | ] |
| 112 | |
| 113 | |
| 114 | def get_collection_stats( |