diff --git a/controllers/player_shot_chart_controller.go b/controllers/player_shot_chart_controller.go index 469f237..fb0df17 100644 --- a/controllers/player_shot_chart_controller.go +++ b/controllers/player_shot_chart_controller.go @@ -67,33 +67,69 @@ func ScrapePlayerShotChart(db *gorm.DB) fiber.Handler { } } + // GetPlayerShotChart godoc -// //@Security ApiKeyAuth -// @Summary Get shot-chart data -// @Description Returns shot-chart points, optionally filtered by playerId and/or season -// @Tags PlayerShotChart -// @Accept json -// @Produce json -// @Param playerId query string false "Player ID (e.g., hardeja01)" -// @Param season query int false "Season (e.g., 2023)" -// @Success 200 {array} models.PlayerShotChart -// @Failure 500 {object} map[string]string -// //@Router /api/playershotchart [get] +// @Summary Get shot-chart data +// @Description Returns a paginated list of shot-chart points, optionally filtered by various parameters. +// @Tags PlayerShotChart +// @Accept json +// @Produce json +// @Param page query int false "Page number for pagination (defaults to 1)" +// @Param playerId query string false "Player ID (e.g., hardeja01)" +// @Param season query int false "Season (e.g., 2023)" +// @Param date query string false "Game date (e.g., Oct 17, 2018)" +// @Param qtr query string false "Quarter (e.g., 1st Qtr)" +// @Param result query boolean false "Shot result (true for made, false for missed)" +// @Param shot_type query string false "Shot type (e.g., 2-pointer)" +// @Param opponent query string false "Opponent team (e.g., NOP)" +// @Success 200 {array} models.PlayerShotChart +// @Failure 500 {object} map[string]string +// @Router /api/playershotchart [get] func GetPlayerShotChart(db *gorm.DB) fiber.Handler { return func(c *fiber.Ctx) error { var shots []models.PlayerShotChart query := db.Model(&models.PlayerShotChart{}) + // --- Filtering Logic (unchanged) --- if pid := c.Query("playerId"); pid != "" { query = query.Where("player_id = ?", pid) } - if s := c.QueryInt("season", 0); s != 0 { + if s := c.QueryInt("season"); s != 0 { query = query.Where("season = ?", s) } + if date := c.Query("date"); date != "" { + query = query.Where("date = ?", date) + } + if qtr := c.Query("qtr"); qtr != "" { + query = query.Where("qtr = ?", qtr) + } + if c.Query("result") != "" { + query = query.Where("result = ?", c.QueryBool("result")) + } + if shotType := c.Query("shot_type"); shotType != "" { + query = query.Where("shot_type = ?", shotType) + } + if opponent := c.Query("opponent"); opponent != "" { + query = query.Where("opponent = ?", opponent) + } + + // --- Pagination Logic --- + // Set a fixed limit of 50 results per page. + limit := 50 + + // Get the page number from the query, defaulting to 1. + page := c.QueryInt("page", 1) + + // Calculate the offset based on the page number and limit. + offset := (page - 1) * limit + + // Apply Limit and Offset to the GORM query. + query = query.Limit(limit).Offset(offset) + if err := query.Find(&shots).Error; err != nil { - return c.Status(500).JSON(fiber.Map{"error": err.Error()}) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(shots) } diff --git a/docs/docs.go b/docs/docs.go index 40079cd..dde91ee 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -101,6 +101,91 @@ const docTemplate = `{ } } }, + "/api/playershotchart": { + "get": { + "description": "Returns a paginated list of shot-chart points, optionally filtered by various parameters.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "PlayerShotChart" + ], + "summary": "Get shot-chart data", + "parameters": [ + { + "type": "integer", + "description": "Page number for pagination (defaults to 1)", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "Player ID (e.g., hardeja01)", + "name": "playerId", + "in": "query" + }, + { + "type": "integer", + "description": "Season (e.g., 2023)", + "name": "season", + "in": "query" + }, + { + "type": "string", + "description": "Game date (e.g., Oct 17, 2018)", + "name": "date", + "in": "query" + }, + { + "type": "string", + "description": "Quarter (e.g., 1st Qtr)", + "name": "qtr", + "in": "query" + }, + { + "type": "boolean", + "description": "Shot result (true for made, false for missed)", + "name": "result", + "in": "query" + }, + { + "type": "string", + "description": "Shot type (e.g., 2-pointer)", + "name": "shot_type", + "in": "query" + }, + { + "type": "string", + "description": "Opponent team (e.g., NOP)", + "name": "opponent", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.PlayerShotChart" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, "/api/playertotals": { "get": { "description": "Filter and paginate player totals", diff --git a/docs/notes/index_tips.md b/docs/notes/index_tips.md index ff93801..5895230 100644 --- a/docs/notes/index_tips.md +++ b/docs/notes/index_tips.md @@ -82,3 +82,15 @@ CREATE INDEX IF NOT EXISTS idx_total_stats_player_name_trgm ON public.player_tot With this type of index, queries using `ILIKE '%davis%'` become extremely fast. This is something to keep in mind as you add more features. For now, running the standard `CREATE INDEX` commands listed above will give you excellent, comprehensive performance for a wide variety of common queries and sorting operations. You've built a truly robust and high-performance API. + + +--- +## Player Shots + +```SQL +CREATE INDEX idx_player_season_filters ON public.player_shot_charts (player_id, season, "date", qtr, result, shot_type, opponent); + +CREATE INDEX idx_player_shot_charts_date ON public.player_shot_charts ("date"); +CREATE INDEX idx_player_shot_charts_opponent ON public.player_shot_charts (opponent); +CREATE INDEX idx_player_shot_charts_shot_type ON public.player_shot_charts (shot_type); +``` \ No newline at end of file diff --git a/docs/swagger.json b/docs/swagger.json index d019ace..7e0d4b1 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -97,6 +97,91 @@ } } }, + "/api/playershotchart": { + "get": { + "description": "Returns a paginated list of shot-chart points, optionally filtered by various parameters.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "PlayerShotChart" + ], + "summary": "Get shot-chart data", + "parameters": [ + { + "type": "integer", + "description": "Page number for pagination (defaults to 1)", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "Player ID (e.g., hardeja01)", + "name": "playerId", + "in": "query" + }, + { + "type": "integer", + "description": "Season (e.g., 2023)", + "name": "season", + "in": "query" + }, + { + "type": "string", + "description": "Game date (e.g., Oct 17, 2018)", + "name": "date", + "in": "query" + }, + { + "type": "string", + "description": "Quarter (e.g., 1st Qtr)", + "name": "qtr", + "in": "query" + }, + { + "type": "boolean", + "description": "Shot result (true for made, false for missed)", + "name": "result", + "in": "query" + }, + { + "type": "string", + "description": "Shot type (e.g., 2-pointer)", + "name": "shot_type", + "in": "query" + }, + { + "type": "string", + "description": "Opponent team (e.g., NOP)", + "name": "opponent", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.PlayerShotChart" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, "/api/playertotals": { "get": { "description": "Filter and paginate player totals", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 6b0a885..a953101 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -185,6 +185,63 @@ paths: summary: Get player advanced stats tags: - PlayerStats + /api/playershotchart: + get: + consumes: + - application/json + description: Returns a paginated list of shot-chart points, optionally filtered + by various parameters. + parameters: + - description: Page number for pagination (defaults to 1) + in: query + name: page + type: integer + - description: Player ID (e.g., hardeja01) + in: query + name: playerId + type: string + - description: Season (e.g., 2023) + in: query + name: season + type: integer + - description: Game date (e.g., Oct 17, 2018) + in: query + name: date + type: string + - description: Quarter (e.g., 1st Qtr) + in: query + name: qtr + type: string + - description: Shot result (true for made, false for missed) + in: query + name: result + type: boolean + - description: Shot type (e.g., 2-pointer) + in: query + name: shot_type + type: string + - description: Opponent team (e.g., NOP) + in: query + name: opponent + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.PlayerShotChart' + type: array + "500": + description: Internal Server Error + schema: + additionalProperties: + type: string + type: object + summary: Get shot-chart data + tags: + - PlayerShotChart /api/playertotals: get: consumes: