mirror of
https://github.com/nprasad2077/NBA_Go.git
synced 2026-09-22 14:05:13 +00:00
250 lines
8.4 KiB
Go
250 lines
8.4 KiB
Go
package controllers
|
|
|
|
import (
|
|
"github.com/gofiber/fiber/v2"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/nprasad2077/NBA_Go/models"
|
|
"github.com/nprasad2077/NBA_Go/services"
|
|
)
|
|
|
|
// --- MODIFICATION START ---
|
|
// A DTO is created to control the JSON output for advanced stats.
|
|
// It omits fields like ID, ExternalID, CreatedAt, UpdatedAt, and DeletedAt.
|
|
type PlayerAdvancedStatDTO struct {
|
|
PlayerID string `json:"playerId"`
|
|
PlayerName string `json:"playerName"`
|
|
Position string `json:"position"`
|
|
Age int `json:"age"`
|
|
Team string `json:"team"`
|
|
Games int `json:"games"`
|
|
MinutesPlayed int `json:"minutesPlayed"`
|
|
PER float64 `json:"per"`
|
|
TSPercent float64 `json:"tsPercent"`
|
|
ThreePAR float64 `json:"threePAR"`
|
|
FTr float64 `json:"ftr"`
|
|
OffensiveRBPercent float64 `json:"offensiveRBPercent"`
|
|
DefensiveRBPercent float64 `json:"defensiveRBPercent"`
|
|
TotalRBPercent float64 `json:"totalRBPercent"`
|
|
AssistPercent float64 `json:"assistPercent"`
|
|
StealPercent float64 `json:"stealPercent"`
|
|
BlockPercent float64 `json:"blockPercent"`
|
|
TurnoverPercent float64 `json:"turnoverPercent"`
|
|
UsagePercent float64 `json:"usagePercent"`
|
|
OffensiveWS float64 `json:"offensiveWS"`
|
|
DefensiveWS float64 `json:"defensiveWS"`
|
|
WinShares float64 `json:"winShares"`
|
|
WinSharesPer float64 `json:"winSharesPer"`
|
|
OffensiveBox float64 `json:"offensiveBox"`
|
|
DefensiveBox float64 `json:"defensiveBox"`
|
|
Box float64 `json:"box"`
|
|
VORP float64 `json:"vorp"`
|
|
Season int `json:"season"`
|
|
IsPlayoff bool `json:"isPlayoff"`
|
|
}
|
|
|
|
// AdvancedStatsResponse is the swagger response model for GetAllAdvancedPlayerStats
|
|
// It wraps the returned player advanced stats and pagination metadata.
|
|
// The Data field is updated to use the DTO.
|
|
type AdvancedStatsResponse struct {
|
|
Data []PlayerAdvancedStatDTO `json:"data"`
|
|
Pagination struct {
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"pageSize"`
|
|
Pages int64 `json:"pages"`
|
|
} `json:"pagination"`
|
|
}
|
|
// --- MODIFICATION END ---
|
|
|
|
|
|
var advancedSortMap = map[string]string{
|
|
"playerId": "player_id",
|
|
"playerName": "player_name",
|
|
"position": "position",
|
|
"age": "age",
|
|
"games": "games",
|
|
"minutesPlayed": "minutes_played",
|
|
"per": "per",
|
|
"tsPercent": "ts_percent",
|
|
"threePAR": "three_par",
|
|
"ftr": "ftr",
|
|
"offensiveRBPercent": "offensive_rb_percent",
|
|
"defensiveRBPercent": "defensive_rb_percent",
|
|
"totalRBPercent": "total_rb_percent",
|
|
"assistPercent": "assist_percent",
|
|
"stealPercent": "steal_percent",
|
|
"blockPercent": "block_percent",
|
|
"turnoverPercent": "turnover_percent",
|
|
"usagePercent": "usage_percent",
|
|
"offensiveWS": "offensive_ws",
|
|
"defensiveWS": "defensive_ws",
|
|
"winShares": "win_shares",
|
|
"winSharesPer": "win_shares_per",
|
|
"offensiveBox": "offensive_box",
|
|
"defensiveBox": "defensive_box",
|
|
"box": "box",
|
|
"vorp": "vorp",
|
|
"team": "team",
|
|
"season": "season",
|
|
}
|
|
|
|
|
|
// ScrapePlayerAdvancedStats godoc
|
|
// @ignore
|
|
// @Summary Scrape player advanced stats from BR website
|
|
// @Tags PlayerStats
|
|
// @Param season query int true "Season (e.g. 2025)"
|
|
// @Param isPlayoff query bool false "Whether playoffs?"
|
|
// @Success 200 {object} map[string]string
|
|
// @Failure 400,500 {object} map[string]string
|
|
// //@Router /api/playeradvancedstats/scrape [get]
|
|
func ScrapePlayerAdvancedStats(db *gorm.DB) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
season := c.QueryInt("season", 0)
|
|
if season == 0 {
|
|
return c.Status(400).JSON(fiber.Map{"error": "season is required"})
|
|
}
|
|
isPlayoff := c.QueryBool("isPlayoff", false)
|
|
|
|
if err := services.FetchAndStorePlayerAdvancedScrapedStats(db, season, isPlayoff); err != nil {
|
|
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
|
}
|
|
return c.JSON(fiber.Map{"message": "scrape+store complete"})
|
|
}
|
|
}
|
|
|
|
// GetAllAdvancedPlayerStats godoc
|
|
// //@Security ApiKeyAuth
|
|
// @Summary Get player advanced stats
|
|
// @Description Returns filtered and paginated player advanced stats
|
|
// @Tags PlayerStats
|
|
// @x-order 2
|
|
// @Group Player Stats
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param season query int false "Season (e.g., 2025)"
|
|
// @Param team query string false "Team abbreviation (e.g., MIL)"
|
|
// @Param playerId query string false "Player ID (e.g., greenaj01)"
|
|
// @Param page query int false "Page number" default(1)
|
|
// @Param pageSize query int false "Page size" default(20)
|
|
// @Param sortBy query string false "Field to sort by" default(winShares)
|
|
// @Param ascending query bool false "Sort ascending" default(false)
|
|
// @Param isPlayoff query bool false "Whether playoffs?"
|
|
// @Success 200 {object} controllers.AdvancedStatsResponse
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /api/playeradvancedstats [get]
|
|
func GetAllAdvancedPlayerStats(db *gorm.DB) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
var stats []models.PlayerAdvancedStat
|
|
|
|
// --- FILTERS ---
|
|
playerId := c.Query("playerId")
|
|
if playerId == "" {
|
|
playerId = c.Query("player_id")
|
|
}
|
|
|
|
season := c.QueryInt("season", 0)
|
|
team := c.Query("team")
|
|
|
|
// --- PAGINATION ---
|
|
page := c.QueryInt("page", 1)
|
|
pageSize := c.QueryInt("pageSize", 20)
|
|
if pageSize > 50 {
|
|
pageSize = 50
|
|
}
|
|
offset := (page - 1) * pageSize
|
|
|
|
// --- SORTING ---
|
|
sortByParam := c.Query("sortBy", "winShares")
|
|
ascending := c.QueryBool("ascending", false)
|
|
|
|
sortBy, ok := advancedSortMap[sortByParam]
|
|
if !ok {
|
|
sortBy = "win_shares" // Safe default
|
|
}
|
|
|
|
order := sortBy + " DESC"
|
|
if ascending {
|
|
order = sortBy + " ASC"
|
|
}
|
|
|
|
// --- QUERY BUILDING ---
|
|
query := db.Model(&models.PlayerAdvancedStat{})
|
|
|
|
if season != 0 {
|
|
query = query.Where("season = ?", season)
|
|
}
|
|
if team != "" {
|
|
query = query.Where("team = ?", team)
|
|
}
|
|
if playerId != "" {
|
|
query = query.Where("player_id = ?", playerId)
|
|
}
|
|
|
|
if c.Query("isPlayoff") != "" {
|
|
isPlayoff := c.QueryBool("isPlayoff", false)
|
|
query = query.Where("is_playoff = ?", isPlayoff)
|
|
}
|
|
|
|
// Count total records for pagination
|
|
var total int64
|
|
query.Count(&total)
|
|
|
|
// Fetch the data page
|
|
err := query.Order(order).Limit(pageSize).Offset(offset).Find(&stats).Error
|
|
if err != nil {
|
|
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
|
}
|
|
|
|
// --- MODIFICATION START ---
|
|
// Transform the database models into DTOs.
|
|
advancedStatDTOs := make([]PlayerAdvancedStatDTO, len(stats))
|
|
for i, s := range stats {
|
|
advancedStatDTOs[i] = PlayerAdvancedStatDTO{
|
|
PlayerID: s.PlayerID,
|
|
PlayerName: s.PlayerName,
|
|
Position: s.Position,
|
|
Age: s.Age,
|
|
Team: s.Team,
|
|
Games: s.Games,
|
|
MinutesPlayed: s.MinutesPlayed,
|
|
PER: s.PER,
|
|
TSPercent: s.TSPercent,
|
|
ThreePAR: s.ThreePAR,
|
|
FTr: s.FTR, // FIX: Changed s.FTr to s.FTR to match the model
|
|
OffensiveRBPercent: s.OffensiveRBPercent,
|
|
DefensiveRBPercent: s.DefensiveRBPercent,
|
|
TotalRBPercent: s.TotalRBPercent,
|
|
AssistPercent: s.AssistPercent,
|
|
StealPercent: s.StealPercent,
|
|
BlockPercent: s.BlockPercent,
|
|
TurnoverPercent: s.TurnoverPercent,
|
|
UsagePercent: s.UsagePercent,
|
|
OffensiveWS: s.OffensiveWS,
|
|
DefensiveWS: s.DefensiveWS,
|
|
WinShares: s.WinShares,
|
|
WinSharesPer: s.WinSharesPer,
|
|
OffensiveBox: s.OffensiveBox,
|
|
DefensiveBox: s.DefensiveBox,
|
|
Box: s.Box,
|
|
VORP: s.VORP,
|
|
Season: s.Season,
|
|
IsPlayoff: s.IsPlayoff,
|
|
}
|
|
}
|
|
|
|
// Build the final response using the new DTOs and response struct.
|
|
resp := AdvancedStatsResponse{
|
|
Data: advancedStatDTOs,
|
|
}
|
|
resp.Pagination.Total = total
|
|
resp.Pagination.Page = page
|
|
resp.Pagination.PageSize = pageSize
|
|
resp.Pagination.Pages = (total + int64(pageSize) - 1) / int64(pageSize)
|
|
|
|
return c.JSON(resp)
|
|
// --- MODIFICATION END ---
|
|
}
|
|
}
|