From 26d60fc8b2dada3f6c53c289f997d11384881ed6 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 11 Apr 2026 23:34:57 +0200 Subject: [PATCH] Updated score saving in match --- lib/data/dao/match_dao.dart | 16 +++++++ lib/data/dao/score_dao.dart | 73 +++++++++++++++++++++-------- lib/data/db/tables/score_table.dart | 2 +- lib/data/models/match.dart | 9 ++-- lib/data/models/score.dart | 12 +---- 5 files changed, 77 insertions(+), 35 deletions(-) diff --git a/lib/data/dao/match_dao.dart b/lib/data/dao/match_dao.dart index 9f3892b..3dbacb4 100644 --- a/lib/data/dao/match_dao.dart +++ b/lib/data/dao/match_dao.dart @@ -29,6 +29,9 @@ class MatchDao extends DatabaseAccessor with _$MatchDaoMixin { } final players = await db.playerMatchDao.getPlayersOfMatch(matchId: row.id) ?? []; + + final scores = await db.scoreDao.getAllMatchScores(matchId: row.id); + final winner = await db.scoreDao.getWinner(matchId: row.id); return Match( id: row.id, @@ -39,6 +42,7 @@ class MatchDao extends DatabaseAccessor with _$MatchDaoMixin { notes: row.notes ?? '', createdAt: row.createdAt, endedAt: row.endedAt, + scores: scores, winner: winner, ); }), @@ -60,6 +64,8 @@ class MatchDao extends DatabaseAccessor with _$MatchDaoMixin { final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? []; + final scores = await db.scoreDao.getAllMatchScores(matchId: matchId); + final winner = await db.scoreDao.getWinner(matchId: matchId); return Match( @@ -71,6 +77,7 @@ class MatchDao extends DatabaseAccessor with _$MatchDaoMixin { notes: result.notes ?? '', createdAt: result.createdAt, endedAt: result.endedAt, + scores: scores, winner: winner, ); } @@ -100,6 +107,15 @@ class MatchDao extends DatabaseAccessor with _$MatchDaoMixin { ); } + for (final pid in match.scores.keys) { + final playerScores = match.scores[pid]!; + await db.scoreDao.addScoresAsList( + scores: playerScores, + playerId: pid, + matchId: match.id, + ); + } + if (match.winner != null) { await db.scoreDao.setWinner( matchId: match.id, diff --git a/lib/data/dao/score_dao.dart b/lib/data/dao/score_dao.dart index 6db9e8e..0d314d0 100644 --- a/lib/data/dao/score_dao.dart +++ b/lib/data/dao/score_dao.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:drift/drift.dart'; import 'package:tallee/data/db/database.dart'; import 'package:tallee/data/db/tables/score_table.dart'; @@ -30,6 +32,29 @@ class ScoreDao extends DatabaseAccessor with _$ScoreDaoMixin { ); } + Future addScoresAsList({ + required List scores, + required String playerId, + required String matchId, + }) async { + if (scores.isEmpty) return; + final entries = scores + .map( + (score) => ScoreTableCompanion.insert( + playerId: playerId, + matchId: matchId, + roundNumber: score.roundNumber, + score: score.score, + change: score.change, + ), + ) + .toList(); + + await batch((batch) { + batch.insertAll(scoreTable, entries, mode: InsertMode.insertOrReplace); + }); + } + /// Retrieves the score for a specific round. Future getScore({ required String playerId, @@ -48,7 +73,6 @@ class ScoreDao extends DatabaseAccessor with _$ScoreDaoMixin { if (result == null) return null; return Score( - playerId: result.playerId, roundNumber: result.roundNumber, score: result.score, change: result.change, @@ -56,19 +80,23 @@ class ScoreDao extends DatabaseAccessor with _$ScoreDaoMixin { } /// Retrieves all scores for a specific match. - Future> getAllMatchScores({required String matchId}) async { + Future>> getAllMatchScores({ + required String matchId, + }) async { final query = select(scoreTable)..where((s) => s.matchId.equals(matchId)); final result = await query.get(); - return result - .map( - (row) => Score( - playerId: row.playerId, - roundNumber: row.roundNumber, - score: row.score, - change: row.change, - ), - ) - .toList(); + + final Map> scoresByPlayer = {}; + for (final row in result) { + final score = Score( + roundNumber: row.roundNumber, + score: row.score, + change: row.change, + ); + scoresByPlayer.putIfAbsent(row.playerId, () => []).add(score); + } + + return scoresByPlayer; } /// Retrieves all scores for a specific player in a match. @@ -83,13 +111,15 @@ class ScoreDao extends DatabaseAccessor with _$ScoreDaoMixin { return result .map( (row) => Score( - playerId: row.playerId, roundNumber: row.roundNumber, score: row.score, change: row.change, ), ) - .toList(); + .toList() + ..sort( + (scoreA, scoreB) => scoreA.roundNumber.compareTo(scoreB.roundNumber), + ); } /// Updates a score entry. @@ -149,16 +179,19 @@ class ScoreDao extends DatabaseAccessor with _$ScoreDaoMixin { return rowsAffected > 0; } - /// Gets the latest round number for a match. - Future getLatestRoundNumber({required String matchId}) async { + /// Gets the highest (latest) round number for a match. + /// Returns `null` if there are no scores for the match. + Future getLatestRoundNumber({required String matchId}) async { final query = selectOnly(scoreTable) ..where(scoreTable.matchId.equals(matchId)) ..addColumns([scoreTable.roundNumber.max()]); final result = await query.getSingle(); - return result.read(scoreTable.roundNumber.max()) ?? 0; + return result.read(scoreTable.roundNumber.max()); } - /// Gets the total score for a player in a match (sum of all changes). + /// Aggregates the total score for a player in a match by summing all their + /// score entry changes. Returns `0` if there are no scores for the player + /// in the match. Future getTotalScoreForPlayer({ required String playerId, required String matchId, @@ -168,8 +201,8 @@ class ScoreDao extends DatabaseAccessor with _$ScoreDaoMixin { matchId: matchId, ); if (scores.isEmpty) return 0; - // Return the score from the latest round - return scores.last.score; + // Return the sum of all score changes + return scores.fold(0, (sum, element) => sum + element.change); } Future hasWinner({required String matchId}) async { diff --git a/lib/data/db/tables/score_table.dart b/lib/data/db/tables/score_table.dart index a7bf122..56c036e 100644 --- a/lib/data/db/tables/score_table.dart +++ b/lib/data/db/tables/score_table.dart @@ -13,4 +13,4 @@ class ScoreTable extends Table { @override Set> get primaryKey => {playerId, matchId, roundNumber}; -} \ No newline at end of file +} diff --git a/lib/data/models/match.dart b/lib/data/models/match.dart index ad7f2e3..56c9972 100644 --- a/lib/data/models/match.dart +++ b/lib/data/models/match.dart @@ -15,7 +15,7 @@ class Match { final Group? group; final List players; final String notes; - List scores; + Map> scores; Player? winner; Match({ @@ -27,10 +27,11 @@ class Match { this.group, this.players = const [], this.notes = '', - this.scores = const [], + Map>? scores, this.winner, }) : id = id ?? const Uuid().v4(), - createdAt = createdAt ?? clock.now(); + createdAt = createdAt ?? clock.now(), + scores = scores ?? {for (var player in players) player.id: []}; @override String toString() { @@ -67,7 +68,7 @@ class Match { 'gameId': game.id, 'groupId': group?.id, 'playerIds': players.map((player) => player.id).toList(), - 'scores': scores.map((score) => score.toJson()).toList(), + 'scores': scores, 'notes': notes, }; } diff --git a/lib/data/models/score.dart b/lib/data/models/score.dart index a8bc240..3fabfaf 100644 --- a/lib/data/models/score.dart +++ b/lib/data/models/score.dart @@ -1,24 +1,16 @@ class Score { - final String playerId; final int roundNumber; int score = 0; int change = 0; - Score({ - required this.playerId, - required this.roundNumber, - required this.score, - required this.change, - }); + Score({required this.roundNumber, required this.score, required this.change}); Score.fromJson(Map json) - : playerId = json['playerId'], - roundNumber = json['roundNumber'], + : roundNumber = json['roundNumber'], score = json['score'], change = json['change']; Map toJson() => { - 'playerId': playerId, 'roundNumber': roundNumber, 'score': score, 'change': change,