added some initial routes, ways to show overall stats, matches
This commit is contained in:
117
Sources/App/Controllers/StatsAPIController.swift
Normal file
117
Sources/App/Controllers/StatsAPIController.swift
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
////
|
||||||
|
//// StatsAPIController.swift
|
||||||
|
//// App
|
||||||
|
////
|
||||||
|
//// Created by Michael Simard on 5/29/20.
|
||||||
|
////
|
||||||
|
//
|
||||||
|
//import Fluent
|
||||||
|
//import Vapor
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//protocol ContentController {
|
||||||
|
// associatedtype Model: Fluent.Model
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//protocol StatsContentRepresentable {
|
||||||
|
// associatedtype StatsItem: Content
|
||||||
|
// var statsContent : StatsItem { get }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//protocol StatsContentController: ContentController where Model: StatsContentRepresentable {
|
||||||
|
//
|
||||||
|
// func stats (_:Request) throws -> EventLoopFuture<Page<Model.StatsItem>>
|
||||||
|
// func setupStatsRoute( routes: RoutesBuilder)
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//extension StatsContentController {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// func stats (req:Request) throws -> EventLoopFuture<Page<Model.StatsItem>> {
|
||||||
|
// return Model.query(on: req.db).paginate(for: req).map { $0.map(\.statsContent)}
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func setupStatsRoute( routes: RoutesBuilder)
|
||||||
|
// {
|
||||||
|
// routes.get(use: self.stats)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////***********
|
||||||
|
//
|
||||||
|
//final class StatsModel: Model, Content {
|
||||||
|
// typealias IDValue = <#type#>
|
||||||
|
//
|
||||||
|
// static var schema: String
|
||||||
|
//
|
||||||
|
// init() {
|
||||||
|
// <#code#>
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var winLoss:String
|
||||||
|
// var totalWins:Int
|
||||||
|
// var totalLosses:Int
|
||||||
|
// init( winLoss:String, totalWins:Int, totalLosses:Int) {
|
||||||
|
//
|
||||||
|
// self.winLoss = winLoss
|
||||||
|
// self.totalWins = totalWins
|
||||||
|
// self.totalLosses = totalLosses
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//extension StatsModel: StatsContentRepresentable {
|
||||||
|
//
|
||||||
|
// struct StatsItem: Content {
|
||||||
|
//
|
||||||
|
// var winLoss:String
|
||||||
|
// var totalWins:Int
|
||||||
|
// var totalLosses:Int
|
||||||
|
//
|
||||||
|
// init(model:StatsModel) {
|
||||||
|
//
|
||||||
|
// self.winLoss = model.winLoss
|
||||||
|
// self.totalWins = model.totalWins
|
||||||
|
// self.totalLosses = model.totalLosses
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var statsContent: StatsItem { .init(model:self) }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////***********
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//struct StatsAPIController: StatsContentController {
|
||||||
|
//
|
||||||
|
// typealias Model = StatsModel
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//struct StatsRouter: RouteCollection {
|
||||||
|
//
|
||||||
|
// func boot(routes: RoutesBuilder) throws {
|
||||||
|
// let statsRoute = routes.grouped("api", "stats")
|
||||||
|
//
|
||||||
|
// StatsAPIController().setupStatsRoute(routes: statsRoute)
|
||||||
|
//
|
||||||
|
//// statsRoute.get("allMatches", use: index)
|
||||||
|
//// statsRoute.get("totalWins", use: totalWins)
|
||||||
|
//// statsRoute.get("totalLosses", use: totalLosses)
|
||||||
|
// //statsRoute.get("overall", use: totalLosses)
|
||||||
|
//
|
||||||
|
// //beaconsRoute.get("overallStats", use: index)
|
||||||
|
// //beaconsRoute.post("", use: create)
|
||||||
|
// // beaconsRoute.delete(":beaconID", use: delete)
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//}
|
||||||
86
Sources/App/Controllers/StatsController.swift
Normal file
86
Sources/App/Controllers/StatsController.swift
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import Fluent
|
||||||
|
import Vapor
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct StatsController: RouteCollection {
|
||||||
|
func boot(routes: RoutesBuilder) throws {
|
||||||
|
let statsRoute = routes.grouped("api", "stats")
|
||||||
|
|
||||||
|
statsRoute.get("allMatches", use: index)
|
||||||
|
statsRoute.get("totalWins", use: totalWins)
|
||||||
|
statsRoute.get("totalLosses", use: totalLosses)
|
||||||
|
statsRoute.get("overall", use: overall)
|
||||||
|
|
||||||
|
//beaconsRoute.get("overallStats", use: index)
|
||||||
|
//beaconsRoute.post("", use: create)
|
||||||
|
// beaconsRoute.delete(":beaconID", use: delete)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func index(req: Request) throws -> EventLoopFuture<[Match]> {
|
||||||
|
return Match.query(on: req.db).all()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func totalWins(req: Request) throws -> EventLoopFuture<Int> {
|
||||||
|
return Match.query(on: req.db)
|
||||||
|
.filter(\.$win == true)
|
||||||
|
.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
func totalLosses(req: Request) throws -> EventLoopFuture<Int> {
|
||||||
|
return Match.query(on: req.db)
|
||||||
|
.filter(\.$win == false)
|
||||||
|
.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func overall(req: Request) throws -> EventLoopFuture<Stats> {
|
||||||
|
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
|
||||||
|
|
||||||
|
let ratio:Double = (Double(winCount) / Double(lossCount)).truncate(places: 2)
|
||||||
|
|
||||||
|
return Stats.init(winLoss: String(ratio), totalWins: winCount, totalLosses: lossCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
|
// func create(req: Request) throws -> EventLoopFuture<Beacon> {
|
||||||
|
// let newBeacon = try req.content.decode(Beacon.Create.self)
|
||||||
|
// let beacon = Beacon(id: UUID(), ownerId: nil)
|
||||||
|
// return beacon.save(on: req.db).map { beacon }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func delete(req: Request) throws -> EventLoopFuture<HTTPStatus> {
|
||||||
|
// return Beacon.find(req.parameters.get("beaconID"), on: req.db)
|
||||||
|
// .unwrap(or: Abort(.notFound))
|
||||||
|
// .flatMap { $0.delete(on: req.db) }
|
||||||
|
// .transform(to: .ok)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension Double
|
||||||
|
{
|
||||||
|
func truncate(places : Int)-> Double
|
||||||
|
{
|
||||||
|
return Double(floor(pow(10.0, Double(places)) * self)/pow(10.0, Double(places)))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import Fluent
|
|
||||||
import Vapor
|
|
||||||
|
|
||||||
struct TodoController: RouteCollection {
|
|
||||||
func boot(routes: RoutesBuilder) throws {
|
|
||||||
let todos = routes.grouped("match")
|
|
||||||
todos.get(use: index)
|
|
||||||
todos.post(use: create)
|
|
||||||
todos.group(":matchID") { todo in
|
|
||||||
todo.delete(use: delete)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func index(req: Request) throws -> EventLoopFuture<[Todo]> {
|
|
||||||
return Todo.query(on: req.db).all()
|
|
||||||
}
|
|
||||||
|
|
||||||
func create(req: Request) throws -> EventLoopFuture<Todo> {
|
|
||||||
let todo = try req.content.decode(Todo.self)
|
|
||||||
return todo.save(on: req.db).map { todo }
|
|
||||||
}
|
|
||||||
|
|
||||||
func delete(req: Request) throws -> EventLoopFuture<HTTPStatus> {
|
|
||||||
return Todo.find(req.parameters.get("matchID"), on: req.db)
|
|
||||||
.unwrap(or: Abort(.notFound))
|
|
||||||
.flatMap { $0.delete(on: req.db) }
|
|
||||||
.transform(to: .ok)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@ struct CreateMatch: Migration {
|
|||||||
.id()
|
.id()
|
||||||
.field("map", .string)
|
.field("map", .string)
|
||||||
.field("win", .bool)
|
.field("win", .bool)
|
||||||
.field("date", .bool)
|
.field("date", .date)
|
||||||
.field("roundsWon", .int)
|
.field("roundsWon", .int)
|
||||||
.field("roundsLost", .int)
|
.field("roundsLost", .int)
|
||||||
|
|
||||||
|
|||||||
43
Sources/App/Models/Match.swift
Normal file
43
Sources/App/Models/Match.swift
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import Fluent
|
||||||
|
import Vapor
|
||||||
|
|
||||||
|
final class Match: Model, Content {
|
||||||
|
static let schema = "match"
|
||||||
|
|
||||||
|
@ID(key: .id)
|
||||||
|
var id: UUID?
|
||||||
|
|
||||||
|
@Field(key: "map")
|
||||||
|
var map: String?
|
||||||
|
|
||||||
|
@Field(key: "win")
|
||||||
|
var win: Bool
|
||||||
|
|
||||||
|
@Field(key: "date")
|
||||||
|
var date: Date
|
||||||
|
|
||||||
|
@Field(key: "roundsWon")
|
||||||
|
var roundsWon: Int?
|
||||||
|
|
||||||
|
@Field(key: "roundsLost")
|
||||||
|
var roundsLost: Int?
|
||||||
|
|
||||||
|
|
||||||
|
init() { }
|
||||||
|
|
||||||
|
init(id: UUID? = nil, map:String?, win:Bool, date:Date, roundsWon:Int?, roundsLost:Int?) {
|
||||||
|
self.id = id
|
||||||
|
self.map = map
|
||||||
|
self.win = win
|
||||||
|
self.date = date
|
||||||
|
self.roundsWon = roundsWon
|
||||||
|
self.roundsLost = roundsLost
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Match {
|
||||||
|
struct Create: Content {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
24
Sources/App/Models/Stats.swift
Normal file
24
Sources/App/Models/Stats.swift
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Stats.swift
|
||||||
|
// App
|
||||||
|
//
|
||||||
|
// Created by Michael Simard on 5/29/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
import Fluent
|
||||||
|
import Vapor
|
||||||
|
|
||||||
|
final class Stats: Content {
|
||||||
|
var winLossRatio:String
|
||||||
|
var totalWins:Int
|
||||||
|
var totalLosses:Int
|
||||||
|
|
||||||
|
init( winLoss:String, totalWins:Int, totalLosses:Int) {
|
||||||
|
self.winLossRatio = winLoss
|
||||||
|
self.totalWins = totalWins
|
||||||
|
self.totalLosses = totalLosses
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import Fluent
|
|
||||||
import Vapor
|
|
||||||
|
|
||||||
final class Todo: Model, Content {
|
|
||||||
static let schema = "todos"
|
|
||||||
|
|
||||||
@ID(key: .id)
|
|
||||||
var id: UUID?
|
|
||||||
|
|
||||||
@Field(key: "title")
|
|
||||||
var title: String
|
|
||||||
|
|
||||||
init() { }
|
|
||||||
|
|
||||||
init(id: UUID? = nil, title: String) {
|
|
||||||
self.id = id
|
|
||||||
self.title = title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,10 +8,10 @@ public func configure(_ app: Application) throws {
|
|||||||
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
|
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
|
||||||
|
|
||||||
app.databases.use(.postgres(
|
app.databases.use(.postgres(
|
||||||
hostname: Environment.get("DATABASE_HOST") ?? "localhost",
|
hostname: Environment.get("DATABASE_HOST") ?? "sledsoft.com",
|
||||||
username: Environment.get("DATABASE_USERNAME") ?? "fanosphere",
|
username: Environment.get("DATABASE_USERNAME") ?? "cod",
|
||||||
password: Environment.get("DATABASE_PASSWORD") ?? "pw4fanosphere",
|
password: Environment.get("DATABASE_PASSWORD") ?? "pw4cod",
|
||||||
database: Environment.get("DATABASE_NAME") ?? "codmw"
|
database: Environment.get("DATABASE_NAME") ?? "cod_db"
|
||||||
), as: .psql)
|
), as: .psql)
|
||||||
|
|
||||||
app.migrations.add(CreateMatch())
|
app.migrations.add(CreateMatch())
|
||||||
|
|||||||
@@ -10,5 +10,5 @@ func routes(_ app: Application) throws {
|
|||||||
return "Hello, world!"
|
return "Hello, world!"
|
||||||
}
|
}
|
||||||
|
|
||||||
try app.register(collection: TodoController())
|
try app.register(collection: StatsController())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user