public async Task AddEventAsync(GameId gameId, GameEvent gameEvent, CancellationToken cancellationToken) { if (gameId == null) { throw new ArgumentNullException(nameof(gameId)); } if (gameEvent == null) { throw new ArgumentNullException(nameof(gameEvent)); } cancellationToken.ThrowIfCancellationRequested(); using var connection = await _connectionFactory.CreateAndOpenAsync(cancellationToken); using var transaction = connection.BeginTransaction(); int surrogateGameId; { var command = new CommandDefinition( commandText: "SELECT id FROM game WHERE game_id = @gameId;", parameters: new { gameId }, transaction, cancellationToken: cancellationToken ); surrogateGameId = await connection.QuerySingleAsync <int>(command); } // Couldn't figure out how to support INSERT with composite types with Dapper, so ADO.NET to the rescue. using (var command = connection.CreateCommand()) { var commandText = @" INSERT INTO game_event (game_id, idx, by_player_id, card_drawn, card_used, chip, coord, next_player_id, sequences, winner) VALUES (@gameId, @idx, @byPlayerId, @cardDrawn, @cardUsed, @chip, @coord, @nextPlayerId, @sequences, @winner);"; command.CommandText = commandText; command.Parameters.AddWithValue("@gameId", surrogateGameId); command.Parameters.AddWithValue("@idx", gameEvent.Index); command.Parameters.AddWithValue("@byPlayerId", gameEvent.ByPlayerId.Value); command.Parameters.AddWithValue("@cardDrawn", CardComposite.FromCard(gameEvent.CardDrawn) as object ?? DBNull.Value); command.Parameters.AddWithValue("@cardUsed", CardComposite.FromCard(gameEvent.CardUsed) !); command.Parameters.AddWithValue("@chip", gameEvent.Chip as object ?? DBNull.Value); command.Parameters.AddWithValue("@coord", CoordComposite.FromCoord(gameEvent.Coord)); command.Parameters.AddWithValue("@nextPlayerId", gameEvent.NextPlayerId?.Value as object ?? DBNull.Value); command.Parameters.AddWithValue("@sequences", gameEvent.Sequences.Select(SequenceComposite.FromSequence).ToArray()); command.Parameters.AddWithValue("@winner", gameEvent.Winner as object ?? DBNull.Value); command.Transaction = transaction; await command.ExecuteNonQueryAsync(cancellationToken); } await transaction.CommitAsync(cancellationToken); }
public async Task <GameId> PersistNewGameAsync(NewGame newGame, CancellationToken cancellationToken) { if (newGame == null) { throw new ArgumentNullException(nameof(newGame)); } cancellationToken.ThrowIfCancellationRequested(); GameId gameId; using (var connection = await _connectionFactory.CreateAndOpenAsync(cancellationToken)) { using var transaction = connection.BeginTransaction(); try { int surrogateGameId = default; int firstPlayerId = default; { var commandText = @" INSERT INTO game (board_type, num_sequences_to_win, seed, version) VALUES (@boardType, @numSequencesToWin, @seed, @version) RETURNING id, game_id;"; var parameters = new { boardType = (int)newGame.BoardType, numSequencesToWin = newGame.NumberOfSequencesToWin, seed = newGame.Seed, version = 1 }; var command = new CommandDefinition( commandText, parameters, transaction, cancellationToken: cancellationToken ); var result = await connection.QuerySingleAsync <insert_into_game>(command); surrogateGameId = result.id; gameId = result.game_id; } for (int i = 0; i < newGame.PlayerList.Players.Count; i++) { var commandText = @" INSERT INTO game_player (game_id, player_id, player_type) VALUES (@gameId, @playerId, @playerType::player_type) RETURNING id;"; var player = newGame.PlayerList.Players[i]; var parameters = new { gameId = surrogateGameId, playerId = player.Handle, playerType = player.Type.ToString().ToLowerInvariant(), }; var command = new CommandDefinition( commandText, parameters, transaction, cancellationToken: cancellationToken ); var result = await connection.QuerySingleAsync <int>(command); if (newGame.FirstPlayerIndex == i) { firstPlayerId = result; } } { var commandText = @" UPDATE game SET first_player_id = @firstPlayerId WHERE id = @gameId;"; var parameters = new { firstPlayerId, gameId = surrogateGameId }; var command = new CommandDefinition( commandText, parameters, transaction, cancellationToken: cancellationToken ); await connection.ExecuteAsync(command); } await transaction.CommitAsync(cancellationToken); } catch { await transaction.RollbackAsync(cancellationToken); throw; } } return(gameId); }