// // Queries.swift // TournamentStats // // Created by Laurent Morvillier on 03/06/2019. // Copyright © 2019 Stax River. All rights reserved. // import Foundation import RealmSwift import Realm class Queries { static func festivalStats(realm: Realm) -> FestivalStats { let tournaments = realm.objects(Tournament.self) let stats = FestivalStats() stats.cumulatedBuyins = tournaments.sum(ofProperty: "buyin") stats.totalEntries = tournaments.sum(ofProperty: "entries") stats.totalPrizePool = tournaments.sum(ofProperty: "prizepool") stats.eventsCount = tournaments.count return stats } static func biggestWinners(realm: Realm) -> [CumulatedResults] { let players = realm.objects(Player.self) var crArray: [CumulatedResults] = [] for player in players { crArray.append(CumulatedResults(player: player)) } return crArray.sorted(by: { (cr1, cr2) -> Bool in return cr1.total > cr2.total }) } static func averageCash(realm: Realm, minCount: Int) -> [CumulatedResults] { let players = realm.objects(Player.self).filter(NSPredicate(format: "results.@count >= %i", minCount)) var crArray: [CumulatedResults] = [] for player in players { crArray.append(CumulatedResults(player: player, options: [.average])) } return crArray.sorted(by: { (cr1, cr2) -> Bool in return cr1.total > cr2.total }) } static func mostCashes(realm: Realm, notable: Bool = false) -> [CumulatedResults] { var players = realm.objects(Player.self) if (notable) { players = players.filter("notable = true") } var crArray: [CumulatedResults] = [] for player in players { crArray.append(CumulatedResults(player: player, options: [.countSorted])) } return crArray.sorted(by: { (cr1, cr2) -> Bool in if cr1.numberOfCashes == cr2.numberOfCashes { return cr1.total > cr2.total } return cr1.numberOfCashes > cr2.numberOfCashes }) } static func mostWins(realm: Realm) -> [CumulatedWins] { var crArray: [CumulatedWins] = [] for player in realm.objects(Player.self) { crArray.append(CumulatedWins(player: player)) } crArray = crArray.filter { $0.winsCount > 0 } return crArray.sorted(by: { (cr1, cr2) -> Bool in if cr1.winsCount == cr2.winsCount { return cr1.numberOfCashes > cr2.numberOfCashes } return cr1.winsCount > cr2.winsCount }) } static func allWinnersSortedByEvent(realm: Realm, date: Date? = nil) -> [TournamentWinner] { let winners: Results if let day = date { winners = realm.objects(Result.self).filter("rank == 1 && ANY tournaments.date IN %@", [day]) } else { winners = realm.objects(Result.self).filter("rank == 1") } var tws: [TournamentWinner] = [] for w in winners { let tw = TournamentWinner(tournament: w.tournaments.first!, result: w) tws.append(tw) } tws.sort { (tw1, tw2) -> Bool in tw1.tournament.number < tw2.tournament.number } return tws } static func notableCashes(realm: Realm, date: Date) -> [PlayerResult] { let notableCashes: Results = realm.objects(Result.self).filter("player.notable = true && ANY tournaments.date IN %@", [date]) var prs: [PlayerResult] = [] for nc in notableCashes { let pr = PlayerResult(tournament: nc.tournaments.first!, result: nc) prs.append(pr) } prs.sort { (pr1, pr2) -> Bool in if pr1.result.rank == pr2.result.rank { return pr1.result.earnings > pr2.result.earnings } return pr1.result.rank < pr2.result.rank } return prs } static func sortedEvents(realm: Realm, fieldName: String, ascending: Bool) -> [TournamentRepresentable] { let tournies = realm.objects(Tournament.self).sorted(byKeyPath: fieldName, ascending: ascending) var trs: [TournamentRepresentable] = [] for tourny in tournies { trs.append(TournamentRepresentable(tournament: tourny)) } return trs } static func cashesByCountry(realm: Realm) -> [CountryCounter] { let playerDistinctCountries = realm.objects(Player.self).distinct(by: ["country"]) var countryCashes: [CountryCounter] = [] for player in playerDistinctCountries { let country = player.country let resultsByCountry = realm.objects(Result.self).filter("player.country == %@", country) let cc = CountryCounter(country: country, counter: resultsByCountry.count) countryCashes.append(cc) } countryCashes.sort { (cc1, cc2) -> Bool in return cc1.counter > cc2.counter } return countryCashes } static func winsByCountry(realm: Realm) -> [CountryCounter] { let winners: Results = realm.objects(Result.self).filter("rank == 1") var countryWins: [String : CountryCounter] = [:] for winner in winners { if let country = winner.player?.country { if let cc = countryWins[country] { cc.increment() } else { countryWins[country] = CountryCounter(country: country, counter: 1) } } } var sortedCountries = countryWins.values.map { $0 } sortedCountries.sort { (cc1, cc2) -> Bool in return cc1.counter > cc2.counter } return sortedCountries } static func averageEvent(realm: Realm) -> [TournamentStats] { let tournaments: Results = realm.objects(Tournament.self) let entries: Double? = tournaments.average(ofProperty: "entries") let buyin: Double? = tournaments.average(ofProperty: "buyin") let prizepool: Double? = tournaments.average(ofProperty: "prizepool") let winnerResults = tournaments.compactMap { (tournament) -> Result? in return tournament.results.first { $0.rank == 1 } } let averageFirstPrize = winnerResults.reduce(0.0) { $0 + Double($1.earnings) } / Double(tournaments.count) if let entries = entries, let buyin = buyin, let prizepool = prizepool { let ts = TournamentStats(entries: entries, buyin: buyin, prizepool: prizepool, firstPrize: averageFirstPrize) return [ts] } return [] } static func tournamentBuyinDistribution(realm: Realm) -> [DistributionCounter] { let tournaments: Results = realm.objects(Tournament.self) let verylow = DistributionCounter(name: "<$1,000") let low = DistributionCounter(name: "$1,000 - $1,999") let medium = DistributionCounter(name: "$2,000 - $5,000") let high = DistributionCounter(name: ">$5,000") let counters: [DistributionCounter] = [verylow, low, medium, high] tournaments.forEach { tournament in switch tournament.buyin { case 0..<1000: verylow.increment() case 1000..<2000: low.increment() case 2000...5000: medium.increment() default: high.increment() } } return counters } static func tournamentPrizepoolDistribution(realm: Realm) -> [DistributionCounter] { let tournaments: Results = realm.objects(Tournament.self) let low = DistributionCounter(name: "<$1M)") let medium = DistributionCounter(name: "$1M - $5M") let high = DistributionCounter(name: ">5M") let counters: [DistributionCounter] = [low, medium, high] tournaments.forEach { tournament in switch tournament.prizepool { case 0.0..<1000000.0: low.increment() case 1000000.0...5000000.0: medium.increment() default: high.increment() } } return counters } static func firstPrizeDistribution(realm: Realm) -> [DistributionCounter] { let winnerResults = realm.objects(Result.self).filter("rank == 1") let low = DistributionCounter(name: "<$250K") let medium = DistributionCounter(name: "$250K - $1M") let high = DistributionCounter(name: ">$1M") let counters: [DistributionCounter] = [low, medium, high] winnerResults.forEach { result in switch result.earnings { case 0.0..<250000.0: low.increment() case 250000.0...1000000.0: medium.increment() default: high.increment() } } return counters } static func gamesDistribution(realm: Realm) -> [DistributionCounter] { let tournaments: Results = realm.objects(Tournament.self) let noLimitHoldem = DistributionCounter(name: Game.holdem.rawValue) let potLimitOmaha = DistributionCounter(name: Game.omaha.rawValue) let not = DistributionCounter(name: "Others") let games: [DistributionCounter] = [noLimitHoldem, potLimitOmaha, not] tournaments.forEach { tournament in if tournament.name.contains(Game.holdem.rawValue) { noLimitHoldem.increment() } else if tournament.name.contains(Game.omaha.rawValue) { potLimitOmaha.increment() } else { not.increment() } } return games } static func tableSizeDistribution(realm: Realm) -> [DistributionCounter] { let tournaments: Results = realm.objects(Tournament.self).filter("name CONTAINS %@", "No-Limit Hold'em").distinct(by: ["tableSize"]) var slices: [DistributionCounter] = [] var othersCount: Int = 0 for tournament in tournaments { let tableSizeCount = realm.objects(Tournament.self).filter("name CONTAINS %@", "No-Limit Hold'em").filter("tableSize == %i", tournament.tableSize).count if (tableSizeCount < 6) { othersCount += tableSizeCount } else { let counter = DistributionCounter(name: TableSize.format(tableSize: tournament.tableSize), counter: tableSizeCount) slices.append(counter) } } let others = DistributionCounter(name: "Others", counter: othersCount) slices.append(others) slices.sort { (d1, d2) -> Bool in return d1.counter > d2.counter } return slices } static func rankingCounts(realm: Realm) -> [PlayerNotableFinishes] { let players: Results = realm.objects(Player.self) var notableFinishes: [PlayerNotableFinishes] = [] players.forEach { player in var wins: [Result] = [] var runnerUps: [Result] = [] var finalTables: [Result] = [] player.results.forEach { result in switch result.rank { case 1: wins.append(result) case 2: runnerUps.append(result) default: break } let tableSize: Int = result.tournaments.first?.tableSize ?? 9 if result.rank <= tableSize { finalTables.append(result) } } notableFinishes.append(PlayerNotableFinishes(player: player, wins: wins, runnerUps: runnerUps, finalTables: finalTables)) } return notableFinishes } }