public async Task UpdateBowlingFigures_throws_ArgumentException_if_any_bowler_is_null()
        {
            var innings = new MatchInnings
            {
                MatchInningsId = Guid.NewGuid(),
                BowlingFigures = new List <BowlingFigures> {
                    {
                        new BowlingFigures()
                    }
                }
            };

            var repo = new SqlServerStatisticsRepository(Mock.Of <IPlayerRepository>());

            await Assert.ThrowsAsync <ArgumentException>(async() => await repo.UpdateBowlingFigures(innings, Guid.NewGuid(), "Member name", Mock.Of <IDbTransaction>()).ConfigureAwait(false)).ConfigureAwait(false);
        }
        public async Task DeleteBowlingFigures_succeeds()
        {
            var repo = new SqlServerStatisticsRepository(Mock.Of <IPlayerRepository>());

            using (var connection = _databaseFixture.ConnectionFactory.CreateDatabaseConnection())
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    var matchInningsId = await connection.QuerySingleAsync <Guid>($"SELECT TOP 1 MatchInningsId FROM {Tables.BowlingFigures}", transaction : transaction).ConfigureAwait(false);

                    await repo.DeleteBowlingFigures(matchInningsId, transaction).ConfigureAwait(false);

                    var count = await connection.QuerySingleAsync <int>($"SELECT COUNT(*) FROM {Tables.BowlingFigures} WHERE MatchInningsId = @matchInningsId", new { matchInningsId }, transaction).ConfigureAwait(false);

                    transaction.Rollback();

                    Assert.Equal(0, count);
                }
            }
        }
        public async Task UpdateBowlingFigures_calls_CreateOrMatchPlayerIdentity_before_inserting()
        {
            using (var connection = _databaseFixture.ConnectionFactory.CreateDatabaseConnection())
            {
                connection.Open();

                using (var transaction = connection.BeginTransaction())
                {
                    var data = await connection.QuerySingleAsync <(Guid matchInningsId, Guid bowlerPlayerIdentityId)>($"SELECT TOP 1 MatchInningsId, BowlerPlayerIdentityId FROM {Tables.BowlingFigures}", transaction : transaction).ConfigureAwait(false);

                    var innings = new MatchInnings
                    {
                        MatchInningsId = data.matchInningsId,
                        BowlingFigures = new List <BowlingFigures> {
                            {
                                new BowlingFigures {
                                    Bowler = new PlayerIdentity {
                                        PlayerIdentityId = data.bowlerPlayerIdentityId
                                    }
                                }
                            }
                        }
                    };
                    var memberKey  = Guid.NewGuid();
                    var memberName = "Member name";

                    var playerRepo = new Mock <IPlayerRepository>();
                    playerRepo.Setup(x => x.CreateOrMatchPlayerIdentity(innings.BowlingFigures[0].Bowler, memberKey, memberName, transaction)).Returns(Task.FromResult(innings.BowlingFigures[0].Bowler));

                    var statisticsRepo = new SqlServerStatisticsRepository(playerRepo.Object);

                    _ = statisticsRepo.UpdateBowlingFigures(innings, memberKey, memberName, transaction).ConfigureAwait(false);

                    playerRepo.Verify(x => x.CreateOrMatchPlayerIdentity(innings.BowlingFigures[0].Bowler, memberKey, memberName, transaction), Times.Once);

                    transaction.Rollback();
                }
            }
        }
        public async Task UpdateBowlingFigures_throws_ArgumentNullException_if_transaction_is_null()
        {
            var repo = new SqlServerStatisticsRepository(Mock.Of <IPlayerRepository>());

            await Assert.ThrowsAsync <ArgumentNullException>(async() => await repo.UpdateBowlingFigures(new MatchInnings(), Guid.NewGuid(), "Member name", null).ConfigureAwait(false)).ConfigureAwait(false);
        }
        public async Task UpdatePlayerStatistics_inserts_minimal_record()
        {
            var repo = new SqlServerStatisticsRepository(Mock.Of <IPlayerRepository>());

            using (var connection = _databaseFixture.ConnectionFactory.CreateDatabaseConnection())
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    var data = await connection.QuerySingleAsync <(Guid matchId, Guid matchTeamId, Guid teamId, Guid oppositionTeamId, Guid playerId, Guid playerIdentityId)>(
                        @$ "SELECT TOP 1 m.MatchId, home.MatchTeamId, home.TeamId, away.TeamId AS OppositionTeamId, pi.PlayerId, pi.PlayerIdentityId
                           FROM {Tables.Match} m INNER JOIN {Tables.MatchTeam} home ON m.MatchId = home.MatchId AND home.TeamRole = '{TeamRole.Home.ToString()}'
                           INNER JOIN {Tables.MatchTeam} away ON m.MatchId = away.MatchId AND away.TeamRole = '{TeamRole.Away.ToString()}'
                           INNER JOIN {Tables.PlayerIdentity} pi ON home.TeamId = pi.TeamId AND pi.PlayerIdentityId = (SELECT TOP 1 PlayerIdentityId FROM {Tables.PlayerIdentity} WHERE TeamId = home.TeamId)",
                        transaction : transaction).ConfigureAwait(false);

                    var stats = new PlayerInMatchStatisticsRecord
                    {
                        PlayerId            = data.playerId,
                        PlayerIdentityId    = data.playerIdentityId,
                        MatchId             = data.matchId,
                        MatchStartTime      = new DateTimeOffset(new DateTime(2021, 7, 1, 19, 0, 0), TimeSpan.Zero),
                        MatchType           = MatchType.FriendlyMatch,
                        MatchPlayerType     = PlayerType.Mixed,
                        MatchName           = "Team A v Team B",
                        MatchRoute          = "/matches/example-match",
                        MatchTeamId         = data.matchTeamId,
                        TeamId              = data.teamId,
                        TeamName            = "Team name",
                        TeamRoute           = "/teams/example-team",
                        OppositionTeamId    = data.oppositionTeamId,
                        OppositionTeamName  = "Opposition",
                        OppositionTeamRoute = "/teams/opposition-team",
                        MatchInningsPair    = 1,
                        HasRunsConceded     = false,
                        PlayerWasDismissed  = false,
                        Catches             = 0,
                        RunOuts             = 0,
                        PlayerOfTheMatch    = false
                    };

                    await repo.UpdatePlayerStatistics(new[] { stats }, transaction).ConfigureAwait(false);

                    var count = await connection.QuerySingleAsync <int>(@$ "SELECT COUNT(*) FROM {Tables.PlayerInMatchStatistics} 
                                WHERE PlayerId = @PlayerId
                                AND PlayerIdentityId = @PlayerIdentityId
                                AND PlayerIdentityName IS NULL
                                AND PlayerRoute IS NULL
                                AND MatchId = @MatchId
                                AND MatchStartTime = @MatchStartTime
                                AND MatchType = @MatchType
                                AND MatchPlayerType = @MatchPlayerType
                                AND MatchName = @MatchName
                                AND MatchRoute = @MatchRoute
                                AND MatchTeamId = @MatchTeamId
                                AND TeamId = @TeamId
                                AND TeamName = @TeamName
                                AND TeamRoute = @TeamRoute
                                AND OppositionTeamId = @OppositionTeamId
                                AND OppositionTeamName = @OppositionTeamName
                                AND OppositionTeamRoute = @OppositionTeamRoute
                                AND MatchInningsPair = @MatchInningsPair
                                AND HasRunsConceded = @HasRunsConceded
                                AND PlayerWasDismissed = @PlayerWasDismissed
                                AND Catches = @Catches
                                AND RunOuts = @RunOuts
                                AND PlayerOfTheMatch = @PlayerOfTheMatch
                                AND BattedFirst IS NULL
                                AND PlayerInningsId IS NULL
                                AND PlayerInningsNumber IS NULL
                                AND BattingPosition IS NULL
                                AND BowledByPlayerIdentityId IS NULL
                                AND BowledByPlayerIdentityName IS NULL
                                AND BowledByPlayerRoute IS NULL
                                AND BowlingFiguresId IS NULL
                                AND CaughtByPlayerIdentityId IS NULL
                                AND CaughtByPlayerIdentityName IS NULL
                                AND CaughtByPlayerRoute IS NULL
                                AND RunOutByPlayerIdentityId IS NULL
                                AND RunOutByPlayerIdentityName IS NULL
                                AND RunOutByPlayerRoute IS NULL
                                AND DismissalType IS NULL
                                AND RunsScored IS NULL
                                AND BallsFaced IS NULL
                                AND ClubId IS NULL
                                AND TournamentId IS NULL
                                AND SeasonId IS NULL
                                AND CompetitionId IS NULL
                                AND MatchLocationId IS NULL
                                AND Overs IS NULL
                                AND OverNumberOfFirstOverBowled IS NULL
                                AND BallsBowled IS NULL
                                AND Maidens IS NULL
                                AND RunsConceded IS NULL
                                AND Wickets IS NULL
                                AND WicketsWithBowling IS NULL
                                AND NoBalls IS NULL
                                AND Wides IS NULL
                                AND TeamRunsScored IS NULL
                                AND TeamWicketsLost IS NULL
                                AND TeamBonusOrPenaltyRunsAwarded IS NULL
                                AND TeamByesConceded IS NULL
                                AND TeamNoBallsConceded IS NULL
                                AND TeamRunsConceded IS NULL
                                AND TeamWicketsTaken IS NULL
                                AND TeamWidesConceded IS NULL
                                AND WonMatch IS NULL
                                AND WonToss IS NULL",
                                                                        new
                    {
                        stats.PlayerId,
                        stats.PlayerIdentityId,
                        stats.MatchId,
                        stats.MatchStartTime,
                        MatchType       = stats.MatchType.ToString(),
                        MatchPlayerType = stats.MatchPlayerType.ToString(),
                        stats.MatchName,
                        stats.MatchRoute,
                        stats.MatchTeamId,
                        stats.TeamId,
                        stats.TeamName,
                        stats.TeamRoute,
                        stats.OppositionTeamId,
                        stats.OppositionTeamName,
                        stats.OppositionTeamRoute,
                        stats.MatchInningsPair,
                        stats.HasRunsConceded,
                        stats.PlayerWasDismissed,
                        stats.Catches,
                        stats.RunOuts,
                        stats.PlayerOfTheMatch
                    },
                                                                        transaction).ConfigureAwait(false);

                    Assert.Equal(1, count);

                    transaction.Rollback();
                }
        public async Task UpdatePlayerStatistics_throws_ArgumentNullException_if_transaction_is_null()
        {
            var repo = new SqlServerStatisticsRepository(Mock.Of <IPlayerRepository>());

            await Assert.ThrowsAsync <ArgumentNullException>(async() => await repo.UpdatePlayerStatistics(Array.Empty <PlayerInMatchStatisticsRecord>(), null).ConfigureAwait(false)).ConfigureAwait(false);
        }
        public async Task UpdatePlayerStatistics_throws_ArgumentNullException_if_statisticsData_is_null()
        {
            var repo = new SqlServerStatisticsRepository(Mock.Of <IPlayerRepository>());

            await Assert.ThrowsAsync <ArgumentNullException>(async() => await repo.UpdatePlayerStatistics(null, Mock.Of <IDbTransaction>()).ConfigureAwait(false)).ConfigureAwait(false);
        }
        public async Task DeletePlayerStatistics_throws_ArgumentNullException_if_transaction_is_null()
        {
            var repo = new SqlServerStatisticsRepository(Mock.Of <IPlayerRepository>());

            await Assert.ThrowsAsync <ArgumentNullException>(async() => await repo.DeletePlayerStatistics(Guid.NewGuid(), null).ConfigureAwait(false)).ConfigureAwait(false);
        }
        public async Task UpdateBowlingFigures_inserts_and_returns_BowlingFigures()
        {
            using (var connection = _databaseFixture.ConnectionFactory.CreateDatabaseConnection())
            {
                connection.Open();

                using (var transaction = connection.BeginTransaction())
                {
                    var data = await connection.QuerySingleAsync <(Guid matchInningsId, Guid bowlerPlayerIdentityId)>($"SELECT TOP 1 MatchInningsId, BowlerPlayerIdentityId FROM {Tables.BowlingFigures}", transaction : transaction).ConfigureAwait(false);

                    var innings = new MatchInnings
                    {
                        MatchInningsId = data.matchInningsId,
                        BowlingFigures = new List <BowlingFigures> {
                            {
                                new BowlingFigures {
                                    BowlingFiguresId = Guid.NewGuid(),
                                    Bowler           = new PlayerIdentity {
                                        PlayerIdentityId = data.bowlerPlayerIdentityId
                                    },
                                    Overs        = (decimal)5.4,
                                    Maidens      = 1,
                                    RunsConceded = 25,
                                    Wickets      = 2
                                }
                            }
                        }
                    };
                    var memberKey  = Guid.NewGuid();
                    var memberName = "Member name";

                    var playerRepo = new Mock <IPlayerRepository>();
                    playerRepo.Setup(x => x.CreateOrMatchPlayerIdentity(innings.BowlingFigures[0].Bowler, memberKey, memberName, transaction)).Returns(Task.FromResult(innings.BowlingFigures[0].Bowler));

                    var statisticsRepo = new SqlServerStatisticsRepository(playerRepo.Object);

                    var results = await statisticsRepo.UpdateBowlingFigures(innings, memberKey, memberName, transaction).ConfigureAwait(false);

                    var count = await connection.ExecuteScalarAsync <int>(@$ "SELECT COUNT(*) FROM {Tables.BowlingFigures} 
                                        WHERE BowlingFiguresId = @BowlingFiguresId
                                        AND BowlerPlayerIdentityId = @PlayerIdentityId
                                        AND Overs = @Overs
                                        AND Maidens = @Maidens
                                        AND RunsConceded = @RunsConceded
                                        AND Wickets = @Wickets",
                                                                          new
                    {
                        innings.BowlingFigures[0].BowlingFiguresId,
                        innings.BowlingFigures[0].Bowler.PlayerIdentityId,
                        innings.BowlingFigures[0].Overs,
                        innings.BowlingFigures[0].Maidens,
                        innings.BowlingFigures[0].RunsConceded,
                        innings.BowlingFigures[0].Wickets
                    },
                                                                          transaction).ConfigureAwait(false);

                    Assert.Equal(1, count);

                    for (var i = 0; i < innings.BowlingFigures.Count; i++)
                    {
                        Assert.Equal(innings.BowlingFigures[i].BowlingFiguresId, results[i].BowlingFiguresId);
                        Assert.Equal(innings.BowlingFigures[i].Bowler.PlayerIdentityId, results[i].Bowler.PlayerIdentityId);
                        Assert.Equal(innings.BowlingFigures[i].Overs, results[i].Overs);
                        Assert.Equal(innings.BowlingFigures[i].Maidens, results[i].Maidens);
                        Assert.Equal(innings.BowlingFigures[i].RunsConceded, results[i].RunsConceded);
                        Assert.Equal(innings.BowlingFigures[i].Wickets, results[i].Wickets);
                    }

                    transaction.Rollback();
                }
            }
        }