Finalized and updated team implementation, updated team dao, tests, and ex-/import
This commit is contained in:
@@ -8,6 +8,7 @@ import 'package:tallee/data/models/game.dart';
|
|||||||
import 'package:tallee/data/models/group.dart';
|
import 'package:tallee/data/models/group.dart';
|
||||||
import 'package:tallee/data/models/match.dart';
|
import 'package:tallee/data/models/match.dart';
|
||||||
import 'package:tallee/data/models/player.dart';
|
import 'package:tallee/data/models/player.dart';
|
||||||
|
import 'package:tallee/data/models/team.dart';
|
||||||
|
|
||||||
part 'match_dao.g.dart';
|
part 'match_dao.g.dart';
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
|||||||
|
|
||||||
/* Create */
|
/* Create */
|
||||||
|
|
||||||
/// Adds a new [Match] to the database. Also adds players associations.
|
/// Adds a new [Match] to the database. Also adds players associations and teams.
|
||||||
/// This method assumes that the game and group (if any) are already present
|
/// This method assumes that the game and group (if any) are already present
|
||||||
/// in the database.
|
/// in the database.
|
||||||
Future<bool> addMatch({required Match match}) async {
|
Future<bool> addMatch({required Match match}) async {
|
||||||
@@ -36,6 +37,11 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
|||||||
mode: InsertMode.insertOrReplace,
|
mode: InsertMode.insertOrReplace,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Add teams
|
||||||
|
if (match.teams != null && match.teams!.isNotEmpty) {
|
||||||
|
await db.teamDao.addTeamsAsList(teams: match.teams!, matchId: match.id);
|
||||||
|
}
|
||||||
|
|
||||||
for (final p in match.players) {
|
for (final p in match.players) {
|
||||||
await db.playerMatchDao.addPlayerToMatch(
|
await db.playerMatchDao.addPlayerToMatch(
|
||||||
matchId: match.id,
|
matchId: match.id,
|
||||||
@@ -53,7 +59,6 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print('Return true');
|
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -220,6 +225,16 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add teams for matches
|
||||||
|
for (final match in matches) {
|
||||||
|
if (match.teams != null && match.teams!.isNotEmpty) {
|
||||||
|
await db.teamDao.addTeamsAsList(
|
||||||
|
teams: match.teams!,
|
||||||
|
matchId: match.id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -262,12 +277,15 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
|||||||
matchId: row.id,
|
matchId: row.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final teams = await _getMatchTeams(matchId: row.id);
|
||||||
|
|
||||||
return Match(
|
return Match(
|
||||||
id: row.id,
|
id: row.id,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
game: game,
|
game: game,
|
||||||
group: group,
|
group: group,
|
||||||
players: players,
|
players: players,
|
||||||
|
teams: teams.isEmpty ? null : teams,
|
||||||
notes: row.notes ?? '',
|
notes: row.notes ?? '',
|
||||||
createdAt: row.createdAt,
|
createdAt: row.createdAt,
|
||||||
endedAt: row.endedAt,
|
endedAt: row.endedAt,
|
||||||
@@ -294,12 +312,15 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
|||||||
|
|
||||||
final scores = await db.scoreEntryDao.getAllMatchScores(matchId: matchId);
|
final scores = await db.scoreEntryDao.getAllMatchScores(matchId: matchId);
|
||||||
|
|
||||||
|
final teams = await _getMatchTeams(matchId: matchId);
|
||||||
|
|
||||||
return Match(
|
return Match(
|
||||||
id: result.id,
|
id: result.id,
|
||||||
name: result.name,
|
name: result.name,
|
||||||
game: game,
|
game: game,
|
||||||
group: group,
|
group: group,
|
||||||
players: players,
|
players: players,
|
||||||
|
teams: teams.isEmpty ? null : teams,
|
||||||
notes: result.notes ?? '',
|
notes: result.notes ?? '',
|
||||||
createdAt: result.createdAt,
|
createdAt: result.createdAt,
|
||||||
endedAt: result.endedAt,
|
endedAt: result.endedAt,
|
||||||
@@ -319,12 +340,14 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
|||||||
final group = await db.groupDao.getGroupById(groupId: groupId);
|
final group = await db.groupDao.getGroupById(groupId: groupId);
|
||||||
final players =
|
final players =
|
||||||
await db.playerMatchDao.getPlayersOfMatch(matchId: row.id) ?? [];
|
await db.playerMatchDao.getPlayersOfMatch(matchId: row.id) ?? [];
|
||||||
|
final teams = await _getMatchTeams(matchId: row.id);
|
||||||
return Match(
|
return Match(
|
||||||
id: row.id,
|
id: row.id,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
game: game,
|
game: game,
|
||||||
group: group,
|
group: group,
|
||||||
players: players,
|
players: players,
|
||||||
|
teams: teams.isEmpty ? null : teams,
|
||||||
notes: row.notes ?? '',
|
notes: row.notes ?? '',
|
||||||
createdAt: row.createdAt,
|
createdAt: row.createdAt,
|
||||||
endedAt: row.endedAt,
|
endedAt: row.endedAt,
|
||||||
@@ -333,6 +356,29 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper method to retrieve teams for a specific match
|
||||||
|
Future<List<Team>> _getMatchTeams({required String matchId}) async {
|
||||||
|
// Get all unique team IDs from PlayerMatchTable for this match
|
||||||
|
final playerMatchQuery = select(db.playerMatchTable)
|
||||||
|
..where((pm) => pm.matchId.equals(matchId) & pm.teamId.isNotNull());
|
||||||
|
final playerMatches = await playerMatchQuery.get();
|
||||||
|
|
||||||
|
if (playerMatches.isEmpty) return [];
|
||||||
|
|
||||||
|
final teamIds = playerMatches
|
||||||
|
.map((pm) => pm.teamId)
|
||||||
|
.whereType<String>()
|
||||||
|
.toSet()
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
// Fetch all teams
|
||||||
|
final teams = await Future.wait(
|
||||||
|
teamIds.map((teamId) => db.teamDao.getTeamById(teamId: teamId)),
|
||||||
|
);
|
||||||
|
|
||||||
|
return teams;
|
||||||
|
}
|
||||||
|
|
||||||
/* Update */
|
/* Update */
|
||||||
|
|
||||||
/// Changes the name of the match with the given [matchId] to [newName].
|
/// Changes the name of the match with the given [matchId] to [newName].
|
||||||
|
|||||||
@@ -1,17 +1,105 @@
|
|||||||
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/player_match_table.dart';
|
||||||
import 'package:tallee/data/db/tables/team_table.dart';
|
import 'package:tallee/data/db/tables/team_table.dart';
|
||||||
import 'package:tallee/data/models/player.dart';
|
import 'package:tallee/data/models/player.dart';
|
||||||
import 'package:tallee/data/models/team.dart';
|
import 'package:tallee/data/models/team.dart';
|
||||||
|
|
||||||
part 'team_dao.g.dart';
|
part 'team_dao.g.dart';
|
||||||
|
|
||||||
@DriftAccessor(tables: [TeamTable])
|
@DriftAccessor(tables: [TeamTable, PlayerMatchTable])
|
||||||
class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
|
class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
|
||||||
TeamDao(super.db);
|
TeamDao(super.db);
|
||||||
|
|
||||||
|
/* Create */
|
||||||
|
|
||||||
|
/// Adds a new [team] to the database.
|
||||||
|
/// Returns `true` if the team was added, `false` otherwise.
|
||||||
|
Future<bool> addTeam({required Team team, required String matchId}) async {
|
||||||
|
if (await teamExists(teamId: team.id)) return false;
|
||||||
|
await into(teamTable).insert(
|
||||||
|
TeamTableCompanion.insert(
|
||||||
|
id: team.id,
|
||||||
|
name: team.name,
|
||||||
|
createdAt: team.createdAt,
|
||||||
|
),
|
||||||
|
mode: InsertMode.insertOrReplace,
|
||||||
|
);
|
||||||
|
await db.batch((batch) async {
|
||||||
|
for (final player in team.members) {
|
||||||
|
await into(playerMatchTable).insert(
|
||||||
|
PlayerMatchTableCompanion.insert(
|
||||||
|
playerId: player.id,
|
||||||
|
matchId: matchId,
|
||||||
|
teamId: Value(team.id),
|
||||||
|
),
|
||||||
|
mode: InsertMode.insertOrReplace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds multiple [teams] to the database in a batch operation.
|
||||||
|
Future<bool> addTeamsAsList({
|
||||||
|
required List<Team> teams,
|
||||||
|
required String matchId,
|
||||||
|
}) async {
|
||||||
|
if (teams.isEmpty) return false;
|
||||||
|
|
||||||
|
await db.batch(
|
||||||
|
(b) => b.insertAll(
|
||||||
|
teamTable,
|
||||||
|
teams
|
||||||
|
.map(
|
||||||
|
(team) => TeamTableCompanion.insert(
|
||||||
|
id: team.id,
|
||||||
|
name: team.name,
|
||||||
|
createdAt: team.createdAt,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
mode: InsertMode.insertOrIgnore,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (final team in teams) {
|
||||||
|
await db.batch((batch) async {
|
||||||
|
for (final player in team.members) {
|
||||||
|
await into(db.playerMatchTable).insert(
|
||||||
|
PlayerMatchTableCompanion.insert(
|
||||||
|
playerId: player.id,
|
||||||
|
matchId: matchId,
|
||||||
|
teamId: Value(team.id),
|
||||||
|
),
|
||||||
|
mode: InsertMode.insertOrReplace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read */
|
||||||
|
|
||||||
|
/// Retrieves the total count of teams in the database.
|
||||||
|
Future<int> getTeamCount() async {
|
||||||
|
final count =
|
||||||
|
await (selectOnly(teamTable)..addColumns([teamTable.id.count()]))
|
||||||
|
.map((row) => row.read(teamTable.id.count()))
|
||||||
|
.getSingle();
|
||||||
|
return count ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a team with the given [teamId] exists in the database.
|
||||||
|
/// Returns `true` if the team exists, `false` otherwise.
|
||||||
|
Future<bool> teamExists({required String teamId}) async {
|
||||||
|
final query = select(teamTable)..where((t) => t.id.equals(teamId));
|
||||||
|
final result = await query.getSingleOrNull();
|
||||||
|
return result != null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieves all teams from the database.
|
/// Retrieves all teams from the database.
|
||||||
/// Note: This returns teams without their members. Use getTeamById for full team data.
|
|
||||||
Future<List<Team>> getAllTeams() async {
|
Future<List<Team>> getAllTeams() async {
|
||||||
final query = select(teamTable);
|
final query = select(teamTable);
|
||||||
final result = await query.get();
|
final result = await query.get();
|
||||||
@@ -41,8 +129,7 @@ class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper method to get team members from player_match_table.
|
/// Helper method to get team members from PlayerMatchTable.
|
||||||
/// This assumes team members are tracked via the player_match_table.
|
|
||||||
Future<List<Player>> _getTeamMembers({required String teamId}) async {
|
Future<List<Player>> _getTeamMembers({required String teamId}) async {
|
||||||
// Get all player_match entries with this teamId
|
// Get all player_match entries with this teamId
|
||||||
final playerMatchQuery = select(db.playerMatchTable)
|
final playerMatchQuery = select(db.playerMatchTable)
|
||||||
@@ -61,44 +148,28 @@ class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
|
|||||||
return players;
|
return players;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a new [team] to the database.
|
/* Update */
|
||||||
/// Returns `true` if the team was added, `false` otherwise.
|
|
||||||
Future<bool> addTeam({required Team team}) async {
|
/// Updates the name of the team with the given [teamId].
|
||||||
if (!await teamExists(teamId: team.id)) {
|
Future<bool> updateTeamName({
|
||||||
await into(teamTable).insert(
|
required String teamId,
|
||||||
TeamTableCompanion.insert(
|
required String newName,
|
||||||
id: team.id,
|
}) async {
|
||||||
name: team.name,
|
final rowsAffected =
|
||||||
createdAt: team.createdAt,
|
await (update(teamTable)..where((t) => t.id.equals(teamId))).write(
|
||||||
),
|
TeamTableCompanion(name: Value(newName)),
|
||||||
mode: InsertMode.insertOrReplace,
|
);
|
||||||
);
|
return rowsAffected > 0;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds multiple [teams] to the database in a batch operation.
|
/* Delete */
|
||||||
Future<bool> addTeamsAsList({required List<Team> teams}) async {
|
|
||||||
if (teams.isEmpty) return false;
|
|
||||||
|
|
||||||
await db.batch(
|
/// Deletes all teams from the database.
|
||||||
(b) => b.insertAll(
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
teamTable,
|
Future<bool> deleteAllTeams() async {
|
||||||
teams
|
final query = delete(teamTable);
|
||||||
.map(
|
final rowsAffected = await query.go();
|
||||||
(team) => TeamTableCompanion.insert(
|
return rowsAffected > 0;
|
||||||
id: team.id,
|
|
||||||
name: team.name,
|
|
||||||
createdAt: team.createdAt,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
mode: InsertMode.insertOrIgnore,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes the team with the given [teamId] from the database.
|
/// Deletes the team with the given [teamId] from the database.
|
||||||
@@ -108,39 +179,4 @@ class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
|
|||||||
final rowsAffected = await query.go();
|
final rowsAffected = await query.go();
|
||||||
return rowsAffected > 0;
|
return rowsAffected > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a team with the given [teamId] exists in the database.
|
|
||||||
/// Returns `true` if the team exists, `false` otherwise.
|
|
||||||
Future<bool> teamExists({required String teamId}) async {
|
|
||||||
final query = select(teamTable)..where((t) => t.id.equals(teamId));
|
|
||||||
final result = await query.getSingleOrNull();
|
|
||||||
return result != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the name of the team with the given [teamId].
|
|
||||||
Future<void> updateTeamName({
|
|
||||||
required String teamId,
|
|
||||||
required String newName,
|
|
||||||
}) async {
|
|
||||||
await (update(teamTable)..where((t) => t.id.equals(teamId))).write(
|
|
||||||
TeamTableCompanion(name: Value(newName)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the total count of teams in the database.
|
|
||||||
Future<int> getTeamCount() async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(teamTable)..addColumns([teamTable.id.count()]))
|
|
||||||
.map((row) => row.read(teamTable.id.count()))
|
|
||||||
.getSingle();
|
|
||||||
return count ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes all teams from the database.
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> deleteAllTeams() async {
|
|
||||||
final query = delete(teamTable);
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,12 @@ part of 'team_dao.dart';
|
|||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
mixin _$TeamDaoMixin on DatabaseAccessor<AppDatabase> {
|
mixin _$TeamDaoMixin on DatabaseAccessor<AppDatabase> {
|
||||||
$TeamTableTable get teamTable => attachedDatabase.teamTable;
|
$TeamTableTable get teamTable => attachedDatabase.teamTable;
|
||||||
|
$PlayerTableTable get playerTable => attachedDatabase.playerTable;
|
||||||
|
$GameTableTable get gameTable => attachedDatabase.gameTable;
|
||||||
|
$GroupTableTable get groupTable => attachedDatabase.groupTable;
|
||||||
|
$MatchTableTable get matchTable => attachedDatabase.matchTable;
|
||||||
|
$PlayerMatchTableTable get playerMatchTable =>
|
||||||
|
attachedDatabase.playerMatchTable;
|
||||||
TeamDaoManager get managers => TeamDaoManager(this);
|
TeamDaoManager get managers => TeamDaoManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,4 +19,17 @@ class TeamDaoManager {
|
|||||||
TeamDaoManager(this._db);
|
TeamDaoManager(this._db);
|
||||||
$$TeamTableTableTableManager get teamTable =>
|
$$TeamTableTableTableManager get teamTable =>
|
||||||
$$TeamTableTableTableManager(_db.attachedDatabase, _db.teamTable);
|
$$TeamTableTableTableManager(_db.attachedDatabase, _db.teamTable);
|
||||||
|
$$PlayerTableTableTableManager get playerTable =>
|
||||||
|
$$PlayerTableTableTableManager(_db.attachedDatabase, _db.playerTable);
|
||||||
|
$$GameTableTableTableManager get gameTable =>
|
||||||
|
$$GameTableTableTableManager(_db.attachedDatabase, _db.gameTable);
|
||||||
|
$$GroupTableTableTableManager get groupTable =>
|
||||||
|
$$GroupTableTableTableManager(_db.attachedDatabase, _db.groupTable);
|
||||||
|
$$MatchTableTableTableManager get matchTable =>
|
||||||
|
$$MatchTableTableTableManager(_db.attachedDatabase, _db.matchTable);
|
||||||
|
$$PlayerMatchTableTableTableManager get playerMatchTable =>
|
||||||
|
$$PlayerMatchTableTableTableManager(
|
||||||
|
_db.attachedDatabase,
|
||||||
|
_db.playerMatchTable,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2122,7 +2122,7 @@ class $PlayerMatchTableTable extends PlayerMatchTable
|
|||||||
type: DriftSqlType.string,
|
type: DriftSqlType.string,
|
||||||
requiredDuringInsert: false,
|
requiredDuringInsert: false,
|
||||||
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
||||||
'REFERENCES team_table (id)',
|
'REFERENCES team_table (id) ON DELETE SET NULL',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
@@ -2820,6 +2820,13 @@ abstract class _$AppDatabase extends GeneratedDatabase {
|
|||||||
),
|
),
|
||||||
result: [TableUpdate('player_match_table', kind: UpdateKind.delete)],
|
result: [TableUpdate('player_match_table', kind: UpdateKind.delete)],
|
||||||
),
|
),
|
||||||
|
WritePropagation(
|
||||||
|
on: TableUpdateQuery.onTableName(
|
||||||
|
'team_table',
|
||||||
|
limitUpdateKind: UpdateKind.delete,
|
||||||
|
),
|
||||||
|
result: [TableUpdate('player_match_table', kind: UpdateKind.update)],
|
||||||
|
),
|
||||||
WritePropagation(
|
WritePropagation(
|
||||||
on: TableUpdateQuery.onTableName(
|
on: TableUpdateQuery.onTableName(
|
||||||
'player_table',
|
'player_table',
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ class PlayerMatchTable extends Table {
|
|||||||
text().references(PlayerTable, #id, onDelete: KeyAction.cascade)();
|
text().references(PlayerTable, #id, onDelete: KeyAction.cascade)();
|
||||||
TextColumn get matchId =>
|
TextColumn get matchId =>
|
||||||
text().references(MatchTable, #id, onDelete: KeyAction.cascade)();
|
text().references(MatchTable, #id, onDelete: KeyAction.cascade)();
|
||||||
TextColumn get teamId => text().references(TeamTable, #id).nullable()();
|
TextColumn get teamId => text()
|
||||||
|
.references(TeamTable, #id, onDelete: KeyAction.setNull)
|
||||||
|
.nullable()();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Set<Column<Object>> get primaryKey => {playerId, matchId};
|
Set<Column<Object>> get primaryKey => {playerId, matchId};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:tallee/data/models/game.dart';
|
|||||||
import 'package:tallee/data/models/group.dart';
|
import 'package:tallee/data/models/group.dart';
|
||||||
import 'package:tallee/data/models/player.dart';
|
import 'package:tallee/data/models/player.dart';
|
||||||
import 'package:tallee/data/models/score_entry.dart';
|
import 'package:tallee/data/models/score_entry.dart';
|
||||||
|
import 'package:tallee/data/models/team.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class Match {
|
class Match {
|
||||||
@@ -14,6 +15,7 @@ class Match {
|
|||||||
final Game game;
|
final Game game;
|
||||||
final Group? group;
|
final Group? group;
|
||||||
final List<Player> players;
|
final List<Player> players;
|
||||||
|
final List<Team>? teams;
|
||||||
final String notes;
|
final String notes;
|
||||||
Map<String, ScoreEntry?> scores;
|
Map<String, ScoreEntry?> scores;
|
||||||
|
|
||||||
@@ -23,6 +25,7 @@ class Match {
|
|||||||
required this.players,
|
required this.players,
|
||||||
this.endedAt,
|
this.endedAt,
|
||||||
this.group,
|
this.group,
|
||||||
|
this.teams,
|
||||||
this.notes = '',
|
this.notes = '',
|
||||||
String? id,
|
String? id,
|
||||||
DateTime? createdAt,
|
DateTime? createdAt,
|
||||||
@@ -55,6 +58,7 @@ class Match {
|
|||||||
),
|
),
|
||||||
group = null,
|
group = null,
|
||||||
players = [],
|
players = [],
|
||||||
|
teams = [],
|
||||||
scores = json['scores'] != null
|
scores = json['scores'] != null
|
||||||
? (json['scores'] as Map<String, dynamic>).map(
|
? (json['scores'] as Map<String, dynamic>).map(
|
||||||
(key, value) => MapEntry(
|
(key, value) => MapEntry(
|
||||||
@@ -78,6 +82,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(),
|
||||||
|
'teams': teams?.map((team) => team.toJson()).toList(),
|
||||||
'scores': scores.map((key, value) => MapEntry(key, value?.toJson())),
|
'scores': scores.map((key, value) => MapEntry(key, value?.toJson())),
|
||||||
'notes': notes,
|
'notes': notes,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,13 +35,11 @@ class DataTransferService {
|
|||||||
final groups = await db.groupDao.getAllGroups();
|
final groups = await db.groupDao.getAllGroups();
|
||||||
final players = await db.playerDao.getAllPlayers();
|
final players = await db.playerDao.getAllPlayers();
|
||||||
final games = await db.gameDao.getAllGames();
|
final games = await db.gameDao.getAllGames();
|
||||||
final teams = await db.teamDao.getAllTeams();
|
|
||||||
|
|
||||||
final Map<String, dynamic> jsonMap = {
|
final Map<String, dynamic> jsonMap = {
|
||||||
'players': players.map((player) => player.toJson()).toList(),
|
'players': players.map((player) => player.toJson()).toList(),
|
||||||
'games': games.map((game) => game.toJson()).toList(),
|
'games': games.map((game) => game.toJson()).toList(),
|
||||||
'groups': groups.map((group) => group.toJson()).toList(),
|
'groups': groups.map((group) => group.toJson()).toList(),
|
||||||
'teams': teams.map((team) => team.toJson()).toList(),
|
|
||||||
'matches': matches.map((match) => match.toJson()).toList(),
|
'matches': matches.map((match) => match.toJson()).toList(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -130,8 +128,6 @@ class DataTransferService {
|
|||||||
final importedGroups = parseGroupsFromJson(decodedJson, playerById);
|
final importedGroups = parseGroupsFromJson(decodedJson, playerById);
|
||||||
final groupById = {for (final g in importedGroups) g.id: g};
|
final groupById = {for (final g in importedGroups) g.id: g};
|
||||||
|
|
||||||
final importedTeams = parseTeamsFromJson(decodedJson, playerById);
|
|
||||||
|
|
||||||
final importedMatches = parseMatchesFromJson(
|
final importedMatches = parseMatchesFromJson(
|
||||||
decodedJson,
|
decodedJson,
|
||||||
gameById,
|
gameById,
|
||||||
@@ -142,7 +138,6 @@ class DataTransferService {
|
|||||||
await db.playerDao.addPlayersAsList(players: importedPlayers);
|
await db.playerDao.addPlayersAsList(players: importedPlayers);
|
||||||
await db.gameDao.addGamesAsList(games: importedGames);
|
await db.gameDao.addGamesAsList(games: importedGames);
|
||||||
await db.groupDao.addGroupsAsList(groups: importedGroups);
|
await db.groupDao.addGroupsAsList(groups: importedGroups);
|
||||||
await db.teamDao.addTeamsAsList(teams: importedTeams);
|
|
||||||
await db.matchDao.addMatchesAsList(matches: importedMatches);
|
await db.matchDao.addMatchesAsList(matches: importedMatches);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,13 +185,12 @@ class DataTransferService {
|
|||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses teams from JSON data.
|
/// Parses teams from a list of JSON objects.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
static List<Team> parseTeamsFromJson(
|
static List<Team> parseTeamsFromJson(
|
||||||
Map<String, dynamic> decodedJson,
|
List<dynamic> teamsJson,
|
||||||
Map<String, Player> playerById,
|
Map<String, Player> playerById,
|
||||||
) {
|
) {
|
||||||
final teamsJson = (decodedJson['teams'] as List<dynamic>?) ?? [];
|
|
||||||
return teamsJson.map((t) {
|
return teamsJson.map((t) {
|
||||||
final map = t as Map<String, dynamic>;
|
final map = t as Map<String, dynamic>;
|
||||||
final memberIds = (map['memberIds'] as List<dynamic>? ?? [])
|
final memberIds = (map['memberIds'] as List<dynamic>? ?? [])
|
||||||
@@ -259,12 +253,16 @@ class DataTransferService {
|
|||||||
.whereType<Player>()
|
.whereType<Player>()
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
|
final teamsJson = (map['teams'] as List<dynamic>?) ?? [];
|
||||||
|
final teams = parseTeamsFromJson(teamsJson, playersMap);
|
||||||
|
|
||||||
return Match(
|
return Match(
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
game: game,
|
game: game,
|
||||||
group: group,
|
group: group,
|
||||||
players: players,
|
players: players,
|
||||||
|
teams: teams.isEmpty ? null : teams,
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
endedAt: endedAt,
|
endedAt: endedAt,
|
||||||
notes: notes,
|
notes: notes,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:core' hide Match;
|
||||||
|
|
||||||
import 'package:clock/clock.dart';
|
import 'package:clock/clock.dart';
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:drift/native.dart';
|
import 'package:drift/native.dart';
|
||||||
@@ -18,8 +20,11 @@ void main() {
|
|||||||
late Team testTeam1;
|
late Team testTeam1;
|
||||||
late Team testTeam2;
|
late Team testTeam2;
|
||||||
late Team testTeam3;
|
late Team testTeam3;
|
||||||
late Game testGame1;
|
late Team testTeam4;
|
||||||
late Game testGame2;
|
late Game testGame;
|
||||||
|
late Match testMatch1;
|
||||||
|
late Match testMatch2;
|
||||||
|
late Match matchWithNoTeams;
|
||||||
final fixedDate = DateTime(2025, 11, 19, 00, 11, 23);
|
final fixedDate = DateTime(2025, 11, 19, 00, 11, 23);
|
||||||
final fakeClock = Clock(() => fixedDate);
|
final fakeClock = Clock(() => fixedDate);
|
||||||
|
|
||||||
@@ -40,27 +45,35 @@ void main() {
|
|||||||
testTeam1 = Team(name: 'Team Alpha', members: [testPlayer1, testPlayer2]);
|
testTeam1 = Team(name: 'Team Alpha', members: [testPlayer1, testPlayer2]);
|
||||||
testTeam2 = Team(name: 'Team Beta', members: [testPlayer3, testPlayer4]);
|
testTeam2 = Team(name: 'Team Beta', members: [testPlayer3, testPlayer4]);
|
||||||
testTeam3 = Team(name: 'Team Gamma', members: [testPlayer1, testPlayer3]);
|
testTeam3 = Team(name: 'Team Gamma', members: [testPlayer1, testPlayer3]);
|
||||||
testGame1 = Game(
|
testTeam4 = Team(name: 'Team Omega', members: [testPlayer2, testPlayer4]);
|
||||||
name: 'Game 1',
|
testGame = Game(
|
||||||
ruleset: Ruleset.singleWinner,
|
name: 'Test Game',
|
||||||
description: 'Test game 1',
|
ruleset: Ruleset.highestScore,
|
||||||
color: GameColor.blue,
|
color: GameColor.blue,
|
||||||
icon: '',
|
icon: '',
|
||||||
);
|
);
|
||||||
testGame2 = Game(
|
testMatch1 = Match(
|
||||||
name: 'Game 2',
|
name: 'Match 1',
|
||||||
ruleset: Ruleset.highestScore,
|
game: testGame,
|
||||||
description: 'Test game 2',
|
players: [],
|
||||||
color: GameColor.red,
|
teams: [testTeam1, testTeam2],
|
||||||
icon: '',
|
);
|
||||||
|
testMatch2 = Match(
|
||||||
|
name: 'Match 2',
|
||||||
|
game: testGame,
|
||||||
|
players: [],
|
||||||
|
teams: [testTeam3, testTeam4],
|
||||||
|
);
|
||||||
|
matchWithNoTeams = Match(
|
||||||
|
name: 'Match with no teams',
|
||||||
|
game: testGame,
|
||||||
|
players: [testPlayer1, testPlayer2, testPlayer3, testPlayer4],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
await database.gameDao.addGame(game: testGame);
|
||||||
await database.playerDao.addPlayersAsList(
|
await database.playerDao.addPlayersAsList(
|
||||||
players: [testPlayer1, testPlayer2, testPlayer3, testPlayer4],
|
players: [testPlayer1, testPlayer2, testPlayer3, testPlayer4],
|
||||||
);
|
);
|
||||||
await database.gameDao.addGame(game: testGame1);
|
|
||||||
await database.gameDao.addGame(game: testGame2);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() async {
|
tearDown(() async {
|
||||||
@@ -68,460 +81,251 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
group('Team Tests', () {
|
group('Team Tests', () {
|
||||||
// Verifies that a single team can be added and retrieved with all fields intact.
|
group('CREATE', () {
|
||||||
test('Adding and fetching a single team works correctly', () async {
|
test('Adding and fetching a single team works correctly', () async {
|
||||||
final added = await database.teamDao.addTeam(team: testTeam1);
|
await database.matchDao.addMatch(match: matchWithNoTeams);
|
||||||
expect(added, true);
|
final added = await database.teamDao.addTeam(
|
||||||
|
team: testTeam1,
|
||||||
final fetchedTeam = await database.teamDao.getTeamById(
|
matchId: matchWithNoTeams.id,
|
||||||
teamId: testTeam1.id,
|
);
|
||||||
);
|
expect(added, isTrue);
|
||||||
|
|
||||||
expect(fetchedTeam.id, testTeam1.id);
|
final fetchedTeam = await database.teamDao.getTeamById(
|
||||||
expect(fetchedTeam.name, testTeam1.name);
|
teamId: testTeam1.id,
|
||||||
expect(fetchedTeam.createdAt, testTeam1.createdAt);
|
);
|
||||||
});
|
|
||||||
|
expect(fetchedTeam.id, testTeam1.id);
|
||||||
// Verifies that multiple teams can be added at once and retrieved correctly.
|
expect(fetchedTeam.name, testTeam1.name);
|
||||||
test('Adding and fetching multiple teams works correctly', () async {
|
expect(fetchedTeam.createdAt, testTeam1.createdAt);
|
||||||
await database.teamDao.addTeamsAsList(
|
expect(fetchedTeam.members.length, testTeam1.members.length);
|
||||||
teams: [testTeam1, testTeam2, testTeam3],
|
for (int i = 0; i < fetchedTeam.members.length; i++) {
|
||||||
);
|
expect(fetchedTeam.members[i].id, testTeam1.members[i].id);
|
||||||
|
expect(fetchedTeam.members[i].name, testTeam1.members[i].name);
|
||||||
final allTeams = await database.teamDao.getAllTeams();
|
}
|
||||||
expect(allTeams.length, 3);
|
});
|
||||||
|
|
||||||
final testTeams = {
|
test('Adding and fetching multiple teams works correctly', () async {
|
||||||
testTeam1.id: testTeam1,
|
await database.matchDao.addMatch(match: matchWithNoTeams);
|
||||||
testTeam2.id: testTeam2,
|
await database.teamDao.addTeamsAsList(
|
||||||
testTeam3.id: testTeam3,
|
teams: [testTeam1, testTeam2, testTeam3],
|
||||||
};
|
matchId: matchWithNoTeams.id,
|
||||||
|
);
|
||||||
for (final team in allTeams) {
|
|
||||||
final testTeam = testTeams[team.id]!;
|
final allTeams = await database.teamDao.getAllTeams();
|
||||||
|
expect(allTeams.length, 3);
|
||||||
expect(team.id, testTeam.id);
|
|
||||||
expect(team.name, testTeam.name);
|
final testTeams = {
|
||||||
expect(team.createdAt, testTeam.createdAt);
|
testTeam1.id: testTeam1,
|
||||||
}
|
testTeam2.id: testTeam2,
|
||||||
});
|
testTeam3.id: testTeam3,
|
||||||
|
};
|
||||||
// Verifies that adding the same team twice does not create duplicates and returns false.
|
|
||||||
test('Adding the same team twice does not create duplicates', () async {
|
for (final team in allTeams) {
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
final testTeam = testTeams[team.id]!;
|
||||||
final addedAgain = await database.teamDao.addTeam(team: testTeam1);
|
|
||||||
|
expect(team.id, testTeam.id);
|
||||||
expect(addedAgain, false);
|
expect(team.name, testTeam.name);
|
||||||
|
expect(team.createdAt, testTeam.createdAt);
|
||||||
final teamCount = await database.teamDao.getTeamCount();
|
}
|
||||||
expect(teamCount, 1);
|
});
|
||||||
});
|
|
||||||
|
test('addTeam() ignores duplicates', () async {
|
||||||
// Verifies that teamExists returns correct boolean based on team presence.
|
await database.matchDao.addMatch(match: matchWithNoTeams);
|
||||||
test('Team existence check works correctly', () async {
|
var added = await database.teamDao.addTeam(
|
||||||
var teamExists = await database.teamDao.teamExists(teamId: testTeam1.id);
|
team: testTeam1,
|
||||||
expect(teamExists, false);
|
matchId: matchWithNoTeams.id,
|
||||||
|
);
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
expect(added, isTrue);
|
||||||
|
|
||||||
teamExists = await database.teamDao.teamExists(teamId: testTeam1.id);
|
added = await database.teamDao.addTeam(
|
||||||
expect(teamExists, true);
|
team: testTeam1,
|
||||||
});
|
matchId: matchWithNoTeams.id,
|
||||||
|
);
|
||||||
// Verifies that deleteTeam removes the team and returns true.
|
expect(added, isFalse);
|
||||||
test('Deleting a team works correctly', () async {
|
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
final teamCount = await database.teamDao.getTeamCount();
|
||||||
|
expect(teamCount, 1);
|
||||||
final teamDeleted = await database.teamDao.deleteTeam(
|
});
|
||||||
teamId: testTeam1.id,
|
|
||||||
);
|
test('addTeamsAsList() with empty list returns isFalse', () async {
|
||||||
expect(teamDeleted, true);
|
final added = await database.teamDao.addTeamsAsList(
|
||||||
|
teams: [],
|
||||||
final teamExists = await database.teamDao.teamExists(
|
matchId: matchWithNoTeams.id,
|
||||||
teamId: testTeam1.id,
|
);
|
||||||
);
|
expect(added, isFalse);
|
||||||
expect(teamExists, false);
|
});
|
||||||
});
|
|
||||||
|
test('addTeamsAsList() ignores duplicates', () async {
|
||||||
// Verifies that deleteTeam returns false for a non-existent team ID.
|
await database.matchDao.addMatch(match: matchWithNoTeams);
|
||||||
test('Deleting a non-existent team returns false', () async {
|
final added = await database.teamDao.addTeamsAsList(
|
||||||
final teamDeleted = await database.teamDao.deleteTeam(
|
teams: [testTeam1, testTeam2, testTeam1],
|
||||||
teamId: 'non-existent-id',
|
matchId: matchWithNoTeams.id,
|
||||||
);
|
);
|
||||||
expect(teamDeleted, false);
|
expect(added, isTrue);
|
||||||
});
|
|
||||||
|
final teamCount = await database.teamDao.getTeamCount();
|
||||||
// Verifies that getTeamCount returns correct count through add/delete operations.
|
expect(teamCount, 2);
|
||||||
test('Getting the team count works correctly', () async {
|
|
||||||
var teamCount = await database.teamDao.getTeamCount();
|
|
||||||
expect(teamCount, 0);
|
|
||||||
|
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
|
||||||
|
|
||||||
teamCount = await database.teamDao.getTeamCount();
|
|
||||||
expect(teamCount, 1);
|
|
||||||
|
|
||||||
await database.teamDao.addTeam(team: testTeam2);
|
|
||||||
|
|
||||||
teamCount = await database.teamDao.getTeamCount();
|
|
||||||
expect(teamCount, 2);
|
|
||||||
|
|
||||||
await database.teamDao.deleteTeam(teamId: testTeam1.id);
|
|
||||||
|
|
||||||
teamCount = await database.teamDao.getTeamCount();
|
|
||||||
expect(teamCount, 1);
|
|
||||||
|
|
||||||
await database.teamDao.deleteTeam(teamId: testTeam2.id);
|
|
||||||
|
|
||||||
teamCount = await database.teamDao.getTeamCount();
|
|
||||||
expect(teamCount, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that updateTeamName correctly updates only the name field.
|
|
||||||
test('Updating team name works correctly', () async {
|
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
|
||||||
|
|
||||||
var fetchedTeam = await database.teamDao.getTeamById(
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
);
|
|
||||||
expect(fetchedTeam.name, testTeam1.name);
|
|
||||||
|
|
||||||
const newName = 'Updated Team Name';
|
|
||||||
await database.teamDao.updateTeamName(
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
newName: newName,
|
|
||||||
);
|
|
||||||
|
|
||||||
fetchedTeam = await database.teamDao.getTeamById(teamId: testTeam1.id);
|
|
||||||
expect(fetchedTeam.name, newName);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that deleteAllTeams removes all teams from the database.
|
|
||||||
test('Deleting all teams works correctly', () async {
|
|
||||||
await database.teamDao.addTeamsAsList(
|
|
||||||
teams: [testTeam1, testTeam2, testTeam3],
|
|
||||||
);
|
|
||||||
|
|
||||||
var teamCount = await database.teamDao.getTeamCount();
|
|
||||||
expect(teamCount, 3);
|
|
||||||
|
|
||||||
final deleted = await database.teamDao.deleteAllTeams();
|
|
||||||
expect(deleted, true);
|
|
||||||
|
|
||||||
teamCount = await database.teamDao.getTeamCount();
|
|
||||||
expect(teamCount, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that deleteAllTeams returns false when no teams exist.
|
|
||||||
test('Deleting all teams when empty returns false', () async {
|
|
||||||
final deleted = await database.teamDao.deleteAllTeams();
|
|
||||||
expect(deleted, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that addTeamsAsList returns false when given an empty list.
|
|
||||||
test('Adding teams as list with empty list returns false', () async {
|
|
||||||
final added = await database.teamDao.addTeamsAsList(teams: []);
|
|
||||||
expect(added, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that addTeamsAsList with duplicate IDs ignores duplicates and keeps the first.
|
|
||||||
test('Adding teams with duplicate IDs ignores duplicates', () async {
|
|
||||||
final duplicateTeam = Team(
|
|
||||||
id: testTeam1.id,
|
|
||||||
name: 'Duplicate Team',
|
|
||||||
members: [testPlayer4],
|
|
||||||
);
|
|
||||||
|
|
||||||
await database.teamDao.addTeamsAsList(
|
|
||||||
teams: [testTeam1, duplicateTeam, testTeam2],
|
|
||||||
);
|
|
||||||
|
|
||||||
final teamCount = await database.teamDao.getTeamCount();
|
|
||||||
expect(teamCount, 2);
|
|
||||||
|
|
||||||
// The first one should be kept (insertOrIgnore)
|
|
||||||
final fetchedTeam = await database.teamDao.getTeamById(
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
);
|
|
||||||
expect(fetchedTeam.name, testTeam1.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that getAllTeams returns empty list when no teams exist.
|
|
||||||
test('Getting all teams when empty returns empty list', () async {
|
|
||||||
final allTeams = await database.teamDao.getAllTeams();
|
|
||||||
expect(allTeams.isEmpty, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that getTeamById throws exception for non-existent team.
|
|
||||||
test('Getting non-existent team throws exception', () async {
|
|
||||||
expect(
|
|
||||||
() => database.teamDao.getTeamById(teamId: 'non-existent-id'),
|
|
||||||
throwsA(isA<StateError>()),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that updating team name preserves other fields.
|
|
||||||
test('Updating team name preserves other team fields', () async {
|
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
|
||||||
final originalTeam = await database.teamDao.getTeamById(
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
);
|
|
||||||
final originalCreatedAt = originalTeam.createdAt;
|
|
||||||
|
|
||||||
const newName = 'Brand New Team Name';
|
|
||||||
await database.teamDao.updateTeamName(
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
newName: newName,
|
|
||||||
);
|
|
||||||
|
|
||||||
final updatedTeam = await database.teamDao.getTeamById(
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(updatedTeam.name, newName);
|
|
||||||
expect(updatedTeam.id, testTeam1.id);
|
|
||||||
expect(updatedTeam.createdAt, originalCreatedAt);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that team name can be updated to an empty string.
|
|
||||||
test('Updating team name to empty string works', () async {
|
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
|
||||||
|
|
||||||
await database.teamDao.updateTeamName(teamId: testTeam1.id, newName: '');
|
|
||||||
|
|
||||||
final updatedTeam = await database.teamDao.getTeamById(
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(updatedTeam.name, '');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that team name can be updated to a very long string.
|
|
||||||
test('Updating team name to long string works', () async {
|
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
|
||||||
final longName = 'A' * 500; // 500 character name
|
|
||||||
|
|
||||||
await database.teamDao.updateTeamName(
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
newName: longName,
|
|
||||||
);
|
|
||||||
|
|
||||||
final updatedTeam = await database.teamDao.getTeamById(
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(updatedTeam.name, longName);
|
|
||||||
expect(updatedTeam.name.length, 500);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that updating non-existent team name doesn't throw error.
|
|
||||||
test('Updating non-existent team name completes without error', () async {
|
|
||||||
expect(
|
|
||||||
() => database.teamDao.updateTeamName(
|
|
||||||
teamId: 'non-existent-id',
|
|
||||||
newName: 'New Name',
|
|
||||||
),
|
|
||||||
returnsNormally,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that deleteTeam only affects the specified team.
|
|
||||||
test('Deleting one team does not affect other teams', () async {
|
|
||||||
await database.teamDao.addTeamsAsList(
|
|
||||||
teams: [testTeam1, testTeam2, testTeam3],
|
|
||||||
);
|
|
||||||
|
|
||||||
await database.teamDao.deleteTeam(teamId: testTeam2.id);
|
|
||||||
|
|
||||||
final allTeams = await database.teamDao.getAllTeams();
|
|
||||||
expect(allTeams.length, 2);
|
|
||||||
expect(allTeams.any((t) => t.id == testTeam1.id), true);
|
|
||||||
expect(allTeams.any((t) => t.id == testTeam2.id), false);
|
|
||||||
expect(allTeams.any((t) => t.id == testTeam3.id), true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that teams with overlapping members are independent.
|
|
||||||
test('Teams with overlapping members are independent', () async {
|
|
||||||
// Create two matches since player_match has primary key {playerId, matchId}
|
|
||||||
final match1 = Match(
|
|
||||||
name: 'Match 1',
|
|
||||||
game: testGame1,
|
|
||||||
players: [testPlayer1, testPlayer2],
|
|
||||||
);
|
|
||||||
final match2 = Match(
|
|
||||||
name: 'Match 2',
|
|
||||||
game: testGame2,
|
|
||||||
players: [testPlayer1, testPlayer2],
|
|
||||||
);
|
|
||||||
await database.matchDao.addMatch(match: match1);
|
|
||||||
await database.matchDao.addMatch(match: match2);
|
|
||||||
|
|
||||||
// Add teams to database
|
|
||||||
await database.teamDao.addTeamsAsList(teams: [testTeam1, testTeam3]);
|
|
||||||
|
|
||||||
// Associate players with teams through match1
|
|
||||||
// testTeam1: player1, player2
|
|
||||||
await database.playerMatchDao.addPlayerToMatch(
|
|
||||||
playerId: testPlayer1.id,
|
|
||||||
matchId: match1.id,
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
);
|
|
||||||
await database.playerMatchDao.addPlayerToMatch(
|
|
||||||
playerId: testPlayer2.id,
|
|
||||||
matchId: match1.id,
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Associate players with teams through match2
|
|
||||||
// testTeam3: player1, player3 (overlapping player1)
|
|
||||||
await database.playerMatchDao.addPlayerToMatch(
|
|
||||||
playerId: testPlayer1.id,
|
|
||||||
matchId: match2.id,
|
|
||||||
teamId: testTeam3.id,
|
|
||||||
);
|
|
||||||
await database.playerMatchDao.addPlayerToMatch(
|
|
||||||
playerId: testPlayer3.id,
|
|
||||||
matchId: match2.id,
|
|
||||||
teamId: testTeam3.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
final team1 = await database.teamDao.getTeamById(teamId: testTeam1.id);
|
|
||||||
final team3 = await database.teamDao.getTeamById(teamId: testTeam3.id);
|
|
||||||
|
|
||||||
expect(team1.members.length, 2);
|
|
||||||
expect(team3.members.length, 2);
|
|
||||||
expect(team1.members.any((p) => p.id == testPlayer1.id), true);
|
|
||||||
expect(team3.members.any((p) => p.id == testPlayer1.id), true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that adding teams sequentially works correctly.
|
|
||||||
test('Adding teams sequentially maintains correct count', () async {
|
|
||||||
var count = await database.teamDao.getTeamCount();
|
|
||||||
expect(count, 0);
|
|
||||||
|
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
|
||||||
count = await database.teamDao.getTeamCount();
|
|
||||||
expect(count, 1);
|
|
||||||
|
|
||||||
await database.teamDao.addTeam(team: testTeam2);
|
|
||||||
count = await database.teamDao.getTeamCount();
|
|
||||||
expect(count, 2);
|
|
||||||
|
|
||||||
await database.teamDao.addTeam(team: testTeam3);
|
|
||||||
count = await database.teamDao.getTeamCount();
|
|
||||||
expect(count, 3);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that getAllTeams returns all teams with correct data.
|
|
||||||
test('Getting all teams returns all teams with correct data', () async {
|
|
||||||
await database.teamDao.addTeamsAsList(
|
|
||||||
teams: [testTeam1, testTeam2, testTeam3],
|
|
||||||
);
|
|
||||||
|
|
||||||
final allTeams = await database.teamDao.getAllTeams();
|
|
||||||
|
|
||||||
expect(allTeams.length, 3);
|
|
||||||
expect(allTeams.map((t) => t.id).toSet(), {
|
|
||||||
testTeam1.id,
|
|
||||||
testTeam2.id,
|
|
||||||
testTeam3.id,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verifies that teamExists returns false for deleted teams.
|
group('READ', () {
|
||||||
test('Team existence returns false after deletion', () async {
|
test('getTeamCount works correctly', () async {
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
var count = await database.teamDao.getTeamCount();
|
||||||
expect(await database.teamDao.teamExists(teamId: testTeam1.id), true);
|
expect(count, 0);
|
||||||
|
|
||||||
await database.teamDao.deleteTeam(teamId: testTeam1.id);
|
await database.matchDao.addMatch(match: testMatch1);
|
||||||
expect(await database.teamDao.teamExists(teamId: testTeam1.id), false);
|
|
||||||
|
count = await database.teamDao.getTeamCount();
|
||||||
|
expect(count, 2);
|
||||||
|
|
||||||
|
await database.teamDao.addTeam(
|
||||||
|
team: testTeam2,
|
||||||
|
matchId: matchWithNoTeams.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
count = await database.teamDao.getTeamCount();
|
||||||
|
expect(count, 2);
|
||||||
|
|
||||||
|
await database.teamDao.deleteTeam(teamId: testTeam1.id);
|
||||||
|
|
||||||
|
count = await database.teamDao.getTeamCount();
|
||||||
|
expect(count, 1);
|
||||||
|
|
||||||
|
await database.teamDao.deleteTeam(teamId: testTeam2.id);
|
||||||
|
|
||||||
|
count = await database.teamDao.getTeamCount();
|
||||||
|
expect(count, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('teamExists() works correctly', () async {
|
||||||
|
var teamExists = await database.teamDao.teamExists(
|
||||||
|
teamId: testTeam1.id,
|
||||||
|
);
|
||||||
|
expect(teamExists, isFalse);
|
||||||
|
|
||||||
|
await database.matchDao.addMatch(match: matchWithNoTeams);
|
||||||
|
|
||||||
|
await database.teamDao.addTeam(
|
||||||
|
team: testTeam1,
|
||||||
|
matchId: matchWithNoTeams.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
teamExists = await database.teamDao.teamExists(teamId: testTeam1.id);
|
||||||
|
expect(teamExists, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getAllTeams() with no teams returns empty list', () async {
|
||||||
|
final allTeams = await database.teamDao.getAllTeams();
|
||||||
|
expect(allTeams, isA<List<Team>>());
|
||||||
|
expect(allTeams.isEmpty, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getAllTeams() works correctly', () async {
|
||||||
|
await database.matchDao.addMatch(match: matchWithNoTeams);
|
||||||
|
|
||||||
|
await database.teamDao.addTeamsAsList(
|
||||||
|
teams: [testTeam1, testTeam2, testTeam3],
|
||||||
|
matchId: matchWithNoTeams.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
final allTeams = await database.teamDao.getAllTeams();
|
||||||
|
|
||||||
|
expect(allTeams.length, 3);
|
||||||
|
expect(allTeams.map((t) => t.id).toSet(), {
|
||||||
|
testTeam1.id,
|
||||||
|
testTeam2.id,
|
||||||
|
testTeam3.id,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Getting non-existent team throws exception', () async {
|
||||||
|
expect(
|
||||||
|
() => database.teamDao.getTeamById(teamId: 'non-existent-id'),
|
||||||
|
throwsA(isA<StateError>()),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verifies that adding multiple teams in batch then deleting returns correct count.
|
group('UPDATED', () {
|
||||||
test('Batch add then partial delete maintains correct count', () async {
|
test('updateTeamName() works correctly', () async {
|
||||||
await database.teamDao.addTeamsAsList(
|
await database.matchDao.addMatch(match: matchWithNoTeams);
|
||||||
teams: [testTeam1, testTeam2, testTeam3],
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(await database.teamDao.getTeamCount(), 3);
|
await database.teamDao.addTeam(
|
||||||
|
team: testTeam1,
|
||||||
|
matchId: matchWithNoTeams.id,
|
||||||
|
);
|
||||||
|
|
||||||
await database.teamDao.deleteTeam(teamId: testTeam1.id);
|
var fetchedTeam = await database.teamDao.getTeamById(
|
||||||
expect(await database.teamDao.getTeamCount(), 2);
|
teamId: testTeam1.id,
|
||||||
|
);
|
||||||
|
expect(fetchedTeam.name, testTeam1.name);
|
||||||
|
|
||||||
await database.teamDao.deleteTeam(teamId: testTeam3.id);
|
const newName = 'New name';
|
||||||
expect(await database.teamDao.getTeamCount(), 1);
|
await database.teamDao.updateTeamName(
|
||||||
|
teamId: testTeam1.id,
|
||||||
|
newName: newName,
|
||||||
|
);
|
||||||
|
|
||||||
|
fetchedTeam = await database.teamDao.getTeamById(teamId: testTeam1.id);
|
||||||
|
expect(fetchedTeam.name, newName);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('updateTeamName() does nothing for non-existent team', () async {
|
||||||
|
final updated = await database.teamDao.updateTeamName(
|
||||||
|
teamId: 'non-existing-id',
|
||||||
|
newName: 'New Name',
|
||||||
|
);
|
||||||
|
expect(updated, isFalse);
|
||||||
|
|
||||||
|
final allTeams = await database.teamDao.getAllTeams();
|
||||||
|
expect(allTeams, isEmpty);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verifies that deleteAllTeams with single team works.
|
group('DELETE', () {
|
||||||
test('Deleting all teams with single team returns true', () async {
|
test('deleteTeam() works correctly', () async {
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
await database.matchDao.addMatch(match: testMatch1);
|
||||||
expect(await database.teamDao.getTeamCount(), 1);
|
await database.matchDao.addMatch(match: matchWithNoTeams);
|
||||||
|
|
||||||
final deleted = await database.teamDao.deleteAllTeams();
|
await database.teamDao.addTeam(
|
||||||
expect(deleted, true);
|
team: testTeam1,
|
||||||
expect(await database.teamDao.getTeamCount(), 0);
|
matchId: matchWithNoTeams.id,
|
||||||
});
|
);
|
||||||
|
|
||||||
// Verifies that addTeam after deleteAllTeams works correctly.
|
final deleted = await database.teamDao.deleteTeam(teamId: testTeam1.id);
|
||||||
test('Adding team after deleteAllTeams works correctly', () async {
|
expect(deleted, isTrue);
|
||||||
await database.teamDao.addTeamsAsList(teams: [testTeam1, testTeam2]);
|
|
||||||
expect(await database.teamDao.getTeamCount(), 2);
|
|
||||||
|
|
||||||
await database.teamDao.deleteAllTeams();
|
final teamExists = await database.teamDao.teamExists(
|
||||||
expect(await database.teamDao.getTeamCount(), 0);
|
teamId: testTeam1.id,
|
||||||
|
);
|
||||||
|
expect(teamExists, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
final added = await database.teamDao.addTeam(team: testTeam3);
|
test('Deleting a non-existent team returns isFalse', () async {
|
||||||
expect(added, true);
|
final deleted = await database.teamDao.deleteTeam(
|
||||||
expect(await database.teamDao.getTeamCount(), 1);
|
teamId: 'non-existent-id',
|
||||||
|
);
|
||||||
|
expect(deleted, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
final fetchedTeam = await database.teamDao.getTeamById(
|
test('deleteAllTeams() works correctly', () async {
|
||||||
teamId: testTeam3.id,
|
await database.matchDao.addMatchesAsList(
|
||||||
);
|
matches: [testMatch1, testMatch2],
|
||||||
expect(fetchedTeam.name, testTeam3.name);
|
);
|
||||||
});
|
var teamCount = await database.teamDao.getTeamCount();
|
||||||
|
expect(teamCount, 4);
|
||||||
|
|
||||||
// Verifies that addTeamsAsList with partial duplicates ignores duplicates.
|
final deleted = await database.teamDao.deleteAllTeams();
|
||||||
test('Adding teams with some duplicates ignores only duplicates', () async {
|
expect(deleted, isTrue);
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
|
||||||
|
|
||||||
final duplicateTeam1 = Team(
|
teamCount = await database.teamDao.getTeamCount();
|
||||||
id: testTeam1.id,
|
expect(teamCount, 0);
|
||||||
name: 'Different Name',
|
});
|
||||||
members: [testPlayer3],
|
|
||||||
);
|
|
||||||
|
|
||||||
await database.teamDao.addTeamsAsList(
|
test('deleteAllTeams() with empty list returns false', () async {
|
||||||
teams: [duplicateTeam1, testTeam2, testTeam3],
|
final deleted = await database.teamDao.deleteAllTeams();
|
||||||
);
|
expect(deleted, isFalse);
|
||||||
|
});
|
||||||
final allTeams = await database.teamDao.getAllTeams();
|
|
||||||
expect(allTeams.length, 3);
|
|
||||||
|
|
||||||
// Verify testTeam1 retained original name (was inserted first)
|
|
||||||
final team1 = await database.teamDao.getTeamById(teamId: testTeam1.id);
|
|
||||||
expect(team1.name, testTeam1.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that team IDs are preserved correctly.
|
|
||||||
test('Team IDs are preserved through add and retrieve', () async {
|
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
|
||||||
|
|
||||||
final fetchedTeam = await database.teamDao.getTeamById(
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(fetchedTeam.id, testTeam1.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifies that createdAt timestamps are preserved.
|
|
||||||
test('Team createdAt timestamps are preserved', () async {
|
|
||||||
await database.teamDao.addTeam(team: testTeam1);
|
|
||||||
|
|
||||||
final fetchedTeam = await database.teamDao.getTeamById(
|
|
||||||
teamId: testTeam1.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(fetchedTeam.createdAt, testTeam1.createdAt);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,9 @@ void main() {
|
|||||||
await database.playerDao.addPlayer(player: testPlayer1);
|
await database.playerDao.addPlayer(player: testPlayer1);
|
||||||
await database.gameDao.addGame(game: testGame);
|
await database.gameDao.addGame(game: testGame);
|
||||||
await database.groupDao.addGroup(group: testGroup);
|
await database.groupDao.addGroup(group: testGroup);
|
||||||
|
/*
|
||||||
await database.teamDao.addTeam(team: testTeam);
|
await database.teamDao.addTeam(team: testTeam);
|
||||||
|
*/
|
||||||
await database.matchDao.addMatch(match: testMatch);
|
await database.matchDao.addMatch(match: testMatch);
|
||||||
|
|
||||||
var playerCount = await database.playerDao.getPlayerCount();
|
var playerCount = await database.playerDao.getPlayerCount();
|
||||||
@@ -137,7 +139,9 @@ void main() {
|
|||||||
await database.playerDao.addPlayer(player: testPlayer2);
|
await database.playerDao.addPlayer(player: testPlayer2);
|
||||||
await database.gameDao.addGame(game: testGame);
|
await database.gameDao.addGame(game: testGame);
|
||||||
await database.groupDao.addGroup(group: testGroup);
|
await database.groupDao.addGroup(group: testGroup);
|
||||||
|
/*
|
||||||
await database.teamDao.addTeam(team: testTeam);
|
await database.teamDao.addTeam(team: testTeam);
|
||||||
|
*/
|
||||||
await database.matchDao.addMatch(match: testMatch);
|
await database.matchDao.addMatch(match: testMatch);
|
||||||
|
|
||||||
final ctx = await getContext(tester);
|
final ctx = await getContext(tester);
|
||||||
@@ -244,7 +248,9 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Team data is correct', (tester) async {
|
testWidgets('Team data is correct', (tester) async {
|
||||||
|
/*
|
||||||
await database.teamDao.addTeam(team: testTeam);
|
await database.teamDao.addTeam(team: testTeam);
|
||||||
|
*/
|
||||||
|
|
||||||
final ctx = await getContext(tester);
|
final ctx = await getContext(tester);
|
||||||
final jsonString = await DataTransferService.getAppDataAsJson(ctx);
|
final jsonString = await DataTransferService.getAppDataAsJson(ctx);
|
||||||
@@ -644,19 +650,17 @@ void main() {
|
|||||||
test('parseTeamsFromJson()', () {
|
test('parseTeamsFromJson()', () {
|
||||||
final playerById = {testPlayer1.id: testPlayer1};
|
final playerById = {testPlayer1.id: testPlayer1};
|
||||||
|
|
||||||
final jsonMap = {
|
final teamsJson = [
|
||||||
'teams': [
|
{
|
||||||
{
|
'id': testTeam.id,
|
||||||
'id': testTeam.id,
|
'name': testTeam.name,
|
||||||
'name': testTeam.name,
|
'memberIds': [testPlayer1.id],
|
||||||
'memberIds': [testPlayer1.id],
|
'createdAt': testTeam.createdAt.toIso8601String(),
|
||||||
'createdAt': testTeam.createdAt.toIso8601String(),
|
},
|
||||||
},
|
];
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
final teams = DataTransferService.parseTeamsFromJson(
|
final teams = DataTransferService.parseTeamsFromJson(
|
||||||
jsonMap,
|
teamsJson,
|
||||||
playerById,
|
playerById,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -668,15 +672,21 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('parseTeamsFromJson() empty list', () {
|
test('parseTeamsFromJson() empty list', () {
|
||||||
final jsonMap = {'teams': []};
|
final teams = DataTransferService.parseTeamsFromJson([], {});
|
||||||
final teams = DataTransferService.parseTeamsFromJson(jsonMap, {});
|
|
||||||
expect(teams, isEmpty);
|
expect(teams, isEmpty);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('parseTeamsFromJson() missing key', () {
|
test('parseTeamsFromJson() missing memberIds', () {
|
||||||
final jsonMap = <String, dynamic>{};
|
final teamsJson = [
|
||||||
final teams = DataTransferService.parseTeamsFromJson(jsonMap, {});
|
{
|
||||||
expect(teams, isEmpty);
|
'id': testTeam.id,
|
||||||
|
'name': testTeam.name,
|
||||||
|
'createdAt': testTeam.createdAt.toIso8601String(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
final teams = DataTransferService.parseTeamsFromJson(teamsJson, {});
|
||||||
|
expect(teams.length, 1);
|
||||||
|
expect(teams[0].members, isEmpty);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('parseMatchesFromJson()', () {
|
test('parseMatchesFromJson()', () {
|
||||||
|
|||||||
Reference in New Issue
Block a user