diff --git a/lib/data/dao/game_dao.dart b/lib/data/dao/game_dao.dart index 9ed9849..018866a 100644 --- a/lib/data/dao/game_dao.dart +++ b/lib/data/dao/game_dao.dart @@ -50,14 +50,6 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { /// Also adds associated players and group if they exist. Future addGame({required Game game}) async { await db.transaction(() async { - for (final p in game.players ?? []) { - await db.playerDao.addPlayer(player: p); - await db.playerGameDao.addPlayerToGame(gameId: game.id, playerId: p.id); - } - if (game.group != null) { - await db.groupDao.addGroup(group: game.group!); - await db.groupGameDao.addGroupToGame(game.id, game.group!.id); - } await into(gameTable).insert( GameTableCompanion.insert( id: game.id, @@ -67,6 +59,114 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { ), mode: InsertMode.insertOrReplace, ); + + if (game.players != null) { + await db.playerDao.addPlayers(players: game.players!); + for (final p in game.players ?? []) { + await db.playerGameDao.addPlayerToGame( + gameId: game.id, + playerId: p.id, + ); + } + } + + if (game.group != null) { + await db.groupDao.addGroup(group: game.group!); + await db.groupGameDao.addGroupToGame(game.id, game.group!.id); + } + }); + } + + Future addGames({required List games}) async { + if (games.isEmpty) return; + await db.transaction(() async { + // Add all games in batch + await db.batch( + (b) => b.insertAll( + gameTable, + games + .map( + (game) => GameTableCompanion.insert( + id: game.id, + name: game.name, + createdAt: game.createdAt, + winnerId: Value(game.winner), + ), + ) + .toList(), + mode: InsertMode.insertOrReplace, + ), + ); + // Add all groups of the games in batch + await db.batch( + (b) => b.insertAll( + db.groupTable, + games + .where((game) => game.group != null) + .map( + (game) => GroupTableCompanion.insert( + id: game.group!.id, + name: game.group!.name, + createdAt: game.group!.createdAt, + ), + ) + .toList(), + mode: InsertMode.insertOrReplace, + ), + ); + + // Add all players of the games in batch + await db.batch((b) async { + for (final game in games) { + if (game.players != null) { + for (final p in game.players ?? []) { + b.insert( + db.playerGameTable, + PlayerGameTableCompanion.insert( + gameId: game.id, + playerId: p.id, + ), + mode: InsertMode.insertOrReplace, + ); + } + } + } + }); + + // Add all group-game associations in batch + await db.batch((b) async { + for (final game in games) { + if (game.group != null) { + b.insert( + db.groupGameTable, + GroupGameTableCompanion.insert( + gameId: game.id, + groupId: game.group!.id, + ), + mode: InsertMode.insertOrReplace, + ); + } + } + }); + + // Add all player-game associations in batch + await db.batch((b) async { + for (final game in games) { + if (game.players != null) { + for (final p in game.players ?? []) { + b.insert( + db.playerTable, + PlayerTableCompanion.insert( + id: p.id, + name: p.name, + createdAt: p.createdAt, + ), + mode: InsertMode.insertOrReplace, + ); + } + } + } + }); }); } diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index 6eaea09..695d78a 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -57,6 +57,10 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { name: group.name, createdAt: group.createdAt, ), + mode: InsertMode.insertOrReplace, + ); + await Future.wait( + group.members.map((player) => db.playerDao.addPlayer(player: player)), ); await db.batch( (b) => b.insertAll( @@ -69,17 +73,57 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { ), ) .toList(), + mode: InsertMode.insertOrReplace, ), ); - await Future.wait( - group.members.map((player) => db.playerDao.addPlayer(player: player)), - ); }); return true; } return false; } + /// Adds multiple groups to the database. + /// Also adds the group's members to the [PlayerGroupTable]. + Future addGroups({required List groups}) async { + if (groups.isEmpty) return; + await db.transaction(() async { + await db.batch( + (b) => b.insertAll( + groupTable, + groups + .map( + (group) => GroupTableCompanion.insert( + id: group.id, + name: group.name, + createdAt: group.createdAt, + ), + ) + .toList(), + mode: InsertMode.insertOrReplace, + ), + ); + + for (final group in groups) { + await db.playerDao.addPlayers(players: group.members); + + await db.batch( + (b) => b.insertAll( + db.playerGroupTable, + group.members + .map( + (member) => PlayerGroupTableCompanion.insert( + playerId: member.id, + groupId: group.id, + ), + ) + .toList(), + mode: InsertMode.insertOrReplace, + ), + ); + } + }); + } + /// Deletes the group with the given [id] from the database. /// Returns `true` if more than 0 rows were affected, otherwise `false`. Future deleteGroup({required String groupId}) async { diff --git a/lib/data/dao/player_dao.dart b/lib/data/dao/player_dao.dart index 353819c..53e251f 100644 --- a/lib/data/dao/player_dao.dart +++ b/lib/data/dao/player_dao.dart @@ -42,12 +42,36 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { name: player.name, createdAt: player.createdAt, ), + mode: InsertMode.insertOrReplace, ); return true; } return false; } + /// Adds multiple [players] to the database in a batch operation. + Future addPlayers({required List players}) async { + if (players.isEmpty) return false; + + await db.batch( + (b) => b.insertAll( + playerTable, + players + .map( + (player) => PlayerTableCompanion.insert( + id: player.id, + name: player.name, + createdAt: player.createdAt, + ), + ) + .toList(), + mode: InsertMode.insertOrReplace, + ), + ); + + return true; + } + /// Deletes the player with the given [id] from the database. /// Returns `true` if the player was deleted, `false` if the player did not exist. Future deletePlayer({required String playerId}) async { diff --git a/lib/data/db/database.g.dart b/lib/data/db/database.g.dart index 3f10169..f211d0c 100644 --- a/lib/data/db/database.g.dart +++ b/lib/data/db/database.g.dart @@ -552,12 +552,9 @@ class $GameTableTable extends GameTable late final GeneratedColumn winnerId = GeneratedColumn( 'winner_id', aliasedName, - false, + true, type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES player_table (id) ON DELETE CASCADE', - ), + requiredDuringInsert: false, ); static const VerificationMeta _createdAtMeta = const VerificationMeta( 'createdAt', @@ -602,8 +599,6 @@ class $GameTableTable extends GameTable _winnerIdMeta, winnerId.isAcceptableOrUnknown(data['winner_id']!, _winnerIdMeta), ); - } else if (isInserting) { - context.missing(_winnerIdMeta); } if (data.containsKey('created_at')) { context.handle( @@ -633,7 +628,7 @@ class $GameTableTable extends GameTable winnerId: attachedDatabase.typeMapping.read( DriftSqlType.string, data['${effectivePrefix}winner_id'], - )!, + ), createdAt: attachedDatabase.typeMapping.read( DriftSqlType.dateTime, data['${effectivePrefix}created_at'], @@ -650,12 +645,12 @@ class $GameTableTable extends GameTable class GameTableData extends DataClass implements Insertable { final String id; final String name; - final String winnerId; + final String? winnerId; final DateTime createdAt; const GameTableData({ required this.id, required this.name, - required this.winnerId, + this.winnerId, required this.createdAt, }); @override @@ -663,7 +658,9 @@ class GameTableData extends DataClass implements Insertable { final map = {}; map['id'] = Variable(id); map['name'] = Variable(name); - map['winner_id'] = Variable(winnerId); + if (!nullToAbsent || winnerId != null) { + map['winner_id'] = Variable(winnerId); + } map['created_at'] = Variable(createdAt); return map; } @@ -672,7 +669,9 @@ class GameTableData extends DataClass implements Insertable { return GameTableCompanion( id: Value(id), name: Value(name), - winnerId: Value(winnerId), + winnerId: winnerId == null && nullToAbsent + ? const Value.absent() + : Value(winnerId), createdAt: Value(createdAt), ); } @@ -685,7 +684,7 @@ class GameTableData extends DataClass implements Insertable { return GameTableData( id: serializer.fromJson(json['id']), name: serializer.fromJson(json['name']), - winnerId: serializer.fromJson(json['winnerId']), + winnerId: serializer.fromJson(json['winnerId']), createdAt: serializer.fromJson(json['createdAt']), ); } @@ -695,7 +694,7 @@ class GameTableData extends DataClass implements Insertable { return { 'id': serializer.toJson(id), 'name': serializer.toJson(name), - 'winnerId': serializer.toJson(winnerId), + 'winnerId': serializer.toJson(winnerId), 'createdAt': serializer.toJson(createdAt), }; } @@ -703,12 +702,12 @@ class GameTableData extends DataClass implements Insertable { GameTableData copyWith({ String? id, String? name, - String? winnerId, + Value winnerId = const Value.absent(), DateTime? createdAt, }) => GameTableData( id: id ?? this.id, name: name ?? this.name, - winnerId: winnerId ?? this.winnerId, + winnerId: winnerId.present ? winnerId.value : this.winnerId, createdAt: createdAt ?? this.createdAt, ); GameTableData copyWithCompanion(GameTableCompanion data) { @@ -746,7 +745,7 @@ class GameTableData extends DataClass implements Insertable { class GameTableCompanion extends UpdateCompanion { final Value id; final Value name; - final Value winnerId; + final Value winnerId; final Value createdAt; final Value rowid; const GameTableCompanion({ @@ -759,12 +758,11 @@ class GameTableCompanion extends UpdateCompanion { GameTableCompanion.insert({ required String id, required String name, - required String winnerId, + this.winnerId = const Value.absent(), required DateTime createdAt, this.rowid = const Value.absent(), }) : id = Value(id), name = Value(name), - winnerId = Value(winnerId), createdAt = Value(createdAt); static Insertable custom({ Expression? id, @@ -785,7 +783,7 @@ class GameTableCompanion extends UpdateCompanion { GameTableCompanion copyWith({ Value? id, Value? name, - Value? winnerId, + Value? winnerId, Value? createdAt, Value? rowid, }) { @@ -1538,13 +1536,6 @@ abstract class _$AppDatabase extends GeneratedDatabase { ]; @override StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules([ - WritePropagation( - on: TableUpdateQuery.onTableName( - 'player_table', - limitUpdateKind: UpdateKind.delete, - ), - result: [TableUpdate('game_table', kind: UpdateKind.delete)], - ), WritePropagation( on: TableUpdateQuery.onTableName( 'player_table', @@ -1609,24 +1600,6 @@ final class $$PlayerTableTableReferences extends BaseReferences<_$AppDatabase, $PlayerTableTable, PlayerTableData> { $$PlayerTableTableReferences(super.$_db, super.$_table, super.$_typedResult); - static MultiTypedResultKey<$GameTableTable, List> - _gameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( - db.gameTable, - aliasName: $_aliasNameGenerator(db.playerTable.id, db.gameTable.winnerId), - ); - - $$GameTableTableProcessedTableManager get gameTableRefs { - final manager = $$GameTableTableTableManager( - $_db, - $_db.gameTable, - ).filter((f) => f.winnerId.id.sqlEquals($_itemColumn('id')!)); - - final cache = $_typedResult.readTableOrNull(_gameTableRefsTable($_db)); - return ProcessedTableManager( - manager.$state.copyWith(prefetchedData: cache), - ); - } - static MultiTypedResultKey<$PlayerGroupTableTable, List> _playerGroupTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( db.playerGroupTable, @@ -1698,31 +1671,6 @@ class $$PlayerTableTableFilterComposer builder: (column) => ColumnFilters(column), ); - Expression gameTableRefs( - Expression Function($$GameTableTableFilterComposer f) f, - ) { - final $$GameTableTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.id, - referencedTable: $db.gameTable, - getReferencedColumn: (t) => t.winnerId, - builder: - ( - joinBuilder, { - $addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer, - }) => $$GameTableTableFilterComposer( - $db: $db, - $table: $db.gameTable, - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - ), - ); - return f(composer); - } - Expression playerGroupTableRefs( Expression Function($$PlayerGroupTableTableFilterComposer f) f, ) { @@ -1817,31 +1765,6 @@ class $$PlayerTableTableAnnotationComposer GeneratedColumn get createdAt => $composableBuilder(column: $table.createdAt, builder: (column) => column); - Expression gameTableRefs( - Expression Function($$GameTableTableAnnotationComposer a) f, - ) { - final $$GameTableTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.id, - referencedTable: $db.gameTable, - getReferencedColumn: (t) => t.winnerId, - builder: - ( - joinBuilder, { - $addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer, - }) => $$GameTableTableAnnotationComposer( - $db: $db, - $table: $db.gameTable, - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - ), - ); - return f(composer); - } - Expression playerGroupTableRefs( Expression Function($$PlayerGroupTableTableAnnotationComposer a) f, ) { @@ -1907,7 +1830,6 @@ class $$PlayerTableTableTableManager (PlayerTableData, $$PlayerTableTableReferences), PlayerTableData, PrefetchHooks Function({ - bool gameTableRefs, bool playerGroupTableRefs, bool playerGameTableRefs, }) @@ -1956,42 +1878,16 @@ class $$PlayerTableTableTableManager ) .toList(), prefetchHooksCallback: - ({ - gameTableRefs = false, - playerGroupTableRefs = false, - playerGameTableRefs = false, - }) { + ({playerGroupTableRefs = false, playerGameTableRefs = false}) { return PrefetchHooks( db: db, explicitlyWatchedTables: [ - if (gameTableRefs) db.gameTable, if (playerGroupTableRefs) db.playerGroupTable, if (playerGameTableRefs) db.playerGameTable, ], addJoins: null, getPrefetchedDataCallback: (items) async { return [ - if (gameTableRefs) - await $_getPrefetchedData< - PlayerTableData, - $PlayerTableTable, - GameTableData - >( - currentTable: table, - referencedTable: $$PlayerTableTableReferences - ._gameTableRefsTable(db), - managerFromTypedResult: (p0) => - $$PlayerTableTableReferences( - db, - table, - p0, - ).gameTableRefs, - referencedItemsForCurrentItem: - (item, referencedItems) => referencedItems.where( - (e) => e.winnerId == item.id, - ), - typedResults: items, - ), if (playerGroupTableRefs) await $_getPrefetchedData< PlayerTableData, @@ -2055,7 +1951,6 @@ typedef $$PlayerTableTableProcessedTableManager = (PlayerTableData, $$PlayerTableTableReferences), PlayerTableData, PrefetchHooks Function({ - bool gameTableRefs, bool playerGroupTableRefs, bool playerGameTableRefs, }) @@ -2436,7 +2331,7 @@ typedef $$GameTableTableCreateCompanionBuilder = GameTableCompanion Function({ required String id, required String name, - required String winnerId, + Value winnerId, required DateTime createdAt, Value rowid, }); @@ -2444,7 +2339,7 @@ typedef $$GameTableTableUpdateCompanionBuilder = GameTableCompanion Function({ Value id, Value name, - Value winnerId, + Value winnerId, Value createdAt, Value rowid, }); @@ -2453,25 +2348,6 @@ final class $$GameTableTableReferences extends BaseReferences<_$AppDatabase, $GameTableTable, GameTableData> { $$GameTableTableReferences(super.$_db, super.$_table, super.$_typedResult); - static $PlayerTableTable _winnerIdTable(_$AppDatabase db) => - db.playerTable.createAlias( - $_aliasNameGenerator(db.gameTable.winnerId, db.playerTable.id), - ); - - $$PlayerTableTableProcessedTableManager get winnerId { - final $_column = $_itemColumn('winner_id')!; - - final manager = $$PlayerTableTableTableManager( - $_db, - $_db.playerTable, - ).filter((f) => f.id.sqlEquals($_column)); - final item = $_typedResult.readTableOrNull(_winnerIdTable($_db)); - if (item == null) return manager; - return ProcessedTableManager( - manager.$state.copyWith(prefetchedData: [item]), - ); - } - static MultiTypedResultKey<$PlayerGameTableTable, List> _playerGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( db.playerGameTable, @@ -2530,34 +2406,16 @@ class $$GameTableTableFilterComposer builder: (column) => ColumnFilters(column), ); + ColumnFilters get winnerId => $composableBuilder( + column: $table.winnerId, + builder: (column) => ColumnFilters(column), + ); + ColumnFilters get createdAt => $composableBuilder( column: $table.createdAt, builder: (column) => ColumnFilters(column), ); - $$PlayerTableTableFilterComposer get winnerId { - final $$PlayerTableTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.winnerId, - referencedTable: $db.playerTable, - getReferencedColumn: (t) => t.id, - builder: - ( - joinBuilder, { - $addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer, - }) => $$PlayerTableTableFilterComposer( - $db: $db, - $table: $db.playerTable, - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - ), - ); - return composer; - } - Expression playerGameTableRefs( Expression Function($$PlayerGameTableTableFilterComposer f) f, ) { @@ -2628,33 +2486,15 @@ class $$GameTableTableOrderingComposer builder: (column) => ColumnOrderings(column), ); + ColumnOrderings get winnerId => $composableBuilder( + column: $table.winnerId, + builder: (column) => ColumnOrderings(column), + ); + ColumnOrderings get createdAt => $composableBuilder( column: $table.createdAt, builder: (column) => ColumnOrderings(column), ); - - $$PlayerTableTableOrderingComposer get winnerId { - final $$PlayerTableTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.winnerId, - referencedTable: $db.playerTable, - getReferencedColumn: (t) => t.id, - builder: - ( - joinBuilder, { - $addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer, - }) => $$PlayerTableTableOrderingComposer( - $db: $db, - $table: $db.playerTable, - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - ), - ); - return composer; - } } class $$GameTableTableAnnotationComposer @@ -2672,32 +2512,12 @@ class $$GameTableTableAnnotationComposer GeneratedColumn get name => $composableBuilder(column: $table.name, builder: (column) => column); + GeneratedColumn get winnerId => + $composableBuilder(column: $table.winnerId, builder: (column) => column); + GeneratedColumn get createdAt => $composableBuilder(column: $table.createdAt, builder: (column) => column); - $$PlayerTableTableAnnotationComposer get winnerId { - final $$PlayerTableTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.winnerId, - referencedTable: $db.playerTable, - getReferencedColumn: (t) => t.id, - builder: - ( - joinBuilder, { - $addJoinBuilderToRootComposer, - $removeJoinBuilderFromRootComposer, - }) => $$PlayerTableTableAnnotationComposer( - $db: $db, - $table: $db.playerTable, - $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, - joinBuilder: joinBuilder, - $removeJoinBuilderFromRootComposer: - $removeJoinBuilderFromRootComposer, - ), - ); - return composer; - } - Expression playerGameTableRefs( Expression Function($$PlayerGameTableTableAnnotationComposer a) f, ) { @@ -2763,7 +2583,6 @@ class $$GameTableTableTableManager (GameTableData, $$GameTableTableReferences), GameTableData, PrefetchHooks Function({ - bool winnerId, bool playerGameTableRefs, bool groupGameTableRefs, }) @@ -2783,7 +2602,7 @@ class $$GameTableTableTableManager ({ Value id = const Value.absent(), Value name = const Value.absent(), - Value winnerId = const Value.absent(), + Value winnerId = const Value.absent(), Value createdAt = const Value.absent(), Value rowid = const Value.absent(), }) => GameTableCompanion( @@ -2797,7 +2616,7 @@ class $$GameTableTableTableManager ({ required String id, required String name, - required String winnerId, + Value winnerId = const Value.absent(), required DateTime createdAt, Value rowid = const Value.absent(), }) => GameTableCompanion.insert( @@ -2816,49 +2635,14 @@ class $$GameTableTableTableManager ) .toList(), prefetchHooksCallback: - ({ - winnerId = false, - playerGameTableRefs = false, - groupGameTableRefs = false, - }) { + ({playerGameTableRefs = false, groupGameTableRefs = false}) { return PrefetchHooks( db: db, explicitlyWatchedTables: [ if (playerGameTableRefs) db.playerGameTable, if (groupGameTableRefs) db.groupGameTable, ], - addJoins: - < - T extends TableManagerState< - dynamic, - dynamic, - dynamic, - dynamic, - dynamic, - dynamic, - dynamic, - dynamic, - dynamic, - dynamic, - dynamic - > - >(state) { - if (winnerId) { - state = - state.withJoin( - currentTable: table, - currentColumn: table.winnerId, - referencedTable: $$GameTableTableReferences - ._winnerIdTable(db), - referencedColumn: $$GameTableTableReferences - ._winnerIdTable(db) - .id, - ) - as T; - } - - return state; - }, + addJoins: null, getPrefetchedDataCallback: (items) async { return [ if (playerGameTableRefs) @@ -2924,7 +2708,6 @@ typedef $$GameTableTableProcessedTableManager = (GameTableData, $$GameTableTableReferences), GameTableData, PrefetchHooks Function({ - bool winnerId, bool playerGameTableRefs, bool groupGameTableRefs, }) diff --git a/lib/services/data_transfer_service.dart b/lib/services/data_transfer_service.dart index 93c788d..13eb658 100644 --- a/lib/services/data_transfer_service.dart +++ b/lib/services/data_transfer_service.dart @@ -110,17 +110,9 @@ class DataTransferService { .toList() ?? []; - for (Player player in importedPlayers) { - await db.playerDao.addPlayer(player: player); - } - - for (Group group in importedGroups) { - await db.groupDao.addGroup(group: group); - } - - for (Game game in importedGames) { - await db.gameDao.addGame(game: game); - } + await db.playerDao.addPlayers(players: importedPlayers); + await db.groupDao.addGroups(groups: importedGroups); + await db.gameDao.addGames(games: importedGames); } else { return ImportResult.invalidSchema; }