289 lines
8.0 KiB
Go
289 lines
8.0 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
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 {
|
|
if len(m.Odds) == 0 {
|
|
return nil
|
|
}
|
|
|
|
for _, raw := range m.Odds {
|
|
var item map[string]interface{}
|
|
if err := json.Unmarshal(raw, &item); err != nil {
|
|
continue
|
|
}
|
|
|
|
name := getString(item["name"])
|
|
handicap := getString(item["handicap"])
|
|
oddsVal := getFloat(item["odds"])
|
|
|
|
rawOddsBytes, _ := json.Marshal(m.Odds)
|
|
|
|
params := dbgen.InsertNonLiveOddParams{
|
|
EventID: pgtype.Text{String: m.EventID, Valid: m.EventID != ""},
|
|
Fi: pgtype.Text{String: m.FI, Valid: m.FI != ""},
|
|
MarketType: m.MarketType,
|
|
MarketName: pgtype.Text{String: m.MarketName, Valid: m.MarketName != ""},
|
|
MarketCategory: pgtype.Text{String: m.MarketCategory, Valid: m.MarketCategory != ""},
|
|
MarketID: pgtype.Text{String: m.MarketID, Valid: m.MarketID != ""},
|
|
Name: pgtype.Text{String: name, Valid: name != ""},
|
|
Handicap: pgtype.Text{String: handicap, Valid: handicap != ""},
|
|
OddsValue: pgtype.Float8{Float64: oddsVal, Valid: oddsVal != 0},
|
|
Section: m.MarketCategory,
|
|
Category: pgtype.Text{Valid: false},
|
|
RawOdds: rawOddsBytes,
|
|
IsActive: pgtype.Bool{Bool: true, Valid: true},
|
|
Source: pgtype.Text{String: "b365api", Valid: true},
|
|
FetchedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
|
|
}
|
|
|
|
err := s.queries.InsertNonLiveOdd(ctx, params)
|
|
if err != nil {
|
|
_ = writeFailedMarketLog(m, err)
|
|
continue
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeFailedMarketLog(m domain.Market, err error) error {
|
|
logDir := "logs"
|
|
logFile := logDir + "/failed_markets.log"
|
|
|
|
if mkErr := os.MkdirAll(logDir, 0755); mkErr != nil {
|
|
return mkErr
|
|
}
|
|
|
|
f, fileErr := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
if fileErr != nil {
|
|
return fileErr
|
|
}
|
|
defer f.Close()
|
|
|
|
entry := struct {
|
|
Time string `json:"time"`
|
|
Error string `json:"error"`
|
|
Record domain.Market `json:"record"`
|
|
}{
|
|
Time: time.Now().Format(time.RFC3339),
|
|
Error: err.Error(),
|
|
Record: m,
|
|
}
|
|
|
|
jsonData, _ := json.MarshalIndent(entry, "", " ")
|
|
_, writeErr := f.WriteString(string(jsonData) + "\n\n")
|
|
return writeErr
|
|
}
|
|
|
|
func getString(v interface{}) string {
|
|
if s, ok := v.(string); ok {
|
|
return s
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func getFloat(v interface{}) float64 {
|
|
if s, ok := v.(string); ok {
|
|
f, err := strconv.ParseFloat(s, 64)
|
|
if err == nil {
|
|
return f
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (s *Store) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
|
|
odds, err := s.queries.GetPrematchOdds(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
domainOdds := make([]domain.Odd, len(odds))
|
|
for i, odd := range odds {
|
|
domainOdds[i] = domain.Odd{
|
|
EventID: odd.EventID.String,
|
|
Fi: odd.Fi.String,
|
|
MarketType: odd.MarketType,
|
|
MarketName: odd.MarketName.String,
|
|
MarketCategory: odd.MarketCategory.String,
|
|
MarketID: odd.MarketID.String,
|
|
Name: odd.Name.String,
|
|
Handicap: odd.Handicap.String,
|
|
OddsValue: odd.OddsValue.Float64,
|
|
Section: odd.Section,
|
|
Category: odd.Category.String,
|
|
RawOdds: func() []domain.RawMessage {
|
|
var rawOdds []domain.RawMessage
|
|
if err := json.Unmarshal(odd.RawOdds, &rawOdds); err != nil {
|
|
rawOdds = nil
|
|
}
|
|
return rawOdds
|
|
}(),
|
|
FetchedAt: odd.FetchedAt.Time,
|
|
Source: odd.Source.String,
|
|
IsActive: odd.IsActive.Bool,
|
|
}
|
|
}
|
|
|
|
return domainOdds, nil
|
|
}
|
|
|
|
func (s *Store) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) {
|
|
rows, err := s.queries.GetALLPrematchOdds(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
domainOdds := make([]domain.Odd, len(rows))
|
|
for i, row := range rows {
|
|
domainOdds[i] = domain.Odd{
|
|
// ID: int64(row.ID),
|
|
EventID: row.EventID.String,
|
|
Fi: row.Fi.String,
|
|
MarketType: row.MarketType,
|
|
MarketName: row.MarketName.String,
|
|
MarketCategory: row.MarketCategory.String,
|
|
MarketID: row.MarketID.String,
|
|
Name: row.Name.String,
|
|
Handicap: row.Handicap.String,
|
|
OddsValue: row.OddsValue.Float64,
|
|
Section: row.Section,
|
|
Category: row.Category.String,
|
|
RawOdds: func() []domain.RawMessage {
|
|
var rawOdds []domain.RawMessage
|
|
if err := json.Unmarshal(row.RawOdds, &rawOdds); err != nil {
|
|
rawOdds = nil
|
|
}
|
|
return rawOdds
|
|
}(),
|
|
FetchedAt: row.FetchedAt.Time,
|
|
Source: row.Source.String,
|
|
IsActive: row.IsActive.Bool,
|
|
}
|
|
}
|
|
|
|
return domainOdds, nil
|
|
}
|
|
|
|
func (s *Store) GetRawOddsByMarketID(ctx context.Context, rawOddsID string, upcomingID string) (domain.RawOddsByMarketID, error) {
|
|
params := dbgen.GetRawOddsByMarketIDParams{
|
|
MarketID: pgtype.Text{String: rawOddsID, Valid: true},
|
|
Fi: pgtype.Text{String: upcomingID, Valid: true},
|
|
}
|
|
|
|
odds, err := s.queries.GetRawOddsByMarketID(ctx, params)
|
|
if err != nil {
|
|
return domain.RawOddsByMarketID{}, err
|
|
}
|
|
|
|
var rawOdds []json.RawMessage
|
|
if err := json.Unmarshal(odds.RawOdds, &rawOdds); err != nil {
|
|
return domain.RawOddsByMarketID{}, err
|
|
}
|
|
|
|
return domain.RawOddsByMarketID{
|
|
ID: int64(odds.ID),
|
|
MarketName: odds.MarketName.String,
|
|
Handicap: odds.Handicap.String,
|
|
RawOdds: func() []domain.RawMessage {
|
|
converted := make([]domain.RawMessage, len(rawOdds))
|
|
for i, r := range rawOdds {
|
|
converted[i] = domain.RawMessage(r)
|
|
}
|
|
return converted
|
|
}(),
|
|
FetchedAt: odds.FetchedAt.Time,
|
|
}, nil
|
|
}
|
|
func (s *Store) GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit domain.ValidInt64, offset domain.ValidInt64) ([]domain.Odd, error) {
|
|
odds, err := s.queries.GetPaginatedPrematchOddsByUpcomingID(ctx, dbgen.GetPaginatedPrematchOddsByUpcomingIDParams{
|
|
ID: upcomingID,
|
|
Limit: pgtype.Int4{
|
|
Int32: int32(limit.Value),
|
|
Valid: limit.Valid,
|
|
},
|
|
Offset: pgtype.Int4{
|
|
Int32: int32(offset.Value),
|
|
Valid: offset.Valid,
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Map the results to domain.Odd
|
|
domainOdds := make([]domain.Odd, len(odds))
|
|
for i, odd := range odds {
|
|
var rawOdds []domain.RawMessage
|
|
if err := json.Unmarshal(odd.RawOdds, &rawOdds); err != nil {
|
|
rawOdds = nil
|
|
}
|
|
|
|
domainOdds[i] = domain.Odd{
|
|
EventID: odd.EventID.String,
|
|
Fi: odd.Fi.String,
|
|
MarketType: odd.MarketType,
|
|
MarketName: odd.MarketName.String,
|
|
MarketCategory: odd.MarketCategory.String,
|
|
MarketID: odd.MarketID.String,
|
|
Name: odd.Name.String,
|
|
Handicap: odd.Handicap.String,
|
|
OddsValue: odd.OddsValue.Float64,
|
|
Section: odd.Section,
|
|
Category: odd.Category.String,
|
|
RawOdds: rawOdds,
|
|
FetchedAt: odd.FetchedAt.Time,
|
|
Source: odd.Source.String,
|
|
IsActive: odd.IsActive.Bool,
|
|
}
|
|
}
|
|
|
|
return domainOdds, nil
|
|
}
|
|
|
|
func (s *Store) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string) ([]domain.Odd, error) {
|
|
|
|
odds, err := s.queries.GetPrematchOddsByUpcomingID(ctx, upcomingID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Map the results to domain.Odd
|
|
domainOdds := make([]domain.Odd, len(odds))
|
|
for i, odd := range odds {
|
|
var rawOdds []domain.RawMessage
|
|
if err := json.Unmarshal(odd.RawOdds, &rawOdds); err != nil {
|
|
rawOdds = nil
|
|
}
|
|
|
|
domainOdds[i] = domain.Odd{
|
|
EventID: odd.EventID.String,
|
|
Fi: odd.Fi.String,
|
|
MarketType: odd.MarketType,
|
|
MarketName: odd.MarketName.String,
|
|
MarketCategory: odd.MarketCategory.String,
|
|
MarketID: odd.MarketID.String,
|
|
Name: odd.Name.String,
|
|
Handicap: odd.Handicap.String,
|
|
OddsValue: odd.OddsValue.Float64,
|
|
Section: odd.Section,
|
|
Category: odd.Category.String,
|
|
RawOdds: rawOdds,
|
|
FetchedAt: odd.FetchedAt.Time,
|
|
Source: odd.Source.String,
|
|
IsActive: odd.IsActive.Bool,
|
|
}
|
|
}
|
|
|
|
return domainOdds, nil
|
|
}
|