diff --git a/lib/data/dao/player_dao.dart b/lib/data/dao/player_dao.dart index c58cb9a..74b2960 100644 --- a/lib/data/dao/player_dao.dart +++ b/lib/data/dao/player_dao.dart @@ -1,4 +1,5 @@ import 'package:drift/drift.dart'; +import 'package:flutter/cupertino.dart'; import 'package:tallee/data/db/database.dart'; import 'package:tallee/data/db/tables/player_table.dart'; import 'package:tallee/data/models/player.dart'; @@ -20,6 +21,7 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { name: row.name, description: row.description, createdAt: row.createdAt, + nameCount: row.nameCount, ), ) .toList(); @@ -34,6 +36,7 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { name: result.name, description: result.description, createdAt: result.createdAt, + nameCount: result.nameCount, ); } @@ -42,12 +45,15 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { /// the new one. Future addPlayer({required Player player}) async { if (!await playerExists(playerId: player.id)) { + final int nameCount = await calculateNameCount(name: player.name); + await into(playerTable).insert( PlayerTableCompanion.insert( id: player.id, name: player.name, description: player.description, createdAt: player.createdAt, + nameCount: Value(nameCount), ), mode: InsertMode.insertOrReplace, ); @@ -62,20 +68,67 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { Future addPlayersAsList({required List players}) async { if (players.isEmpty) return false; + // Filter out players that already exist + final newPlayers = []; + for (final player in players) { + if (!await playerExists(playerId: player.id)) { + newPlayers.add(player); + } + } + + if (newPlayers.isEmpty) return false; + + // Group players by name + final nameGroups = >{}; + for (final player in newPlayers) { + nameGroups.putIfAbsent(player.name, () => []).add(player); + } + + final playersToInsert = []; + + // Process each group of players with the same name + for (final entry in nameGroups.entries) { + final name = entry.key; + final playersWithName = entry.value; + + // Get the current nameCount + var nameCount = await calculateNameCount(name: name); + if (nameCount == 0) nameCount++; + + // One player with the same name + if (playersWithName.length == 1) { + final player = playersWithName[0]; + playersToInsert.add( + PlayerTableCompanion.insert( + id: player.id, + name: player.name, + description: player.description, + createdAt: player.createdAt, + nameCount: Value(nameCount), + ), + ); + } else { + // Multiple players with the same name + for (var i = 0; i < playersWithName.length; i++) { + final player = playersWithName[i]; + playersToInsert.add( + PlayerTableCompanion.insert( + id: player.id, + name: player.name, + description: player.description, + createdAt: player.createdAt, + nameCount: Value(nameCount + i), + ), + ); + } + } + } + await db.batch( (b) => b.insertAll( playerTable, - players - .map( - (player) => PlayerTableCompanion.insert( - id: player.id, - name: player.name, - description: player.description, - createdAt: player.createdAt, - ), - ) - .toList(), - mode: InsertMode.insertOrIgnore, + playersToInsert, + mode: InsertMode.insertOrReplace, ), ); @@ -103,9 +156,36 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { required String playerId, required String newName, }) async { + // Get previous name and name count for the player before updating + final previousPlayerName = await (select( + playerTable, + )..where((p) => p.id.equals(playerId))).map((row) => row.name).getSingle(); + final previousNameCount = await getNameCount(name: previousPlayerName); + await (update(playerTable)..where((p) => p.id.equals(playerId))).write( PlayerTableCompanion(name: Value(newName)), ); + + // Update name count for the new name + final count = await calculateNameCount(name: newName); + if (count > 0) { + await (update(playerTable)..where((p) => p.name.equals(newName))).write( + PlayerTableCompanion(nameCount: Value(count)), + ); + } + + if (previousNameCount > 0) { + // Get the player with that name and the hightest nameCount, and update their nameCount to previousNameCount + final player = await getPlayerWithHighestNameCount( + name: previousPlayerName, + ); + if (player != null) { + await updateNameCount( + playerId: player.id, + nameCount: previousNameCount, + ); + } + } } /// Retrieves the total count of players in the database. @@ -117,6 +197,76 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { return count ?? 0; } + /// Retrieves the count of players with the given [name] in the database. + Future getNameCount({required String name}) async { + final query = select(playerTable)..where((p) => p.name.equals(name)); + final result = await query.get(); + return result.length; + } + + /// Updates the nameCount for the player with the given [playerId] to [nameCount]. + /// Returns `true` if more than 0 rows were affected, otherwise `false`. + Future updateNameCount({ + required String playerId, + required int nameCount, + }) async { + final query = update(playerTable)..where((p) => p.id.equals(playerId)); + final rowsAffected = await query.write( + PlayerTableCompanion(nameCount: Value(nameCount)), + ); + return rowsAffected > 0; + } + + @visibleForTesting + Future getPlayerWithHighestNameCount({required String name}) async { + final query = select(playerTable) + ..where((p) => p.name.equals(name)) + ..orderBy([(p) => OrderingTerm.desc(p.nameCount)]) + ..limit(1); + final result = await query.getSingleOrNull(); + if (result != null) { + return Player( + id: result.id, + name: result.name, + description: result.description, + createdAt: result.createdAt, + nameCount: result.nameCount, + ); + } + return null; + } + + @visibleForTesting + Future calculateNameCount({required String name}) async { + final count = await getNameCount(name: name); + final int nameCount; + + if (count == 1) { + // If one other player exists with the same name, initialize the nameCount + await initializeNameCount(name: name); + // And for the new player, set nameCount to 2 + nameCount = 2; + } else if (count > 1) { + // If more than one player exists with the same name, just increment + // the nameCount for the new player + nameCount = count + 1; + } else { + // If no other players exist with the same name, set nameCount to 0 + nameCount = 0; + } + + return nameCount; + } + + @visibleForTesting + Future initializeNameCount({required String name}) async { + final rowsAffected = + await (update(playerTable)..where((p) => p.name.equals(name))).write( + const PlayerTableCompanion(nameCount: Value(1)), + ); + return rowsAffected > 0; + } + /// Deletes all players from the database. /// Returns `true` if more than 0 rows were affected, otherwise `false`. Future deleteAllPlayers() async { diff --git a/lib/data/db/database.g.dart b/lib/data/db/database.g.dart index 58175df..2190c3d 100644 --- a/lib/data/db/database.g.dart +++ b/lib/data/db/database.g.dart @@ -18,6 +18,17 @@ class $PlayerTableTable extends PlayerTable type: DriftSqlType.string, requiredDuringInsert: true, ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); static const VerificationMeta _nameMeta = const VerificationMeta('name'); @override late final GeneratedColumn name = GeneratedColumn( @@ -27,6 +38,18 @@ class $PlayerTableTable extends PlayerTable type: DriftSqlType.string, requiredDuringInsert: true, ); + static const VerificationMeta _nameCountMeta = const VerificationMeta( + 'nameCount', + ); + @override + late final GeneratedColumn nameCount = GeneratedColumn( + 'name_count', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const Constant(0), + ); static const VerificationMeta _descriptionMeta = const VerificationMeta( 'description', ); @@ -38,19 +61,14 @@ class $PlayerTableTable extends PlayerTable type: DriftSqlType.string, requiredDuringInsert: true, ); - static const VerificationMeta _createdAtMeta = const VerificationMeta( - 'createdAt', - ); @override - late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', - aliasedName, - false, - type: DriftSqlType.dateTime, - requiredDuringInsert: true, - ); - @override - List get $columns => [id, name, description, createdAt]; + List get $columns => [ + id, + createdAt, + name, + nameCount, + description, + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -68,6 +86,14 @@ class $PlayerTableTable extends PlayerTable } else if (isInserting) { context.missing(_idMeta); } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } if (data.containsKey('name')) { context.handle( _nameMeta, @@ -76,6 +102,12 @@ class $PlayerTableTable extends PlayerTable } else if (isInserting) { context.missing(_nameMeta); } + if (data.containsKey('name_count')) { + context.handle( + _nameCountMeta, + nameCount.isAcceptableOrUnknown(data['name_count']!, _nameCountMeta), + ); + } if (data.containsKey('description')) { context.handle( _descriptionMeta, @@ -87,14 +119,6 @@ class $PlayerTableTable extends PlayerTable } else if (isInserting) { context.missing(_descriptionMeta); } - if (data.containsKey('created_at')) { - context.handle( - _createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), - ); - } else if (isInserting) { - context.missing(_createdAtMeta); - } return context; } @@ -108,18 +132,22 @@ class $PlayerTableTable extends PlayerTable DriftSqlType.string, data['${effectivePrefix}id'], )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, name: attachedDatabase.typeMapping.read( DriftSqlType.string, data['${effectivePrefix}name'], )!, + nameCount: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}name_count'], + )!, description: attachedDatabase.typeMapping.read( DriftSqlType.string, data['${effectivePrefix}description'], )!, - createdAt: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, - data['${effectivePrefix}created_at'], - )!, ); } @@ -131,31 +159,35 @@ class $PlayerTableTable extends PlayerTable class PlayerTableData extends DataClass implements Insertable { final String id; - final String name; - final String description; final DateTime createdAt; + final String name; + final int nameCount; + final String description; const PlayerTableData({ required this.id, - required this.name, - required this.description, required this.createdAt, + required this.name, + required this.nameCount, + required this.description, }); @override Map toColumns(bool nullToAbsent) { final map = {}; map['id'] = Variable(id); - map['name'] = Variable(name); - map['description'] = Variable(description); map['created_at'] = Variable(createdAt); + map['name'] = Variable(name); + map['name_count'] = Variable(nameCount); + map['description'] = Variable(description); return map; } PlayerTableCompanion toCompanion(bool nullToAbsent) { return PlayerTableCompanion( id: Value(id), - name: Value(name), - description: Value(description), createdAt: Value(createdAt), + name: Value(name), + nameCount: Value(nameCount), + description: Value(description), ); } @@ -166,9 +198,10 @@ class PlayerTableData extends DataClass implements Insertable { serializer ??= driftRuntimeOptions.defaultSerializer; return PlayerTableData( id: serializer.fromJson(json['id']), - name: serializer.fromJson(json['name']), - description: serializer.fromJson(json['description']), createdAt: serializer.fromJson(json['createdAt']), + name: serializer.fromJson(json['name']), + nameCount: serializer.fromJson(json['nameCount']), + description: serializer.fromJson(json['description']), ); } @override @@ -176,31 +209,35 @@ class PlayerTableData extends DataClass implements Insertable { serializer ??= driftRuntimeOptions.defaultSerializer; return { 'id': serializer.toJson(id), - 'name': serializer.toJson(name), - 'description': serializer.toJson(description), 'createdAt': serializer.toJson(createdAt), + 'name': serializer.toJson(name), + 'nameCount': serializer.toJson(nameCount), + 'description': serializer.toJson(description), }; } PlayerTableData copyWith({ String? id, - String? name, - String? description, DateTime? createdAt, + String? name, + int? nameCount, + String? description, }) => PlayerTableData( id: id ?? this.id, - name: name ?? this.name, - description: description ?? this.description, createdAt: createdAt ?? this.createdAt, + name: name ?? this.name, + nameCount: nameCount ?? this.nameCount, + description: description ?? this.description, ); PlayerTableData copyWithCompanion(PlayerTableCompanion data) { return PlayerTableData( id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, name: data.name.present ? data.name.value : this.name, + nameCount: data.nameCount.present ? data.nameCount.value : this.nameCount, description: data.description.present ? data.description.value : this.description, - createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, ); } @@ -208,76 +245,85 @@ class PlayerTableData extends DataClass implements Insertable { String toString() { return (StringBuffer('PlayerTableData(') ..write('id: $id, ') + ..write('createdAt: $createdAt, ') ..write('name: $name, ') - ..write('description: $description, ') - ..write('createdAt: $createdAt') + ..write('nameCount: $nameCount, ') + ..write('description: $description') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(id, name, description, createdAt); + int get hashCode => Object.hash(id, createdAt, name, nameCount, description); @override bool operator ==(Object other) => identical(this, other) || (other is PlayerTableData && other.id == this.id && + other.createdAt == this.createdAt && other.name == this.name && - other.description == this.description && - other.createdAt == this.createdAt); + other.nameCount == this.nameCount && + other.description == this.description); } class PlayerTableCompanion extends UpdateCompanion { final Value id; - final Value name; - final Value description; final Value createdAt; + final Value name; + final Value nameCount; + final Value description; final Value rowid; const PlayerTableCompanion({ this.id = const Value.absent(), - this.name = const Value.absent(), - this.description = const Value.absent(), this.createdAt = const Value.absent(), + this.name = const Value.absent(), + this.nameCount = const Value.absent(), + this.description = const Value.absent(), this.rowid = const Value.absent(), }); PlayerTableCompanion.insert({ required String id, - required String name, - required String description, required DateTime createdAt, + required String name, + this.nameCount = const Value.absent(), + required String description, this.rowid = const Value.absent(), }) : id = Value(id), + createdAt = Value(createdAt), name = Value(name), - description = Value(description), - createdAt = Value(createdAt); + description = Value(description); static Insertable custom({ Expression? id, - Expression? name, - Expression? description, Expression? createdAt, + Expression? name, + Expression? nameCount, + Expression? description, Expression? rowid, }) { return RawValuesInsertable({ if (id != null) 'id': id, - if (name != null) 'name': name, - if (description != null) 'description': description, if (createdAt != null) 'created_at': createdAt, + if (name != null) 'name': name, + if (nameCount != null) 'name_count': nameCount, + if (description != null) 'description': description, if (rowid != null) 'rowid': rowid, }); } PlayerTableCompanion copyWith({ Value? id, - Value? name, - Value? description, Value? createdAt, + Value? name, + Value? nameCount, + Value? description, Value? rowid, }) { return PlayerTableCompanion( id: id ?? this.id, - name: name ?? this.name, - description: description ?? this.description, createdAt: createdAt ?? this.createdAt, + name: name ?? this.name, + nameCount: nameCount ?? this.nameCount, + description: description ?? this.description, rowid: rowid ?? this.rowid, ); } @@ -288,15 +334,18 @@ class PlayerTableCompanion extends UpdateCompanion { if (id.present) { map['id'] = Variable(id.value); } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } if (name.present) { map['name'] = Variable(name.value); } + if (nameCount.present) { + map['name_count'] = Variable(nameCount.value); + } if (description.present) { map['description'] = Variable(description.value); } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } if (rowid.present) { map['rowid'] = Variable(rowid.value); } @@ -307,9 +356,10 @@ class PlayerTableCompanion extends UpdateCompanion { String toString() { return (StringBuffer('PlayerTableCompanion(') ..write('id: $id, ') - ..write('name: $name, ') - ..write('description: $description, ') ..write('createdAt: $createdAt, ') + ..write('name: $name, ') + ..write('nameCount: $nameCount, ') + ..write('description: $description, ') ..write('rowid: $rowid') ..write(')')) .toString(); @@ -2790,17 +2840,19 @@ abstract class _$AppDatabase extends GeneratedDatabase { typedef $$PlayerTableTableCreateCompanionBuilder = PlayerTableCompanion Function({ required String id, - required String name, - required String description, required DateTime createdAt, + required String name, + Value nameCount, + required String description, Value rowid, }); typedef $$PlayerTableTableUpdateCompanionBuilder = PlayerTableCompanion Function({ Value id, - Value name, - Value description, Value createdAt, + Value name, + Value nameCount, + Value description, Value rowid, }); @@ -2892,18 +2944,23 @@ class $$PlayerTableTableFilterComposer builder: (column) => ColumnFilters(column), ); + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + ColumnFilters get name => $composableBuilder( column: $table.name, builder: (column) => ColumnFilters(column), ); - ColumnFilters get description => $composableBuilder( - column: $table.description, + ColumnFilters get nameCount => $composableBuilder( + column: $table.nameCount, builder: (column) => ColumnFilters(column), ); - ColumnFilters get createdAt => $composableBuilder( - column: $table.createdAt, + ColumnFilters get description => $composableBuilder( + column: $table.description, builder: (column) => ColumnFilters(column), ); @@ -2997,18 +3054,23 @@ class $$PlayerTableTableOrderingComposer builder: (column) => ColumnOrderings(column), ); + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + ColumnOrderings get name => $composableBuilder( column: $table.name, builder: (column) => ColumnOrderings(column), ); - ColumnOrderings get description => $composableBuilder( - column: $table.description, + ColumnOrderings get nameCount => $composableBuilder( + column: $table.nameCount, builder: (column) => ColumnOrderings(column), ); - ColumnOrderings get createdAt => $composableBuilder( - column: $table.createdAt, + ColumnOrderings get description => $composableBuilder( + column: $table.description, builder: (column) => ColumnOrderings(column), ); } @@ -3025,17 +3087,20 @@ class $$PlayerTableTableAnnotationComposer GeneratedColumn get id => $composableBuilder(column: $table.id, builder: (column) => column); + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + GeneratedColumn get name => $composableBuilder(column: $table.name, builder: (column) => column); + GeneratedColumn get nameCount => + $composableBuilder(column: $table.nameCount, builder: (column) => column); + GeneratedColumn get description => $composableBuilder( column: $table.description, builder: (column) => column, ); - GeneratedColumn get createdAt => - $composableBuilder(column: $table.createdAt, builder: (column) => column); - Expression playerGroupTableRefs( Expression Function($$PlayerGroupTableTableAnnotationComposer a) f, ) { @@ -3145,29 +3210,33 @@ class $$PlayerTableTableTableManager updateCompanionCallback: ({ Value id = const Value.absent(), - Value name = const Value.absent(), - Value description = const Value.absent(), Value createdAt = const Value.absent(), + Value name = const Value.absent(), + Value nameCount = const Value.absent(), + Value description = const Value.absent(), Value rowid = const Value.absent(), }) => PlayerTableCompanion( id: id, - name: name, - description: description, createdAt: createdAt, + name: name, + nameCount: nameCount, + description: description, rowid: rowid, ), createCompanionCallback: ({ required String id, - required String name, - required String description, required DateTime createdAt, + required String name, + Value nameCount = const Value.absent(), + required String description, Value rowid = const Value.absent(), }) => PlayerTableCompanion.insert( id: id, - name: name, - description: description, createdAt: createdAt, + name: name, + nameCount: nameCount, + description: description, rowid: rowid, ), withReferenceMapper: (p0) => p0 diff --git a/lib/data/db/tables/player_table.dart b/lib/data/db/tables/player_table.dart index 15b29a5..ce4f931 100644 --- a/lib/data/db/tables/player_table.dart +++ b/lib/data/db/tables/player_table.dart @@ -2,9 +2,10 @@ import 'package:drift/drift.dart'; class PlayerTable extends Table { TextColumn get id => text()(); - TextColumn get name => text()(); - TextColumn get description => text()(); DateTimeColumn get createdAt => dateTime()(); + TextColumn get name => text()(); + IntColumn get nameCount => integer().withDefault(const Constant(0))(); + TextColumn get description => text()(); @override Set> get primaryKey => {id}; diff --git a/lib/data/models/player.dart b/lib/data/models/player.dart index c405de9..b7de429 100644 --- a/lib/data/models/player.dart +++ b/lib/data/models/player.dart @@ -5,12 +5,14 @@ class Player { final String id; final DateTime createdAt; final String name; + final int nameCount; final String description; Player({ String? id, DateTime? createdAt, required this.name, + this.nameCount = 0, String? description, }) : id = id ?? const Uuid().v4(), createdAt = createdAt ?? clock.now(), @@ -26,6 +28,7 @@ class Player { : id = json['id'], createdAt = DateTime.parse(json['createdAt']), name = json['name'], + nameCount = 0, description = json['description']; /// Converts the Player instance to a JSON object. diff --git a/test/db_tests/entities/player_test.dart b/test/db_tests/entities/player_test.dart index 3042b33..45eacf0 100644 --- a/test/db_tests/entities/player_test.dart +++ b/test/db_tests/entities/player_test.dart @@ -1,5 +1,5 @@ import 'package:clock/clock.dart'; -import 'package:drift/drift.dart' hide isNull; +import 'package:drift/drift.dart' hide isNull, isNotNull; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:tallee/data/db/database.dart'; @@ -381,5 +381,162 @@ void main() { ); expect(playerExists, true); }); + + group('Name Count Tests', () { + test('Single player gets initialized wih name count 0', () async { + await database.playerDao.addPlayer(player: testPlayer1); + + final player = await database.playerDao.getPlayerById( + playerId: testPlayer1.id, + ); + expect(player.nameCount, 0); + }); + + test('Multiple players get initialized wih name count 0', () async { + await database.playerDao.addPlayersAsList( + players: [testPlayer1, testPlayer2], + ); + + final players = await database.playerDao.getAllPlayers(); + + expect(players.length, 2); + for (Player p in players) { + expect(p.nameCount, 0); + } + }); + + test( + 'Seperatly added players nameCount gets increased correctly', + () async { + await database.playerDao.addPlayer(player: testPlayer1); + + final player1 = Player(name: testPlayer1.name, description: ''); + await database.playerDao.addPlayer(player: player1); + + var players = await database.playerDao.getAllPlayers(); + + expect(players.length, 2); + players.sort((a, b) => a.nameCount.compareTo(b.nameCount)); + + for (int i = 0; i < players.length - 1; i++) { + expect(players[i].nameCount, i + 1); + } + }, + ); + + test( + 'Together added players nameCount gets increased correctly', + () async { + final player1 = Player(name: testPlayer1.name, description: ''); + final player2 = Player(name: testPlayer1.name, description: ''); + final player3 = Player(name: testPlayer1.name, description: ''); + + // addPlayersAsList() with multiple players and with one player + await database.playerDao.addPlayersAsList(players: [testPlayer1]); + await database.playerDao.addPlayersAsList( + players: [player1, player2, player3], + ); + + var players = await database.playerDao.getAllPlayers(); + + expect(players.length, 4); + players.sort((a, b) => a.nameCount.compareTo(b.nameCount)); + + for (int i = 0; i < players.length - 1; i++) { + expect(players[i].nameCount, i + 1); + } + }, + ); + + test('getNameCount works correctly', () async { + final player2 = Player(name: testPlayer1.name, description: ''); + final player3 = Player(name: testPlayer1.name, description: ''); + + await database.playerDao.addPlayersAsList( + players: [testPlayer1, player2, player3], + ); + + final nameCount = await database.playerDao.getNameCount( + name: testPlayer1.name, + ); + + expect(nameCount, 2); + }); + + test('updateNameCount works correctly', () async { + await database.playerDao.addPlayer(player: testPlayer1); + + final success = await database.playerDao.updateNameCount( + playerId: testPlayer1.id, + nameCount: 2, + ); + + expect(success, true); + + final nameCount = await database.playerDao.getNameCount( + name: testPlayer1.name, + ); + + expect(nameCount, 2); + }); + + test('getPlayerWithHighestNameCount works correctly', () async { + final player2 = Player(name: testPlayer1.name, description: ''); + final player3 = Player(name: testPlayer1.name, description: ''); + + await database.playerDao.addPlayersAsList( + players: [testPlayer1, player2, player3], + ); + + final player = await database.playerDao.getPlayerWithHighestNameCount( + name: testPlayer1.name, + ); + + expect(player, isNotNull); + expect(player!.nameCount, 3); + }); + + test('getPlayerWithHighestNameCount with non existing player', () async { + final player = await database.playerDao.getPlayerWithHighestNameCount( + name: 'non-existing-name', + ); + expect(player, isNull); + }); + + test('calculateNameCount works correctly', () async { + // Case 1: No existing players with the name + var count = await database.playerDao.calculateNameCount( + name: testPlayer1.name, + ); + expect(count, 0); + + // Case 2: One existing player with the name. Should update that + // player's nameCount to 1 and return 2 for the new player + await database.playerDao.addPlayer(player: testPlayer1); + + count = await database.playerDao.calculateNameCount( + name: testPlayer1.name, + ); + expect(count, 2); + + // Case 3: Multiple existing players with the name. + final player2 = Player(name: testPlayer1.name, nameCount: count); + await database.playerDao.addPlayer(player: player2); + + count = await database.playerDao.calculateNameCount( + name: testPlayer1.name, + ); + expect(count, 3); + }); + + test('getPlayerWithHighestNameCount with non existing player', () async { + await database.playerDao.addPlayer(player: testPlayer1); + await database.playerDao.initializeNameCount(name: testPlayer1.name); + final player = await database.playerDao.getPlayerById( + playerId: testPlayer1.id, + ); + expect(player.nameCount, 1); + }); + }); }); }