import Fluent import Vapor struct CODDate { let month:Int let year:Int let day: Int } struct StatsController: RouteCollection { func boot(routes: RoutesBuilder) throws { let statsRoute = routes.grouped("cod-tracker","api", "stats") statsRoute.get("allMatches", use: index) statsRoute.get("totalWins", use: totalWins) statsRoute.get("totalLosses", use: totalLosses) statsRoute.get("overall", use: overall) statsRoute.get("all", use: all) statsRoute.get("allDaily", use: allDaily) } func index(req: Request) throws -> EventLoopFuture<[Match]> { return Match.query(on: req.db).sort(\.$date).all() } func totalWins(req: Request) throws -> EventLoopFuture { return Match.query(on: req.db) .filter(\.$win == true) .count() } func totalLosses(req: Request) throws -> EventLoopFuture { return Match.query(on: req.db) .filter(\.$win == false) .count() } func getMarchStats(req:Request) throws -> EventLoopFuture { return getstatsForMonth(year: 2020, month: 03, req: req) } func getstatsForMonth(year:Int, month:Int, req: Request) -> EventLoopFuture{ let winCount = Match.query(on: req.db) .filter(\.$date >= getStartOfMonth(month: month, year: year)) .filter(\.$date <= getEndOfMonth(month: month, year: year)) .filter(\.$win == true ) .count() let lossCount = Match.query(on: req.db) .filter(\.$date >= getStartOfMonth(month: month, year: year)) .filter(\.$date <= getEndOfMonth(month: month, year: year)) .filter(\.$win == false ) .count() let combined = winCount.and(lossCount) return combined.map { (winCount, lossCount) -> (Stats) in let ratio:Double = (Double(winCount) / Double(lossCount)).truncate(places: 2) return Stats.init(winLoss: String(ratio), totalWins: winCount, totalLosses: lossCount) } } func getStatsForDay(year:Int, month:Int, day:Int, req: Request) -> EventLoopFuture{ let winCount = Match.query(on: req.db) .filter(\.$date >= getStartOfDay(day:day, month: month, year: year)) .filter(\.$date <= getEndOfDay(day: day, month: month, year: year)) .filter(\.$win == true ) .count() let lossCount = Match.query(on: req.db) .filter(\.$date >= getStartOfDay(day:day, month: month, year: year)) .filter(\.$date <= getEndOfDay(day: day, month: month, year: year)) .filter(\.$win == false ) .count() let combined = winCount.and(lossCount) return combined.map { (winCount, lossCount) -> (Stats) in let ratio:Double = (Double(winCount) / Double(lossCount)).truncate(places: 2) return Stats.init(winLoss: String(ratio), totalWins: winCount, totalLosses: lossCount) } } func statsForRecent(numberGames:Int, req:Request) -> EventLoopFuture { let winCount = Match.query(on: req.db) .sort(\.$date) .range(lower: 0, upper: numberGames) .filter(\.$win == true ) .count() let lossCount = Match.query(on: req.db) .sort(\.$date) .range(lower: 0, upper: numberGames) .filter(\.$win == false ) .count() let combined = winCount.and(lossCount) return combined.map { (winCount, lossCount) -> (Stats) in let ratio:Double = (Double(winCount) / Double(lossCount)).truncate(places: 2) return Stats.init(winLoss: String(ratio), totalWins: winCount, totalLosses: lossCount) } } private func getStartOfMonth(month:Int, year:Int) -> Date { let calendar = Calendar.current var components = DateComponents() components.day = 1 components.month = month components.year = year components.hour = 0 components.minute = 0 return calendar.date(from: components)! } private func getEndOfMonth(month:Int, year:Int) -> Date { let calendar = Calendar.current var components = DateComponents() components.day = -1 components.month = month + 1 components.year = year components.hour = 23 components.minute = 59 return calendar.date(from: components)! } private func getStartOfDay(day:Int, month:Int, year:Int) -> Date { let calendar = Calendar.current var components = DateComponents() components.day = day components.month = month components.year = year components.hour = 0 components.minute = 0 return calendar.date(from: components)! } private func getEndOfDay(day:Int, month:Int, year:Int) -> Date { let calendar = Calendar.current var components = DateComponents() components.day = day components.month = month components.year = year components.hour = 23 components.minute = 59 return calendar.date(from: components)! } func all(req: Request) throws -> EventLoopFuture { var date = getStartDate() var previousMonths:[CODDate] = [] repeat { //let stats = getStatsByMonth(year: date.year, month: date.month, req: req) //returns eventloopfuture previousMonths.append(CODDate(month: date.month, year: date.year, day: 15)) date = Calendar.current.date(byAdding: .month, value: 1, to: date)! } while (date.month != (Date().month + 1) || date.year != Date().year) func getMonthStats (_ remaining: ArraySlice, allMonthlyStats: inout [MonthStats], eventLoop: EventLoop) -> EventLoopFuture<[MonthStats]> { var remaining = remaining if let first = remaining.popLast() { return getstatsForMonth(year: first.year, month: first.month, req: req).flatMap { [remaining, allMonthlyStats] (stats) -> EventLoopFuture<[MonthStats]> in var allMonthlyStats = allMonthlyStats allMonthlyStats.append(MonthStats(month: first.month, year: first.year, stats:stats )) return getMonthStats(remaining, allMonthlyStats:&allMonthlyStats, eventLoop: eventLoop) } } else { return req.eventLoop.makeSucceededFuture(allMonthlyStats) } } var stats:[MonthStats] = [] let monthstats = getMonthStats(previousMonths[0.. AllStats in return AllStats.init(overall: overall, byMonth: monthlyStats) } } func overall(req: Request) throws -> EventLoopFuture { let lossCount = Match.query(on: req.db) .filter(\.$win == false) .count() let winCount = Match.query(on: req.db) .filter(\.$win == true ) .count() let combined = winCount.and(lossCount) return combined.map { (winCount, lossCount) -> (Stats) in return Stats.init(winLoss: self.getRatio(num: Double(winCount), den: Double(lossCount)), totalWins: winCount, totalLosses: lossCount) } } private func getRatio( num:Double, den:Double) -> String { return String((Double(num) / Double(den)).truncate(places: 2)) } func allDaily(req:Request) -> EventLoopFuture{ var date = getStartDate() var previousDays:[CODDate] = [] repeat { previousDays.append(CODDate(month: date.month, year: date.year, day: date.day)) date = Calendar.current.date(byAdding: .day, value: 1, to: date)! } while (date < Date()) previousDays = previousDays.reversed() func getDailyStats (_ remaining: ArraySlice, allDailyStats: inout [DailyStats], eventLoop: EventLoop) -> EventLoopFuture<[DailyStats]> { var remaining = remaining if let first = remaining.popLast() { return getStatsForDay(year: first.year, month: first.month, day:first.day, req: req).flatMap { [remaining, allDailyStats] (stats) -> EventLoopFuture<[DailyStats]> in var allDailyStats = allDailyStats let totalWins = allDailyStats.reduce(Double(stats.totalWins)) { (total, dailyStats) -> Double in return total + Double(dailyStats.stats.totalWins) } let totalLosses = allDailyStats.reduce(Double(stats.totalLosses)) { (total, dailyStats) -> Double in return total + Double(dailyStats.stats.totalLosses) } allDailyStats.append(DailyStats(day: first.day, month: first.month, year: first.year, stats: stats, cumulativeRatio: self.getRatio(num: totalWins, den: totalLosses))) return getDailyStats(remaining, allDailyStats:&allDailyStats, eventLoop: eventLoop) } } else { return req.eventLoop.makeSucceededFuture(allDailyStats) } } var stats:[DailyStats] = [] let dailyStats = getDailyStats(previousDays[0.. AllDailyStats in return AllDailyStats(dailyStats: dailyStats.filter({ (dailyStats) -> Bool in if dailyStats.stats.totalWins == 0 && dailyStats.stats.totalLosses == 0 { return false } return true }).reversed() ) } } // func allCumulativeStats(req:Request) -> EventLoopFuture { // // // } private func getStartDate() -> Date { let calendar = Calendar.current var components = DateComponents() components.day = 20 components.month = 03 components.year = 2020 components.hour = 0 components.minute = 0 return calendar.date(from: components)! } } extension Double { func truncate(places : Int)-> Double { return Double(floor(pow(10.0, Double(places)) * self)/pow(10.0, Double(places))) } } extension Date { var month:Int { let calanderDate = Calendar.current.dateComponents([.day, .year, .month], from: self) return calanderDate.month ?? 1 } var year:Int { let calanderDate = Calendar.current.dateComponents([.day, .month, .year], from: self) return calanderDate.year ?? 1 } var day:Int { let calanderDate = Calendar.current.dateComponents([.day, .month, .year], from: self) return calanderDate.day ?? 1 } }