diff --git a/db/query/odds.sql b/db/query/odds.sql index 84e6382..a508511 100644 --- a/db/query/odds.sql +++ b/db/query/odds.sql @@ -75,17 +75,17 @@ SELECT FROM odds WHERE is_active = true AND source = 'b365api'; --- name: GetRawOddsByID :one +-- name: GetRawOddsByMarketID :many SELECT id, raw_odds, fetched_at FROM odds WHERE - raw_odds @> $1::jsonb AND + market_id = $1 AND is_active = true AND source = 'b365api' -LIMIT 1; +LIMIT $2 OFFSET $3; -- name: GetPrematchOddsByUpcomingID :many SELECT diff --git a/docs/docs.go b/docs/docs.go index 1c7970b..a9242b9 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -288,9 +288,9 @@ const docTemplate = `{ } } }, - "/prematch/odds/raw/{raw_odds_id}": { + "/prematch/odds/raw/{market_id}": { "get": { - "description": "Retrieve raw odds by raw odds ID", + "description": "Retrieve raw odds records using a Market ID", "consumes": [ "application/json" ], @@ -300,12 +300,12 @@ const docTemplate = `{ "tags": [ "prematch" ], - "summary": "Retrieve raw odds by ID", + "summary": "Retrieve raw odds by Market ID", "parameters": [ { "type": "string", - "description": "Raw Odds ID", - "name": "raw_odds_id", + "description": "Market ID", + "name": "market_id", "in": "path", "required": true } @@ -314,7 +314,10 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/domain.RawOddsByID" + "type": "array", + "items": { + "$ref": "#/definitions/domain.RawOddsByMarketID" + } } }, "400": { @@ -761,12 +764,9 @@ const docTemplate = `{ } } }, - "domain.RawOddsByID": { + "domain.RawOddsByMarketID": { "type": "object", "properties": { - "event_id": { - "type": "string" - }, "fetched_at": { "type": "string" }, diff --git a/docs/swagger.json b/docs/swagger.json index 118ca95..a9eb780 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -280,9 +280,9 @@ } } }, - "/prematch/odds/raw/{raw_odds_id}": { + "/prematch/odds/raw/{market_id}": { "get": { - "description": "Retrieve raw odds by raw odds ID", + "description": "Retrieve raw odds records using a Market ID", "consumes": [ "application/json" ], @@ -292,12 +292,12 @@ "tags": [ "prematch" ], - "summary": "Retrieve raw odds by ID", + "summary": "Retrieve raw odds by Market ID", "parameters": [ { "type": "string", - "description": "Raw Odds ID", - "name": "raw_odds_id", + "description": "Market ID", + "name": "market_id", "in": "path", "required": true } @@ -306,7 +306,10 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/domain.RawOddsByID" + "type": "array", + "items": { + "$ref": "#/definitions/domain.RawOddsByMarketID" + } } }, "400": { @@ -753,12 +756,9 @@ } } }, - "domain.RawOddsByID": { + "domain.RawOddsByMarketID": { "type": "object", "properties": { - "event_id": { - "type": "string" - }, "fetched_at": { "type": "string" }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index b458113..7587a4d 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -33,10 +33,8 @@ definitions: source: type: string type: object - domain.RawOddsByID: + domain.RawOddsByMarketID: properties: - event_id: - type: string fetched_at: type: string id: @@ -465,15 +463,15 @@ paths: summary: Retrieve prematch odds for an event tags: - prematch - /prematch/odds/raw/{raw_odds_id}: + /prematch/odds/raw/{market_id}: get: consumes: - application/json - description: Retrieve raw odds by raw odds ID + description: Retrieve raw odds records using a Market ID parameters: - - description: Raw Odds ID + - description: Market ID in: path - name: raw_odds_id + name: market_id required: true type: string produces: @@ -482,7 +480,9 @@ paths: "200": description: OK schema: - $ref: '#/definitions/domain.RawOddsByID' + items: + $ref: '#/definitions/domain.RawOddsByMarketID' + type: array "400": description: Bad Request schema: @@ -491,7 +491,7 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/response.APIResponse' - summary: Retrieve raw odds by ID + summary: Retrieve raw odds by Market ID tags: - prematch /prematch/odds/upcoming/{upcoming_id}: diff --git a/gen/db/odds.sql.go b/gen/db/odds.sql.go index 57865e6..2ced1d4 100644 --- a/gen/db/odds.sql.go +++ b/gen/db/odds.sql.go @@ -248,30 +248,49 @@ func (q *Queries) GetPrematchOddsByUpcomingID(ctx context.Context, arg GetPremat return items, nil } -const GetRawOddsByID = `-- name: GetRawOddsByID :one +const GetRawOddsByMarketID = `-- name: GetRawOddsByMarketID :many SELECT id, raw_odds, fetched_at FROM odds WHERE - raw_odds @> $1::jsonb AND + market_id = $1 AND is_active = true AND source = 'b365api' -LIMIT 1 +LIMIT $2 OFFSET $3 ` -type GetRawOddsByIDRow struct { +type GetRawOddsByMarketIDParams struct { + MarketID pgtype.Text + Limit int32 + Offset int32 +} + +type GetRawOddsByMarketIDRow struct { ID int32 RawOdds []byte FetchedAt pgtype.Timestamp } -func (q *Queries) GetRawOddsByID(ctx context.Context, dollar_1 []byte) (GetRawOddsByIDRow, error) { - row := q.db.QueryRow(ctx, GetRawOddsByID, dollar_1) - var i GetRawOddsByIDRow - err := row.Scan(&i.ID, &i.RawOdds, &i.FetchedAt) - return i, err +func (q *Queries) GetRawOddsByMarketID(ctx context.Context, arg GetRawOddsByMarketIDParams) ([]GetRawOddsByMarketIDRow, error) { + rows, err := q.db.Query(ctx, GetRawOddsByMarketID, arg.MarketID, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetRawOddsByMarketIDRow + for rows.Next() { + var i GetRawOddsByMarketIDRow + if err := rows.Scan(&i.ID, &i.RawOdds, &i.FetchedAt); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil } const InsertNonLiveOdd = `-- name: InsertNonLiveOdd :exec diff --git a/internal/domain/odds.go b/internal/domain/odds.go index df2de7e..9992490 100644 --- a/internal/domain/odds.go +++ b/internal/domain/odds.go @@ -38,9 +38,8 @@ type Odd struct { Source string `json:"source"` IsActive bool `json:"is_active"` } -type RawOddsByID struct { - ID int64 `json:"id"` - EventID string `json:"event_id"` - RawOdds []RawMessage `json:"raw_odds"` - FetchedAt time.Time `json:"fetched_at"` +type RawOddsByMarketID struct { + ID int64 `json:"id"` + RawOdds []RawMessage `json:"raw_odds"` + FetchedAt time.Time `json:"fetched_at"` } \ No newline at end of file diff --git a/internal/repository/odds.go b/internal/repository/odds.go index a8573a3..bb41387 100644 --- a/internal/repository/odds.go +++ b/internal/repository/odds.go @@ -1,15 +1,16 @@ package repository import ( - "context" - "encoding/json" - "os" - "strconv" - "time" + "context" + "encoding/json" + "fmt" + "os" + "strconv" + "time" - dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" - "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" - "github.com/jackc/pgx/v5/pgtype" + dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" + "github.com/jackc/pgx/v5/pgtype" ) func (s *Store) SaveNonLiveMarket(ctx context.Context, m domain.Market) error { @@ -175,21 +176,31 @@ func (s *Store) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) { return domainOdds, nil } -func (s *Store) GetRawOddsByID(ctx context.Context, rawOddsID string) (domain.RawOddsByID, error) { - jsonFilter := `[{"id":"` + rawOddsID + `"}]` - - odd, err := s.queries.GetRawOddsByID(ctx, []byte(jsonFilter)) - if err != nil { - return domain.RawOddsByID{}, err +func (s *Store) GetRawOddsByMarketID(ctx context.Context, rawOddsID string) (domain.RawOddsByMarketID, error) { + params := dbgen.GetRawOddsByMarketIDParams{ + MarketID: pgtype.Text{String: rawOddsID, Valid: true}, + Limit: 1, + Offset: 0, } + rows, err := s.queries.GetRawOddsByMarketID(ctx, params) + if err != nil { + return domain.RawOddsByMarketID{}, err + } + + if len(rows) == 0 { + return domain.RawOddsByMarketID{}, fmt.Errorf("no raw odds found for market_id: %s", rawOddsID) + } + + row := rows[0] + var rawOdds []json.RawMessage - if err := json.Unmarshal(odd.RawOdds, &rawOdds); err != nil { - return domain.RawOddsByID{}, err + if err := json.Unmarshal(row.RawOdds, &rawOdds); err != nil { + return domain.RawOddsByMarketID{}, err } - return domain.RawOddsByID{ - ID: int64(odd.ID), + return domain.RawOddsByMarketID{ + ID: int64(row.ID), RawOdds: func() []domain.RawMessage { converted := make([]domain.RawMessage, len(rawOdds)) for i, r := range rawOdds { @@ -197,19 +208,17 @@ func (s *Store) GetRawOddsByID(ctx context.Context, rawOddsID string) (domain.Ra } return converted }(), - FetchedAt: odd.FetchedAt.Time, + FetchedAt: row.FetchedAt.Time, }, nil } func (s *Store) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset int32) ([]domain.Odd, error) { - // Prepare query parameters params := dbgen.GetPrematchOddsByUpcomingIDParams{ ID: upcomingID, Limit: limit, Offset: offset, } - // Execute the query odds, err := s.queries.GetPrematchOddsByUpcomingID(ctx, params) if err != nil { return nil, err diff --git a/internal/services/odds/port.go b/internal/services/odds/port.go index 8805a66..2472e99 100644 --- a/internal/services/odds/port.go +++ b/internal/services/odds/port.go @@ -10,7 +10,7 @@ type Service interface { FetchNonLiveOdds(ctx context.Context) error GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) - GetRawOddsByID(ctx context.Context, rawOddsID string) ([]domain.RawOddsByID, error) + GetRawOddsByMarketID(ctx context.Context, marketID string) ([]domain.RawOddsByMarketID, error) } diff --git a/internal/services/odds/service.go b/internal/services/odds/service.go index 9b31a94..d8bce34 100644 --- a/internal/services/odds/service.go +++ b/internal/services/odds/service.go @@ -122,13 +122,15 @@ func (s *ServiceImpl) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, err return s.store.GetALLPrematchOdds(ctx) } -func (s *ServiceImpl) GetRawOddsByID(ctx context.Context, rawOddsID string) ([]domain.RawOddsByID, error) { - rawOdds, err := s.store.GetRawOddsByID(ctx, rawOddsID) +func (s *ServiceImpl) GetRawOddsByMarketID(ctx context.Context, marketID string) ([]domain.RawOddsByMarketID, error) { + rows, err := s.store.GetRawOddsByMarketID(ctx, marketID) if err != nil { return nil, err } - return []domain.RawOddsByID{rawOdds}, nil + + return []domain.RawOddsByMarketID{rows}, nil } + func (s *ServiceImpl) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset int32) ([]domain.Odd, error) { return s.store.GetPrematchOddsByUpcomingID(ctx, upcomingID, limit, offset) } diff --git a/internal/web_server/handlers/prematch.go b/internal/web_server/handlers/prematch.go index 17e4de4..ea1ac59 100644 --- a/internal/web_server/handlers/prematch.go +++ b/internal/web_server/handlers/prematch.go @@ -55,26 +55,27 @@ func GetALLPrematchOdds(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fibe return response.WriteJSON(c, fiber.StatusOK, "All prematch odds retrieved successfully", odds, nil) } } -// GetRawOddsByID -// @Summary Retrieve raw odds by ID -// @Description Retrieve raw odds by raw odds ID +// GetRawOddsByMarketID +// @Summary Retrieve raw odds by Market ID +// @Description Retrieve raw odds records using a Market ID // @Tags prematch // @Accept json // @Produce json -// @Param raw_odds_id path string true "Raw Odds ID" -// @Success 200 {object} domain.RawOddsByID +// @Param market_id path string true "Market ID" +// @Success 200 {array} domain.RawOddsByMarketID // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /prematch/odds/raw/{raw_odds_id} [get] -func GetRawOddsByID(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fiber.Handler { +// @Router /prematch/odds/raw/{market_id} [get] +func GetRawOddsByMarketID(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fiber.Handler { return func(c *fiber.Ctx) error { - rawOddsID := c.Params("raw_odds_id") - if rawOddsID == "" { - return response.WriteJSON(c, fiber.StatusBadRequest, "Missing raw_odds_id", nil, nil) + marketID := c.Params("market_id") + if marketID == "" { + return response.WriteJSON(c, fiber.StatusBadRequest, "Missing market_id", nil, nil) } - rawOdds, err := prematchSvc.GetRawOddsByID(c.Context(), rawOddsID) + rawOdds, err := prematchSvc.GetRawOddsByMarketID(c.Context(), marketID) if err != nil { + logger.Error("failed to fetch raw odds", "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve raw odds", nil, nil) } diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index f18aa50..1e8a6e5 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -29,7 +29,7 @@ func (a *App) initAppRoutes() { a.fiber.Get("/prematch/odds/:event_id", handlers.GetPrematchOdds(a.logger, a.prematchSvc)) a.fiber.Get("/prematch/odds", handlers.GetALLPrematchOdds(a.logger, a.prematchSvc)) - a.fiber.Get("/prematch/odds/raw/:raw_odds_id", handlers.GetRawOddsByID(a.logger, a.prematchSvc)) + a.fiber.Get("/prematch/odds/raw/:market_id", handlers.GetRawOddsByMarketID(a.logger, a.prematchSvc)) a.fiber.Get("/prematch/events/:id", handlers.GetUpcomingEventByID(a.logger, a.eventSvc)) a.fiber.Get("/prematch/events", handlers.GetAllUpcomingEvents(a.logger, a.eventSvc))