import 'package:postgres/postgres.dart'; import 'spelling_progress_policy.dart'; /// Per-user familiarity with shared [spelling_items]. class UserSpellingProgressDb { UserSpellingProgressDb(this._connection); final Connection _connection; /// Ensures a per-user link to [spellingItemId] with scores starting at zero. Future ensureLink({ required String firebaseUid, required String spellingItemId, }) async { await _connection.execute( Sql.named( ''' INSERT INTO user_spelling_progress ( firebase_uid, spelling_item_id, familiarity_score, attempt_count, correct_count ) VALUES ( @uid, @item_id::uuid, 0, 0, 0 ) ON CONFLICT (firebase_uid, spelling_item_id) DO NOTHING ''', ), parameters: { 'uid': firebaseUid, 'item_id': spellingItemId, }, ); } Future recordQuizOutcome({ required String firebaseUid, required String spellingItemId, required bool correct, }) async { final DateTime now = DateTime.now().toUtc(); final String outcome = correct ? 'correct' : 'incorrect'; final int delta = correct ? SpellingProgressPolicy.correctDelta : -SpellingProgressPolicy.incorrectDelta; await _connection.execute( Sql.named( ''' INSERT INTO user_spelling_progress ( firebase_uid, spelling_item_id, familiarity_score, attempt_count, correct_count, last_attempted_at, last_outcome ) VALUES ( @uid, @item_id::uuid, @delta, 1, @correct_inc, @now, @outcome ) ON CONFLICT (firebase_uid, spelling_item_id) DO UPDATE SET familiarity_score = user_spelling_progress.familiarity_score + @delta, attempt_count = user_spelling_progress.attempt_count + 1, correct_count = user_spelling_progress.correct_count + @correct_inc, last_attempted_at = @now, last_outcome = @outcome ''', ), parameters: { 'uid': firebaseUid, 'item_id': spellingItemId, 'delta': delta, 'correct_inc': correct ? 1 : 0, 'now': now, 'outcome': outcome, }, ); } Future familiarityScore({ required String firebaseUid, required String spellingItemId, }) async { final Result result = await _connection.execute( Sql.named( ''' SELECT familiarity_score FROM user_spelling_progress WHERE firebase_uid = @uid AND spelling_item_id = @item_id::uuid ''', ), parameters: { 'uid': firebaseUid, 'item_id': spellingItemId, }, ); if (result.isEmpty) { return null; } return (result.first[0]! as num).toInt(); } }