Updated score saving in match

This commit is contained in:
2026-04-11 23:34:57 +02:00
parent 520edd0ca6
commit 26d60fc8b2
5 changed files with 77 additions and 35 deletions

View File

@@ -29,6 +29,9 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
} }
final players = final players =
await db.playerMatchDao.getPlayersOfMatch(matchId: row.id) ?? []; 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); final winner = await db.scoreDao.getWinner(matchId: row.id);
return Match( return Match(
id: row.id, id: row.id,
@@ -39,6 +42,7 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
notes: row.notes ?? '', notes: row.notes ?? '',
createdAt: row.createdAt, createdAt: row.createdAt,
endedAt: row.endedAt, endedAt: row.endedAt,
scores: scores,
winner: winner, winner: winner,
); );
}), }),
@@ -60,6 +64,8 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
final players = final players =
await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? []; await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? [];
final scores = await db.scoreDao.getAllMatchScores(matchId: matchId);
final winner = await db.scoreDao.getWinner(matchId: matchId); final winner = await db.scoreDao.getWinner(matchId: matchId);
return Match( return Match(
@@ -71,6 +77,7 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
notes: result.notes ?? '', notes: result.notes ?? '',
createdAt: result.createdAt, createdAt: result.createdAt,
endedAt: result.endedAt, endedAt: result.endedAt,
scores: scores,
winner: winner, winner: winner,
); );
} }
@@ -100,6 +107,15 @@ class MatchDao extends DatabaseAccessor<AppDatabase> 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) { if (match.winner != null) {
await db.scoreDao.setWinner( await db.scoreDao.setWinner(
matchId: match.id, matchId: match.id,

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:tallee/data/db/database.dart'; import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/db/tables/score_table.dart'; import 'package:tallee/data/db/tables/score_table.dart';
@@ -30,6 +32,29 @@ class ScoreDao extends DatabaseAccessor<AppDatabase> with _$ScoreDaoMixin {
); );
} }
Future<void> addScoresAsList({
required List<Score> 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. /// Retrieves the score for a specific round.
Future<Score?> getScore({ Future<Score?> getScore({
required String playerId, required String playerId,
@@ -48,7 +73,6 @@ class ScoreDao extends DatabaseAccessor<AppDatabase> with _$ScoreDaoMixin {
if (result == null) return null; if (result == null) return null;
return Score( return Score(
playerId: result.playerId,
roundNumber: result.roundNumber, roundNumber: result.roundNumber,
score: result.score, score: result.score,
change: result.change, change: result.change,
@@ -56,19 +80,23 @@ class ScoreDao extends DatabaseAccessor<AppDatabase> with _$ScoreDaoMixin {
} }
/// Retrieves all scores for a specific match. /// Retrieves all scores for a specific match.
Future<List<Score>> getAllMatchScores({required String matchId}) async { Future<Map<String, List<Score>>> getAllMatchScores({
required String matchId,
}) async {
final query = select(scoreTable)..where((s) => s.matchId.equals(matchId)); final query = select(scoreTable)..where((s) => s.matchId.equals(matchId));
final result = await query.get(); final result = await query.get();
return result
.map( final Map<String, List<Score>> scoresByPlayer = {};
(row) => Score( for (final row in result) {
playerId: row.playerId, final score = Score(
roundNumber: row.roundNumber, roundNumber: row.roundNumber,
score: row.score, score: row.score,
change: row.change, change: row.change,
), );
) scoresByPlayer.putIfAbsent(row.playerId, () => []).add(score);
.toList(); }
return scoresByPlayer;
} }
/// Retrieves all scores for a specific player in a match. /// Retrieves all scores for a specific player in a match.
@@ -83,13 +111,15 @@ class ScoreDao extends DatabaseAccessor<AppDatabase> with _$ScoreDaoMixin {
return result return result
.map( .map(
(row) => Score( (row) => Score(
playerId: row.playerId,
roundNumber: row.roundNumber, roundNumber: row.roundNumber,
score: row.score, score: row.score,
change: row.change, change: row.change,
), ),
) )
.toList(); .toList()
..sort(
(scoreA, scoreB) => scoreA.roundNumber.compareTo(scoreB.roundNumber),
);
} }
/// Updates a score entry. /// Updates a score entry.
@@ -149,16 +179,19 @@ class ScoreDao extends DatabaseAccessor<AppDatabase> with _$ScoreDaoMixin {
return rowsAffected > 0; return rowsAffected > 0;
} }
/// Gets the latest round number for a match. /// Gets the highest (latest) round number for a match.
Future<int> getLatestRoundNumber({required String matchId}) async { /// Returns `null` if there are no scores for the match.
Future<int?> getLatestRoundNumber({required String matchId}) async {
final query = selectOnly(scoreTable) final query = selectOnly(scoreTable)
..where(scoreTable.matchId.equals(matchId)) ..where(scoreTable.matchId.equals(matchId))
..addColumns([scoreTable.roundNumber.max()]); ..addColumns([scoreTable.roundNumber.max()]);
final result = await query.getSingle(); 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<int> getTotalScoreForPlayer({ Future<int> getTotalScoreForPlayer({
required String playerId, required String playerId,
required String matchId, required String matchId,
@@ -168,8 +201,8 @@ class ScoreDao extends DatabaseAccessor<AppDatabase> with _$ScoreDaoMixin {
matchId: matchId, matchId: matchId,
); );
if (scores.isEmpty) return 0; if (scores.isEmpty) return 0;
// Return the score from the latest round // Return the sum of all score changes
return scores.last.score; return scores.fold<int>(0, (sum, element) => sum + element.change);
} }
Future<bool> hasWinner({required String matchId}) async { Future<bool> hasWinner({required String matchId}) async {

View File

@@ -13,4 +13,4 @@ class ScoreTable extends Table {
@override @override
Set<Column<Object>> get primaryKey => {playerId, matchId, roundNumber}; Set<Column<Object>> get primaryKey => {playerId, matchId, roundNumber};
} }

View File

@@ -15,7 +15,7 @@ class Match {
final Group? group; final Group? group;
final List<Player> players; final List<Player> players;
final String notes; final String notes;
List<Score> scores; Map<String, List<Score>> scores;
Player? winner; Player? winner;
Match({ Match({
@@ -27,10 +27,11 @@ class Match {
this.group, this.group,
this.players = const [], this.players = const [],
this.notes = '', this.notes = '',
this.scores = const [], Map<String, List<Score>>? scores,
this.winner, this.winner,
}) : id = id ?? const Uuid().v4(), }) : id = id ?? const Uuid().v4(),
createdAt = createdAt ?? clock.now(); createdAt = createdAt ?? clock.now(),
scores = scores ?? {for (var player in players) player.id: []};
@override @override
String toString() { String toString() {
@@ -67,7 +68,7 @@ class Match {
'gameId': game.id, 'gameId': game.id,
'groupId': group?.id, 'groupId': group?.id,
'playerIds': players.map((player) => player.id).toList(), 'playerIds': players.map((player) => player.id).toList(),
'scores': scores.map((score) => score.toJson()).toList(), 'scores': scores,
'notes': notes, 'notes': notes,
}; };
} }

View File

@@ -1,24 +1,16 @@
class Score { class Score {
final String playerId;
final int roundNumber; final int roundNumber;
int score = 0; int score = 0;
int change = 0; int change = 0;
Score({ Score({required this.roundNumber, required this.score, required this.change});
required this.playerId,
required this.roundNumber,
required this.score,
required this.change,
});
Score.fromJson(Map<String, dynamic> json) Score.fromJson(Map<String, dynamic> json)
: playerId = json['playerId'], : roundNumber = json['roundNumber'],
roundNumber = json['roundNumber'],
score = json['score'], score = json['score'],
change = json['change']; change = json['change'];
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'playerId': playerId,
'roundNumber': roundNumber, 'roundNumber': roundNumber,
'score': score, 'score': score,
'change': change, 'change': change,