resolve conflict
This commit is contained in:
commit
d3506fd03a
|
|
@ -76,3 +76,4 @@ DROP TABLE IF EXISTS refresh_tokens;
|
|||
DROP TABLE IF EXISTS otps;
|
||||
DROP TABLE IF EXISTS odds;
|
||||
DROP TABLE IF EXISTS events;
|
||||
DROP TABLE IF EXISTS leagues;
|
||||
|
|
@ -184,15 +184,15 @@ CREATE TABLE IF NOT EXISTS branch_cashiers (
|
|||
);
|
||||
CREATE TABLE events (
|
||||
id TEXT PRIMARY KEY,
|
||||
sport_id TEXT,
|
||||
sport_id INT,
|
||||
match_name TEXT,
|
||||
home_team TEXT,
|
||||
away_team TEXT,
|
||||
home_team_id TEXT,
|
||||
away_team_id TEXT,
|
||||
home_team_id INT,
|
||||
away_team_id INT,
|
||||
home_kit_image TEXT,
|
||||
away_kit_image TEXT,
|
||||
league_id TEXT,
|
||||
league_id INT,
|
||||
league_name TEXT,
|
||||
league_cc TEXT,
|
||||
start_time TIMESTAMP,
|
||||
|
|
@ -233,6 +233,13 @@ CREATE TABLE companies (
|
|||
admin_id BIGINT NOT NULL,
|
||||
wallet_id BIGINT NOT NULL
|
||||
);
|
||||
CREATE TABLE leagues (
|
||||
id BIGINT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
country_code TEXT,
|
||||
bet365_id INT,
|
||||
is_active BOOLEAN DEFAULT true
|
||||
);
|
||||
-- Views
|
||||
CREATE VIEW companies_details AS
|
||||
SELECT companies.*,
|
||||
|
|
|
|||
37
db/query/leagues.sql
Normal file
37
db/query/leagues.sql
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
-- name: InsertLeague :exec
|
||||
INSERT INTO leagues (
|
||||
id,
|
||||
name,
|
||||
country_code,
|
||||
bet365_id,
|
||||
is_active
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5
|
||||
)
|
||||
ON CONFLICT (id) DO UPDATE
|
||||
SET name = EXCLUDED.name,
|
||||
country_code = EXCLUDED.country_code,
|
||||
bet365_id = EXCLUDED.bet365_id,
|
||||
is_active = EXCLUDED.is_active;
|
||||
-- name: GetSupportedLeagues :many
|
||||
SELECT id,
|
||||
name,
|
||||
country_code,
|
||||
bet365_id,
|
||||
is_active
|
||||
FROM leagues
|
||||
WHERE is_active = true;
|
||||
-- name: CheckLeagueSupport :one
|
||||
SELECT EXISTS(
|
||||
SELECT 1
|
||||
FROM leagues
|
||||
WHERE id = $1
|
||||
AND is_active = true
|
||||
);
|
||||
-- name: UpdateLeague :exec
|
||||
UPDATE leagues
|
||||
SET name = $1,
|
||||
country_code = $2,
|
||||
bet365_id = $3,
|
||||
is_active = $4
|
||||
WHERE id = $5;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: cashier.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -47,15 +47,15 @@ ORDER BY start_time ASC
|
|||
|
||||
type GetAllUpcomingEventsRow struct {
|
||||
ID string `json:"id"`
|
||||
SportID pgtype.Text `json:"sport_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
MatchName pgtype.Text `json:"match_name"`
|
||||
HomeTeam pgtype.Text `json:"home_team"`
|
||||
AwayTeam pgtype.Text `json:"away_team"`
|
||||
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||
HomeTeamID pgtype.Int4 `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Int4 `json:"away_team_id"`
|
||||
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||
LeagueID pgtype.Text `json:"league_id"`
|
||||
LeagueID pgtype.Int4 `json:"league_id"`
|
||||
LeagueName pgtype.Text `json:"league_name"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
|
|
@ -128,15 +128,15 @@ ORDER BY start_time ASC
|
|||
|
||||
type GetExpiredUpcomingEventsRow struct {
|
||||
ID string `json:"id"`
|
||||
SportID pgtype.Text `json:"sport_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
MatchName pgtype.Text `json:"match_name"`
|
||||
HomeTeam pgtype.Text `json:"home_team"`
|
||||
AwayTeam pgtype.Text `json:"away_team"`
|
||||
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||
HomeTeamID pgtype.Int4 `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Int4 `json:"away_team_id"`
|
||||
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||
LeagueID pgtype.Text `json:"league_id"`
|
||||
LeagueID pgtype.Int4 `json:"league_id"`
|
||||
LeagueName pgtype.Text `json:"league_name"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
|
|
@ -226,8 +226,8 @@ LIMIT $6 OFFSET $5
|
|||
`
|
||||
|
||||
type GetPaginatedUpcomingEventsParams struct {
|
||||
LeagueID pgtype.Text `json:"league_id"`
|
||||
SportID pgtype.Text `json:"sport_id"`
|
||||
LeagueID pgtype.Int4 `json:"league_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
LastStartTime pgtype.Timestamp `json:"last_start_time"`
|
||||
FirstStartTime pgtype.Timestamp `json:"first_start_time"`
|
||||
Offset pgtype.Int4 `json:"offset"`
|
||||
|
|
@ -236,15 +236,15 @@ type GetPaginatedUpcomingEventsParams struct {
|
|||
|
||||
type GetPaginatedUpcomingEventsRow struct {
|
||||
ID string `json:"id"`
|
||||
SportID pgtype.Text `json:"sport_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
MatchName pgtype.Text `json:"match_name"`
|
||||
HomeTeam pgtype.Text `json:"home_team"`
|
||||
AwayTeam pgtype.Text `json:"away_team"`
|
||||
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||
HomeTeamID pgtype.Int4 `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Int4 `json:"away_team_id"`
|
||||
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||
LeagueID pgtype.Text `json:"league_id"`
|
||||
LeagueID pgtype.Int4 `json:"league_id"`
|
||||
LeagueName pgtype.Text `json:"league_name"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
|
|
@ -323,8 +323,8 @@ WHERE is_live = false
|
|||
`
|
||||
|
||||
type GetTotalEventsParams struct {
|
||||
LeagueID pgtype.Text `json:"league_id"`
|
||||
SportID pgtype.Text `json:"sport_id"`
|
||||
LeagueID pgtype.Int4 `json:"league_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
LastStartTime pgtype.Timestamp `json:"last_start_time"`
|
||||
FirstStartTime pgtype.Timestamp `json:"first_start_time"`
|
||||
}
|
||||
|
|
@ -368,15 +368,15 @@ LIMIT 1
|
|||
|
||||
type GetUpcomingByIDRow struct {
|
||||
ID string `json:"id"`
|
||||
SportID pgtype.Text `json:"sport_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
MatchName pgtype.Text `json:"match_name"`
|
||||
HomeTeam pgtype.Text `json:"home_team"`
|
||||
AwayTeam pgtype.Text `json:"away_team"`
|
||||
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||
HomeTeamID pgtype.Int4 `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Int4 `json:"away_team_id"`
|
||||
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||
LeagueID pgtype.Text `json:"league_id"`
|
||||
LeagueID pgtype.Int4 `json:"league_id"`
|
||||
LeagueName pgtype.Text `json:"league_name"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
|
|
@ -484,15 +484,15 @@ SET sport_id = EXCLUDED.sport_id,
|
|||
|
||||
type InsertEventParams struct {
|
||||
ID string `json:"id"`
|
||||
SportID pgtype.Text `json:"sport_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
MatchName pgtype.Text `json:"match_name"`
|
||||
HomeTeam pgtype.Text `json:"home_team"`
|
||||
AwayTeam pgtype.Text `json:"away_team"`
|
||||
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||
HomeTeamID pgtype.Int4 `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Int4 `json:"away_team_id"`
|
||||
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||
LeagueID pgtype.Text `json:"league_id"`
|
||||
LeagueID pgtype.Int4 `json:"league_id"`
|
||||
LeagueName pgtype.Text `json:"league_name"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
|
|
@ -591,15 +591,15 @@ SET sport_id = EXCLUDED.sport_id,
|
|||
|
||||
type InsertUpcomingEventParams struct {
|
||||
ID string `json:"id"`
|
||||
SportID pgtype.Text `json:"sport_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
MatchName pgtype.Text `json:"match_name"`
|
||||
HomeTeam pgtype.Text `json:"home_team"`
|
||||
AwayTeam pgtype.Text `json:"away_team"`
|
||||
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||
HomeTeamID pgtype.Int4 `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Int4 `json:"away_team_id"`
|
||||
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||
LeagueID pgtype.Text `json:"league_id"`
|
||||
LeagueID pgtype.Int4 `json:"league_id"`
|
||||
LeagueName pgtype.Text `json:"league_name"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
|
|
|
|||
128
gen/db/leagues.sql.go
Normal file
128
gen/db/leagues.sql.go
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.29.0
|
||||
// source: leagues.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const CheckLeagueSupport = `-- name: CheckLeagueSupport :one
|
||||
SELECT EXISTS(
|
||||
SELECT 1
|
||||
FROM leagues
|
||||
WHERE id = $1
|
||||
AND is_active = true
|
||||
)
|
||||
`
|
||||
|
||||
func (q *Queries) CheckLeagueSupport(ctx context.Context, id int64) (bool, error) {
|
||||
row := q.db.QueryRow(ctx, CheckLeagueSupport, id)
|
||||
var exists bool
|
||||
err := row.Scan(&exists)
|
||||
return exists, err
|
||||
}
|
||||
|
||||
const GetSupportedLeagues = `-- name: GetSupportedLeagues :many
|
||||
SELECT id,
|
||||
name,
|
||||
country_code,
|
||||
bet365_id,
|
||||
is_active
|
||||
FROM leagues
|
||||
WHERE is_active = true
|
||||
`
|
||||
|
||||
func (q *Queries) GetSupportedLeagues(ctx context.Context) ([]League, error) {
|
||||
rows, err := q.db.Query(ctx, GetSupportedLeagues)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []League
|
||||
for rows.Next() {
|
||||
var i League
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.CountryCode,
|
||||
&i.Bet365ID,
|
||||
&i.IsActive,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const InsertLeague = `-- name: InsertLeague :exec
|
||||
INSERT INTO leagues (
|
||||
id,
|
||||
name,
|
||||
country_code,
|
||||
bet365_id,
|
||||
is_active
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5
|
||||
)
|
||||
ON CONFLICT (id) DO UPDATE
|
||||
SET name = EXCLUDED.name,
|
||||
country_code = EXCLUDED.country_code,
|
||||
bet365_id = EXCLUDED.bet365_id,
|
||||
is_active = EXCLUDED.is_active
|
||||
`
|
||||
|
||||
type InsertLeagueParams struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CountryCode pgtype.Text `json:"country_code"`
|
||||
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||
IsActive pgtype.Bool `json:"is_active"`
|
||||
}
|
||||
|
||||
func (q *Queries) InsertLeague(ctx context.Context, arg InsertLeagueParams) error {
|
||||
_, err := q.db.Exec(ctx, InsertLeague,
|
||||
arg.ID,
|
||||
arg.Name,
|
||||
arg.CountryCode,
|
||||
arg.Bet365ID,
|
||||
arg.IsActive,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const UpdateLeague = `-- name: UpdateLeague :exec
|
||||
UPDATE leagues
|
||||
SET name = $1,
|
||||
country_code = $2,
|
||||
bet365_id = $3,
|
||||
is_active = $4
|
||||
WHERE id = $5
|
||||
`
|
||||
|
||||
type UpdateLeagueParams struct {
|
||||
Name string `json:"name"`
|
||||
CountryCode pgtype.Text `json:"country_code"`
|
||||
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||
IsActive pgtype.Bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateLeague(ctx context.Context, arg UpdateLeagueParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateLeague,
|
||||
arg.Name,
|
||||
arg.CountryCode,
|
||||
arg.Bet365ID,
|
||||
arg.IsActive,
|
||||
arg.ID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
@ -178,15 +178,15 @@ type CustomerWallet struct {
|
|||
|
||||
type Event struct {
|
||||
ID string `json:"id"`
|
||||
SportID pgtype.Text `json:"sport_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
MatchName pgtype.Text `json:"match_name"`
|
||||
HomeTeam pgtype.Text `json:"home_team"`
|
||||
AwayTeam pgtype.Text `json:"away_team"`
|
||||
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||
HomeTeamID pgtype.Int4 `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Int4 `json:"away_team_id"`
|
||||
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||
LeagueID pgtype.Text `json:"league_id"`
|
||||
LeagueID pgtype.Int4 `json:"league_id"`
|
||||
LeagueName pgtype.Text `json:"league_name"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
|
|
@ -201,6 +201,14 @@ type Event struct {
|
|||
Source pgtype.Text `json:"source"`
|
||||
}
|
||||
|
||||
type League struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CountryCode pgtype.Text `json:"country_code"`
|
||||
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||
IsActive pgtype.Bool `json:"is_active"`
|
||||
}
|
||||
|
||||
type Notification struct {
|
||||
ID string `json:"id"`
|
||||
RecipientID int64 `json:"recipient_id"`
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ type ValidInt struct {
|
|||
Value int
|
||||
Valid bool
|
||||
}
|
||||
type ValidInt32 struct {
|
||||
Value int32
|
||||
Valid bool
|
||||
}
|
||||
|
||||
type ValidString struct {
|
||||
Value string
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ import "time"
|
|||
|
||||
type Event struct {
|
||||
ID string
|
||||
SportID string
|
||||
SportID int32
|
||||
MatchName string
|
||||
HomeTeam string
|
||||
AwayTeam string
|
||||
HomeTeamID string
|
||||
AwayTeamID string
|
||||
HomeTeamID int32
|
||||
AwayTeamID int32
|
||||
HomeKitImage string
|
||||
AwayKitImage string
|
||||
LeagueID string
|
||||
LeagueID int32
|
||||
LeagueName string
|
||||
LeagueCC string
|
||||
StartTime string
|
||||
|
|
@ -54,15 +54,15 @@ type BetResult struct {
|
|||
|
||||
type UpcomingEvent struct {
|
||||
ID string // Event ID
|
||||
SportID string // Sport ID
|
||||
SportID int32 // Sport ID
|
||||
MatchName string // Match or event name
|
||||
HomeTeam string // Home team name (if available)
|
||||
AwayTeam string // Away team name (can be empty/null)
|
||||
HomeTeamID string // Home team ID
|
||||
AwayTeamID string // Away team ID (can be empty/null)
|
||||
HomeTeamID int32 // Home team ID
|
||||
AwayTeamID int32 // Away team ID (can be empty/null)
|
||||
HomeKitImage string // Kit or image for home team (optional)
|
||||
AwayKitImage string // Kit or image for away team (optional)
|
||||
LeagueID string // League ID
|
||||
LeagueID int32 // League ID
|
||||
LeagueName string // League name
|
||||
LeagueCC string // League country code
|
||||
StartTime time.Time // Converted from "time" field in UNIX format
|
||||
|
|
|
|||
|
|
@ -1,66 +1,9 @@
|
|||
package domain
|
||||
|
||||
// TODO Will make this dynamic by moving into the database
|
||||
|
||||
var SupportedLeagues = []int64{
|
||||
// Football
|
||||
10041282, //Premier League
|
||||
10083364, //La Liga
|
||||
10041095, //German Bundesliga
|
||||
10041100, //Ligue 1
|
||||
10041809, //UEFA Champions League
|
||||
10041957, //UEFA Europa League
|
||||
10079560, //UEFA Conference League
|
||||
10047168, // US MLS
|
||||
10044469, // Ethiopian Premier League
|
||||
10050282, //UEFA Nations League
|
||||
10044685, //FIFA Club World Cup
|
||||
10082328, //Kings League World Cup
|
||||
10081269, //CONCACAF Champions Cup
|
||||
10040162, //Asia - World Cup Qualifying
|
||||
10067624, //South America - World Cup Qualifying
|
||||
10067913, // Europe - World Cup Qualifying
|
||||
10067624, // South America - World Cup Qualifying
|
||||
|
||||
10043156, //England FA Cup
|
||||
10042103, //France Cup
|
||||
10041088, //Premier League 2
|
||||
10084250, //Turkiye Super League
|
||||
10041187, //Kenya Super League
|
||||
10041315, //Italian Serie A
|
||||
10041391, //Netherlands Eredivisie
|
||||
10036538, //Spain Segunda
|
||||
10041058, //Denmark Superligaen
|
||||
10077480, //Women’s International
|
||||
10046936, // USA NPSL
|
||||
10085159, //Baller League UK
|
||||
10040601, //Argentina Cup
|
||||
10037440, //Brazil Serie A
|
||||
10043205, //Copa Sudamericana
|
||||
|
||||
10037327, //Austria Landesliga
|
||||
10082020, //USA USL League One Cup
|
||||
10037075, //International Match
|
||||
10046648, //Kenya Cup
|
||||
10040485, //Kenya Super League
|
||||
10041369, //Norway Eliteserien
|
||||
|
||||
// Basketball
|
||||
173998768, //NBA
|
||||
10041830, //NBA
|
||||
10049984, //WNBA
|
||||
10037165, //German Bundesliga
|
||||
10036608, //Italian Lega 1
|
||||
10040795, //EuroLeague
|
||||
10084178, //Kenya Premier League
|
||||
10043548, //International Women
|
||||
|
||||
// Ice Hockey
|
||||
10037477, //NHL
|
||||
10037447, //AHL
|
||||
10074238, // AIHL
|
||||
10069385, //IIHF World Championship
|
||||
|
||||
// Cricket
|
||||
|
||||
type League struct {
|
||||
ID int64
|
||||
Name string
|
||||
CountryCode string
|
||||
Bet365ID int32
|
||||
IsActive bool
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
@ -15,10 +14,11 @@ type Market struct {
|
|||
MarketName string
|
||||
MarketID string
|
||||
UpdatedAt time.Time
|
||||
Odds []json.RawMessage
|
||||
Odds []map[string]interface{}
|
||||
Name string
|
||||
Handicap string
|
||||
OddsVal float64
|
||||
Source string
|
||||
}
|
||||
|
||||
type Odd struct {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ type BaseResultResponse struct {
|
|||
Results []json.RawMessage `json:"results"`
|
||||
}
|
||||
|
||||
type League struct {
|
||||
type LeagueRes struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CC string `json:"cc"`
|
||||
|
|
@ -32,7 +32,7 @@ type FootballResultResponse struct {
|
|||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League League `json:"league"`
|
||||
League LeagueRes `json:"league"`
|
||||
Home Team `json:"home"`
|
||||
Away Team `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
|
|
@ -71,7 +71,7 @@ type BasketballResultResponse struct {
|
|||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League League `json:"league"`
|
||||
League LeagueRes `json:"league"`
|
||||
Home Team `json:"home"`
|
||||
Away Team `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
|
|
@ -118,7 +118,7 @@ type IceHockeyResultResponse struct {
|
|||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League League `json:"league"`
|
||||
League LeagueRes `json:"league"`
|
||||
Home Team `json:"home"`
|
||||
Away Team `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
|
|
|
|||
|
|
@ -21,15 +21,15 @@ func (s *Store) SaveEvent(ctx context.Context, e domain.Event) error {
|
|||
|
||||
return s.queries.InsertEvent(ctx, dbgen.InsertEventParams{
|
||||
ID: e.ID,
|
||||
SportID: pgtype.Text{String: e.SportID, Valid: true},
|
||||
SportID: pgtype.Int4{Int32: e.SportID, Valid: true},
|
||||
MatchName: pgtype.Text{String: e.MatchName, Valid: true},
|
||||
HomeTeam: pgtype.Text{String: e.HomeTeam, Valid: true},
|
||||
AwayTeam: pgtype.Text{String: e.AwayTeam, Valid: true},
|
||||
HomeTeamID: pgtype.Text{String: e.HomeTeamID, Valid: true},
|
||||
AwayTeamID: pgtype.Text{String: e.AwayTeamID, Valid: true},
|
||||
HomeTeamID: pgtype.Int4{Int32: e.HomeTeamID, Valid: true},
|
||||
AwayTeamID: pgtype.Int4{Int32: e.AwayTeamID, Valid: true},
|
||||
HomeKitImage: pgtype.Text{String: e.HomeKitImage, Valid: true},
|
||||
AwayKitImage: pgtype.Text{String: e.AwayKitImage, Valid: true},
|
||||
LeagueID: pgtype.Text{String: e.LeagueID, Valid: true},
|
||||
LeagueID: pgtype.Int4{Int32: e.LeagueID, Valid: true},
|
||||
LeagueName: pgtype.Text{String: e.LeagueName, Valid: true},
|
||||
LeagueCc: pgtype.Text{String: e.LeagueCC, Valid: true},
|
||||
StartTime: pgtype.Timestamp{Time: parsedTime, Valid: true},
|
||||
|
|
@ -46,15 +46,15 @@ func (s *Store) SaveEvent(ctx context.Context, e domain.Event) error {
|
|||
func (s *Store) SaveUpcomingEvent(ctx context.Context, e domain.UpcomingEvent) error {
|
||||
return s.queries.InsertUpcomingEvent(ctx, dbgen.InsertUpcomingEventParams{
|
||||
ID: e.ID,
|
||||
SportID: pgtype.Text{String: e.SportID, Valid: true},
|
||||
SportID: pgtype.Int4{Int32: e.SportID, Valid: true},
|
||||
MatchName: pgtype.Text{String: e.MatchName, Valid: true},
|
||||
HomeTeam: pgtype.Text{String: e.HomeTeam, Valid: true},
|
||||
AwayTeam: pgtype.Text{String: e.AwayTeam, Valid: true},
|
||||
HomeTeamID: pgtype.Text{String: e.HomeTeamID, Valid: true},
|
||||
AwayTeamID: pgtype.Text{String: e.AwayTeamID, Valid: true},
|
||||
HomeTeamID: pgtype.Int4{Int32: e.HomeTeamID, Valid: true},
|
||||
AwayTeamID: pgtype.Int4{Int32: e.AwayTeamID, Valid: true},
|
||||
HomeKitImage: pgtype.Text{String: e.HomeKitImage, Valid: true},
|
||||
AwayKitImage: pgtype.Text{String: e.AwayKitImage, Valid: true},
|
||||
LeagueID: pgtype.Text{String: e.LeagueID, Valid: true},
|
||||
LeagueID: pgtype.Int4{Int32: e.LeagueID, Valid: true},
|
||||
LeagueName: pgtype.Text{String: e.LeagueName, Valid: true},
|
||||
LeagueCc: pgtype.Text{String: e.LeagueCC, Valid: true},
|
||||
StartTime: pgtype.Timestamp{Time: e.StartTime, Valid: true},
|
||||
|
|
@ -75,15 +75,15 @@ func (s *Store) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEven
|
|||
for i, e := range events {
|
||||
upcomingEvents[i] = domain.UpcomingEvent{
|
||||
ID: e.ID,
|
||||
SportID: e.SportID.String,
|
||||
SportID: e.SportID.Int32,
|
||||
MatchName: e.MatchName.String,
|
||||
HomeTeam: e.HomeTeam.String,
|
||||
AwayTeam: e.AwayTeam.String,
|
||||
HomeTeamID: e.HomeTeamID.String,
|
||||
AwayTeamID: e.AwayTeamID.String,
|
||||
HomeTeamID: e.HomeTeamID.Int32,
|
||||
AwayTeamID: e.AwayTeamID.Int32,
|
||||
HomeKitImage: e.HomeKitImage.String,
|
||||
AwayKitImage: e.AwayKitImage.String,
|
||||
LeagueID: e.LeagueID.String,
|
||||
LeagueID: e.LeagueID.Int32,
|
||||
LeagueName: e.LeagueName.String,
|
||||
LeagueCC: e.LeagueCc.String,
|
||||
StartTime: e.StartTime.Time.UTC(),
|
||||
|
|
@ -103,15 +103,15 @@ func (s *Store) GetExpiredUpcomingEvents(ctx context.Context) ([]domain.Upcoming
|
|||
for i, e := range events {
|
||||
upcomingEvents[i] = domain.UpcomingEvent{
|
||||
ID: e.ID,
|
||||
SportID: e.SportID.String,
|
||||
SportID: e.SportID.Int32,
|
||||
MatchName: e.MatchName.String,
|
||||
HomeTeam: e.HomeTeam.String,
|
||||
AwayTeam: e.AwayTeam.String,
|
||||
HomeTeamID: e.HomeTeamID.String,
|
||||
AwayTeamID: e.AwayTeamID.String,
|
||||
HomeTeamID: e.HomeTeamID.Int32,
|
||||
AwayTeamID: e.AwayTeamID.Int32,
|
||||
HomeKitImage: e.HomeKitImage.String,
|
||||
AwayKitImage: e.AwayKitImage.String,
|
||||
LeagueID: e.LeagueID.String,
|
||||
LeagueID: e.LeagueID.Int32,
|
||||
LeagueName: e.LeagueName.String,
|
||||
LeagueCC: e.LeagueCc.String,
|
||||
StartTime: e.StartTime.Time.UTC(),
|
||||
|
|
@ -121,15 +121,15 @@ func (s *Store) GetExpiredUpcomingEvents(ctx context.Context) ([]domain.Upcoming
|
|||
return upcomingEvents, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, limit domain.ValidInt64, offset domain.ValidInt64, leagueID domain.ValidString, sportID domain.ValidString, firstStartTime domain.ValidTime, lastStartTime domain.ValidTime) ([]domain.UpcomingEvent, int64, error) {
|
||||
func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, limit domain.ValidInt64, offset domain.ValidInt64, leagueID domain.ValidInt32, sportID domain.ValidInt32, firstStartTime domain.ValidTime, lastStartTime domain.ValidTime) ([]domain.UpcomingEvent, int64, error) {
|
||||
|
||||
events, err := s.queries.GetPaginatedUpcomingEvents(ctx, dbgen.GetPaginatedUpcomingEventsParams{
|
||||
LeagueID: pgtype.Text{
|
||||
String: leagueID.Value,
|
||||
LeagueID: pgtype.Int4{
|
||||
Int32: leagueID.Value,
|
||||
Valid: leagueID.Valid,
|
||||
},
|
||||
SportID: pgtype.Text{
|
||||
String: sportID.Value,
|
||||
SportID: pgtype.Int4{
|
||||
Int32: sportID.Value,
|
||||
Valid: sportID.Valid,
|
||||
},
|
||||
Limit: pgtype.Int4{
|
||||
|
|
@ -157,15 +157,15 @@ func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, limit domain.Val
|
|||
for i, e := range events {
|
||||
upcomingEvents[i] = domain.UpcomingEvent{
|
||||
ID: e.ID,
|
||||
SportID: e.SportID.String,
|
||||
SportID: e.SportID.Int32,
|
||||
MatchName: e.MatchName.String,
|
||||
HomeTeam: e.HomeTeam.String,
|
||||
AwayTeam: e.AwayTeam.String,
|
||||
HomeTeamID: e.HomeTeamID.String,
|
||||
AwayTeamID: e.AwayTeamID.String,
|
||||
HomeTeamID: e.HomeTeamID.Int32,
|
||||
AwayTeamID: e.AwayTeamID.Int32,
|
||||
HomeKitImage: e.HomeKitImage.String,
|
||||
AwayKitImage: e.AwayKitImage.String,
|
||||
LeagueID: e.LeagueID.String,
|
||||
LeagueID: e.LeagueID.Int32,
|
||||
LeagueName: e.LeagueName.String,
|
||||
LeagueCC: e.LeagueCc.String,
|
||||
StartTime: e.StartTime.Time.UTC(),
|
||||
|
|
@ -173,12 +173,12 @@ func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, limit domain.Val
|
|||
}
|
||||
}
|
||||
totalCount, err := s.queries.GetTotalEvents(ctx, dbgen.GetTotalEventsParams{
|
||||
LeagueID: pgtype.Text{
|
||||
String: leagueID.Value,
|
||||
LeagueID: pgtype.Int4{
|
||||
Int32: leagueID.Value,
|
||||
Valid: leagueID.Valid,
|
||||
},
|
||||
SportID: pgtype.Text{
|
||||
String: sportID.Value,
|
||||
SportID: pgtype.Int4{
|
||||
Int32: sportID.Value,
|
||||
Valid: sportID.Valid,
|
||||
},
|
||||
FirstStartTime: pgtype.Timestamp{
|
||||
|
|
@ -205,15 +205,15 @@ func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.Upc
|
|||
|
||||
return domain.UpcomingEvent{
|
||||
ID: event.ID,
|
||||
SportID: event.SportID.String,
|
||||
SportID: event.SportID.Int32,
|
||||
MatchName: event.MatchName.String,
|
||||
HomeTeam: event.HomeTeam.String,
|
||||
AwayTeam: event.AwayTeam.String,
|
||||
HomeTeamID: event.HomeTeamID.String,
|
||||
AwayTeamID: event.AwayTeamID.String,
|
||||
HomeTeamID: event.HomeTeamID.Int32,
|
||||
AwayTeamID: event.AwayTeamID.Int32,
|
||||
HomeKitImage: event.HomeKitImage.String,
|
||||
AwayKitImage: event.AwayKitImage.String,
|
||||
LeagueID: event.LeagueID.String,
|
||||
LeagueID: event.LeagueID.Int32,
|
||||
LeagueName: event.LeagueName.String,
|
||||
LeagueCC: event.LeagueCc.String,
|
||||
StartTime: event.StartTime.Time.UTC(),
|
||||
|
|
|
|||
61
internal/repository/league.go
Normal file
61
internal/repository/league.go
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func (s *Store) SaveLeague(ctx context.Context, l domain.League) error {
|
||||
return s.queries.InsertLeague(ctx, dbgen.InsertLeagueParams{
|
||||
ID: l.ID,
|
||||
Name: l.Name,
|
||||
CountryCode: pgtype.Text{String: l.CountryCode, Valid: true},
|
||||
Bet365ID: pgtype.Int4{Int32: l.Bet365ID, Valid: true},
|
||||
IsActive: pgtype.Bool{Bool: l.IsActive, Valid: true},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) GetSupportedLeagues(ctx context.Context) ([]domain.League, error) {
|
||||
leagues, err := s.queries.GetSupportedLeagues(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
supportedLeagues := make([]domain.League, len(leagues))
|
||||
for i, league := range leagues {
|
||||
supportedLeagues[i] = domain.League{
|
||||
ID: league.ID,
|
||||
Name: league.Name,
|
||||
CountryCode: league.CountryCode.String,
|
||||
Bet365ID: league.Bet365ID.Int32,
|
||||
IsActive: league.IsActive.Bool,
|
||||
}
|
||||
}
|
||||
return supportedLeagues, nil
|
||||
}
|
||||
|
||||
func (s *Store) CheckLeagueSupport(ctx context.Context, leagueID int64) (bool, error) {
|
||||
return s.queries.CheckLeagueSupport(ctx, leagueID)
|
||||
}
|
||||
|
||||
// TODO: change to only take league id instad of the whole league
|
||||
func (s *Store) SetLeagueActive(ctx context.Context, l domain.League) error {
|
||||
return s.queries.UpdateLeague(ctx, dbgen.UpdateLeagueParams{
|
||||
Name: l.Name,
|
||||
CountryCode: pgtype.Text{String: l.CountryCode, Valid: true},
|
||||
Bet365ID: pgtype.Int4{Int32: l.Bet365ID, Valid: true},
|
||||
IsActive: pgtype.Bool{Bool: true, Valid: true},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) SetLeagueInActive(ctx context.Context, l domain.League) error {
|
||||
return s.queries.UpdateLeague(ctx, dbgen.UpdateLeagueParams{
|
||||
Name: l.Name,
|
||||
CountryCode: pgtype.Text{String: l.CountryCode, Valid: true},
|
||||
Bet365ID: pgtype.Int4{Int32: l.Bet365ID, Valid: true},
|
||||
IsActive: pgtype.Bool{Bool: false, Valid: true},
|
||||
})
|
||||
}
|
||||
|
|
@ -17,15 +17,19 @@ func (s *Store) SaveNonLiveMarket(ctx context.Context, m domain.Market) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
for _, raw := range m.Odds {
|
||||
var item map[string]interface{}
|
||||
if err := json.Unmarshal(raw, &item); err != nil {
|
||||
continue
|
||||
}
|
||||
for _, item := range m.Odds {
|
||||
var name string
|
||||
var oddsVal float64
|
||||
|
||||
name := getString(item["name"])
|
||||
if m.Source == "bwin" {
|
||||
nameValue := getMap(item["name"])
|
||||
name = getString(nameValue["value"])
|
||||
oddsVal = getFloat(item["odds"])
|
||||
} else {
|
||||
name = getString(item["name"])
|
||||
oddsVal = getConvertedFloat(item["odds"])
|
||||
}
|
||||
handicap := getString(item["handicap"])
|
||||
oddsVal := getFloat(item["odds"])
|
||||
|
||||
rawOddsBytes, _ := json.Marshal(m.Odds)
|
||||
|
||||
|
|
@ -43,7 +47,7 @@ func (s *Store) SaveNonLiveMarket(ctx context.Context, m domain.Market) error {
|
|||
Category: pgtype.Text{Valid: false},
|
||||
RawOdds: rawOddsBytes,
|
||||
IsActive: pgtype.Bool{Bool: true, Valid: true},
|
||||
Source: pgtype.Text{String: "b365api", Valid: true},
|
||||
Source: pgtype.Text{String: m.Source, Valid: true},
|
||||
FetchedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
|
||||
}
|
||||
|
||||
|
|
@ -85,23 +89,6 @@ func writeFailedMarketLog(m domain.Market, err error) error {
|
|||
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 {
|
||||
|
|
@ -286,3 +273,34 @@ func (s *Store) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID stri
|
|||
|
||||
return domainOdds, nil
|
||||
}
|
||||
|
||||
func getString(v interface{}) string {
|
||||
if s, ok := v.(string); ok {
|
||||
return s
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getConvertedFloat(v interface{}) float64 {
|
||||
if s, ok := v.(string); ok {
|
||||
f, err := strconv.ParseFloat(s, 64)
|
||||
if err == nil {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func getFloat(v interface{}) float64 {
|
||||
if n, ok := v.(float64); ok {
|
||||
return n
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func getMap(v interface{}) map[string]interface{} {
|
||||
if m, ok := v.(map[string]interface{}); ok {
|
||||
return m
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,15 +121,11 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI
|
|||
if err != nil {
|
||||
return domain.CreateBetOutcome{}, err
|
||||
}
|
||||
sportID, err := strconv.ParseInt(event.SportID, 10, 64)
|
||||
if err != nil {
|
||||
return domain.CreateBetOutcome{}, err
|
||||
}
|
||||
newOutcome := domain.CreateBetOutcome{
|
||||
EventID: eventID,
|
||||
OddID: oddID,
|
||||
MarketID: marketID,
|
||||
SportID: sportID,
|
||||
SportID: int64(event.SportID),
|
||||
HomeTeamName: event.HomeTeam,
|
||||
AwayTeamName: event.AwayTeam,
|
||||
MarketName: odds.MarketName,
|
||||
|
|
@ -287,7 +283,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
|
|||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID, sportID, HomeTeam, AwayTeam string, StartTime time.Time, numMarkets int) ([]domain.CreateBetOutcome, float32, error) {
|
||||
func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string, sportID int32, HomeTeam, AwayTeam string, StartTime time.Time, numMarkets int) ([]domain.CreateBetOutcome, float32, error) {
|
||||
|
||||
var newOdds []domain.CreateBetOutcome
|
||||
var totalOdds float32 = 1
|
||||
|
|
@ -337,11 +333,6 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID, sportI
|
|||
s.logger.Error("Failed to parse odd", "error", err)
|
||||
continue
|
||||
}
|
||||
sportID, err := strconv.ParseInt(sportID, 10, 64)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get sport id", "error", err)
|
||||
continue
|
||||
}
|
||||
eventID, err := strconv.ParseInt(eventID, 10, 64)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get event id", "error", err)
|
||||
|
|
@ -365,7 +356,7 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID, sportI
|
|||
EventID: eventID,
|
||||
OddID: oddID,
|
||||
MarketID: marketID,
|
||||
SportID: sportID,
|
||||
SportID: int64(sportID),
|
||||
HomeTeamName: HomeTeam,
|
||||
AwayTeamName: AwayTeam,
|
||||
MarketName: marketName,
|
||||
|
|
@ -388,7 +379,7 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID, sportI
|
|||
return newOdds, totalOdds, nil
|
||||
}
|
||||
|
||||
func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, leagueID, sportID domain.ValidString, firstStartTime, lastStartTime domain.ValidTime) (domain.CreateBetRes, error) {
|
||||
func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, leagueID, sportID domain.ValidInt32, firstStartTime, lastStartTime domain.ValidTime) (domain.CreateBetRes, error) {
|
||||
|
||||
// Get a unexpired event id
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ type Service interface {
|
|||
FetchUpcomingEvents(ctx context.Context) error
|
||||
GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
|
||||
GetExpiredUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
|
||||
GetPaginatedUpcomingEvents(ctx context.Context, limit domain.ValidInt64, offset domain.ValidInt64, leagueID domain.ValidString, sportID domain.ValidString, firstStartTime domain.ValidTime, lastStartTime domain.ValidTime) ([]domain.UpcomingEvent, int64, error)
|
||||
GetPaginatedUpcomingEvents(ctx context.Context, limit domain.ValidInt64, offset domain.ValidInt64, leagueID domain.ValidInt32, sportID domain.ValidInt32, firstStartTime domain.ValidTime, lastStartTime domain.ValidTime) ([]domain.UpcomingEvent, int64, error)
|
||||
GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error)
|
||||
// GetAndStoreMatchResult(ctx context.Context, eventID string) error
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ func (s *service) FetchLiveEvents(ctx context.Context) error {
|
|||
s.fetchLiveEvents(ctx, url.name, url.source)
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
|
@ -75,7 +74,7 @@ func (s *service) fetchLiveEvents(ctx context.Context, url, source string) error
|
|||
events := []domain.Event{}
|
||||
switch source {
|
||||
case "bet365":
|
||||
events = handleBet365prematch(body, sportID)
|
||||
events = handleBet365prematch(body, sportID, source)
|
||||
case "betfair":
|
||||
events = handleBetfairprematch(body, sportID, source)
|
||||
case "1xbet":
|
||||
|
|
@ -97,7 +96,7 @@ func (s *service) fetchLiveEvents(ctx context.Context, url, source string) error
|
|||
|
||||
}
|
||||
|
||||
func handleBet365prematch(body []byte, sportID int) []domain.Event {
|
||||
func handleBet365prematch(body []byte, sportID int, source string) []domain.Event {
|
||||
var data struct {
|
||||
Success int `json:"success"`
|
||||
Results [][]map[string]interface{} `json:"results"`
|
||||
|
|
@ -105,7 +104,7 @@ func handleBet365prematch(body []byte, sportID int) []domain.Event {
|
|||
|
||||
events := []domain.Event{}
|
||||
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
||||
fmt.Printf(" Decode failed for sport_id=%d\nRaw: %s\n", sportID, string(body))
|
||||
fmt.Printf("%s: Decode failed for sport_id=%d\nRaw: %s\n", source, sportID, string(body))
|
||||
return events
|
||||
}
|
||||
|
||||
|
|
@ -117,24 +116,24 @@ func handleBet365prematch(body []byte, sportID int) []domain.Event {
|
|||
|
||||
event := domain.Event{
|
||||
ID: getString(ev["ID"]),
|
||||
SportID: fmt.Sprintf("%d", sportID),
|
||||
SportID: int32(sportID),
|
||||
MatchName: getString(ev["NA"]),
|
||||
Score: getString(ev["SS"]),
|
||||
MatchMinute: getInt(ev["TM"]),
|
||||
TimerStatus: getString(ev["TT"]),
|
||||
HomeTeamID: getString(ev["HT"]),
|
||||
AwayTeamID: getString(ev["AT"]),
|
||||
HomeTeamID: getInt32(ev["HT"]),
|
||||
AwayTeamID: getInt32(ev["AT"]),
|
||||
HomeKitImage: getString(ev["K1"]),
|
||||
AwayKitImage: getString(ev["K2"]),
|
||||
LeagueName: getString(ev["CT"]),
|
||||
LeagueID: getString(ev["C2"]),
|
||||
LeagueID: getInt32(ev["C2"]),
|
||||
LeagueCC: getString(ev["CB"]),
|
||||
StartTime: time.Now().UTC().Format(time.RFC3339),
|
||||
IsLive: true,
|
||||
Status: "live",
|
||||
MatchPeriod: getInt(ev["MD"]),
|
||||
AddedTime: getInt(ev["TA"]),
|
||||
Source: "bet365",
|
||||
Source: source,
|
||||
}
|
||||
|
||||
events = append(events, event)
|
||||
|
|
@ -152,23 +151,20 @@ func handleBetfairprematch(body []byte, sportID int, source string) []domain.Eve
|
|||
|
||||
events := []domain.Event{}
|
||||
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
||||
fmt.Printf(" Decode failed for sport_id=%d\nRaw: %s\n", sportID, string(body))
|
||||
fmt.Printf("%s: Decode failed for sport_id=%d\nRaw: %s\n", source, sportID, string(body))
|
||||
return events
|
||||
}
|
||||
|
||||
for _, ev := range data.Results {
|
||||
homeRaw, _ := ev["home"].(map[string]interface{})
|
||||
homeId, _ := homeRaw["id"].(string)
|
||||
|
||||
awayRaw, _ := ev["home"].(map[string]interface{})
|
||||
awayId, _ := awayRaw["id"].(string)
|
||||
|
||||
event := domain.Event{
|
||||
ID: getString(ev["id"]),
|
||||
SportID: fmt.Sprintf("%d", sportID),
|
||||
SportID: int32(sportID),
|
||||
TimerStatus: getString(ev["time_status"]),
|
||||
HomeTeamID: homeId,
|
||||
AwayTeamID: awayId,
|
||||
HomeTeamID: getInt32(homeRaw["id"]),
|
||||
AwayTeamID: getInt32(awayRaw["id"]),
|
||||
StartTime: time.Now().UTC().Format(time.RFC3339),
|
||||
IsLive: true,
|
||||
Status: "live",
|
||||
|
|
@ -221,8 +217,8 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
|||
log.Printf("Sport ID %d", sportID)
|
||||
for page <= totalPages {
|
||||
page = page + 1
|
||||
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s&page=%d", sportID, s.token, page)
|
||||
log.Printf("📡 Fetching data for sport %d at page %d", sportID, page)
|
||||
url := fmt.Sprintf(url, sportID, s.token, page)
|
||||
log.Printf("📡 Fetching data from %s - sport %d, for event data page %d", source, sportID, page)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to fetch event data for page %d: %v", page, err)
|
||||
|
|
@ -246,33 +242,35 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
|||
// continue
|
||||
// }
|
||||
|
||||
// leagueID, err := strconv.ParseInt(ev.League.ID, 10, 64)
|
||||
// if err != nil {
|
||||
// log.Printf("❌ Invalid league id, leagueID %v", ev.League.ID)
|
||||
// continue
|
||||
// }
|
||||
leagueID, err := strconv.ParseInt(ev.League.ID, 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("❌ Invalid league id, leagueID %v", ev.League.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
// if !slices.Contains(domain.SupportedLeagues, leagueID) {
|
||||
// // fmt.Printf("⚠️ Skipping league %s (%d) as it is not supported\n", ev.League.Name, leagueID)
|
||||
// _, err = fmt.Fprintf(b, "Skipped league %s (%d) in sport %d\n", ev.League.Name, leagueID, sportID)
|
||||
// if err != nil {
|
||||
// fmt.Printf(" Error while logging skipped league")
|
||||
// }
|
||||
// skippedLeague = append(skippedLeague, ev.League.Name)
|
||||
// continue
|
||||
// }
|
||||
// doesn't make sense to save and check back to back, but for now it can be here
|
||||
s.store.SaveLeague(ctx, domain.League{
|
||||
ID: leagueID,
|
||||
Name: ev.League.Name,
|
||||
IsActive: true,
|
||||
})
|
||||
|
||||
if supported, err := s.store.CheckLeagueSupport(ctx, leagueID); !supported || err != nil {
|
||||
skippedLeague = append(skippedLeague, ev.League.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
event := domain.UpcomingEvent{
|
||||
ID: ev.ID,
|
||||
SportID: ev.SportID,
|
||||
SportID: convertInt32(ev.SportID),
|
||||
MatchName: "",
|
||||
HomeTeam: ev.Home.Name,
|
||||
AwayTeam: "", // handle nil safely
|
||||
HomeTeamID: ev.Home.ID,
|
||||
AwayTeamID: "",
|
||||
HomeTeamID: convertInt32(ev.Home.ID),
|
||||
AwayTeamID: 0,
|
||||
HomeKitImage: "",
|
||||
AwayKitImage: "",
|
||||
LeagueID: ev.League.ID,
|
||||
LeagueID: convertInt32(ev.League.ID),
|
||||
LeagueName: ev.League.Name,
|
||||
LeagueCC: "",
|
||||
StartTime: time.Unix(startUnix, 0).UTC(),
|
||||
|
|
@ -281,7 +279,7 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
|||
|
||||
if ev.Away != nil {
|
||||
event.AwayTeam = ev.Away.Name
|
||||
event.AwayTeamID = ev.Away.ID
|
||||
event.AwayTeamID = convertInt32(ev.Away.ID)
|
||||
event.MatchName = ev.Home.Name + " vs " + ev.Away.Name
|
||||
}
|
||||
|
||||
|
|
@ -319,6 +317,20 @@ func getInt(v interface{}) int {
|
|||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func getInt32(v interface{}) int32 {
|
||||
if n, err := strconv.Atoi(getString(v)); err == nil {
|
||||
return int32(n)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func convertInt32(num string) int32 {
|
||||
if n, err := strconv.Atoi(num); err == nil {
|
||||
return int32(n)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func (s *service) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error) {
|
||||
return s.store.GetAllUpcomingEvents(ctx)
|
||||
}
|
||||
|
|
@ -327,7 +339,7 @@ func (s *service) GetExpiredUpcomingEvents(ctx context.Context) ([]domain.Upcomi
|
|||
return s.store.GetExpiredUpcomingEvents(ctx)
|
||||
}
|
||||
|
||||
func (s *service) GetPaginatedUpcomingEvents(ctx context.Context, limit domain.ValidInt64, offset domain.ValidInt64, leagueID domain.ValidString, sportID domain.ValidString, firstStartTime domain.ValidTime, lastStartTime domain.ValidTime) ([]domain.UpcomingEvent, int64, error) {
|
||||
func (s *service) GetPaginatedUpcomingEvents(ctx context.Context, limit domain.ValidInt64, offset domain.ValidInt64, leagueID domain.ValidInt32, sportID domain.ValidInt32, firstStartTime domain.ValidTime, lastStartTime domain.ValidTime) ([]domain.UpcomingEvent, int64, error) {
|
||||
return s.store.GetPaginatedUpcomingEvents(ctx, limit, offset, leagueID, sportID, firstStartTime, lastStartTime)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"log/slog"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||||
|
|
@ -35,6 +36,38 @@ func New(store *repository.Store, cfg *config.Config, logger *slog.Logger) *Serv
|
|||
|
||||
// TODO Add the optimization to get 10 events at the same time
|
||||
func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
||||
var wg sync.WaitGroup
|
||||
errChan := make(chan error, 2)
|
||||
// wg.Add(2)
|
||||
wg.Add(1)
|
||||
|
||||
// go func() {
|
||||
// defer wg.Done()
|
||||
// if err := s.fetchBet365Odds(ctx); err != nil {
|
||||
// errChan <- fmt.Errorf("bet365 odds fetching error: %w", err)
|
||||
// }
|
||||
// }()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := s.fetchBwinOdds(ctx); err != nil {
|
||||
errChan <- fmt.Errorf("bwin odds fetching error: %w", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var errs []error
|
||||
for err := range errChan {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) fetchBet365Odds(ctx context.Context) error {
|
||||
eventIDs, err := s.store.GetAllUpcomingEvents(ctx)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to fetch upcoming event IDs: %v", err)
|
||||
|
|
@ -80,9 +113,7 @@ func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
|||
continue
|
||||
}
|
||||
|
||||
sportID, err := strconv.ParseInt(event.SportID, 10, 64)
|
||||
|
||||
switch sportID {
|
||||
switch event.SportID {
|
||||
case domain.FOOTBALL:
|
||||
if err := s.parseFootball(ctx, oddsData.Results[0]); err != nil {
|
||||
s.logger.Error("Error while inserting football odd")
|
||||
|
|
@ -147,6 +178,93 @@ func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) fetchBwinOdds(ctx context.Context) error {
|
||||
// getting odds for a specific event is not possible for bwin, most specific we can get is fetch odds on a single sport
|
||||
// so instead of having event and odds fetched separetly event will also be fetched along with the odds
|
||||
sportIds := []int{4, 12, 7}
|
||||
for _, sportId := range sportIds {
|
||||
url := fmt.Sprintf("https://api.b365api.com/v1/bwin/prematch?sport_id=%d&token=%s", sportId, s.config.Bet365Token)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to create request for sportId %d: %v", sportId, err)
|
||||
continue
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to fetch request for sportId %d: %v", sportId, err)
|
||||
continue
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to read response body for sportId %d: %v", sportId, err)
|
||||
continue
|
||||
}
|
||||
|
||||
var data struct {
|
||||
Success int `json:"success"`
|
||||
Results []map[string]interface{} `json:"results"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
||||
fmt.Printf("Decode failed for sport_id=%d\nRaw: %s\n", sportId, string(body))
|
||||
continue
|
||||
}
|
||||
|
||||
for _, res := range data.Results {
|
||||
if getInt(res["Id"]) == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
event := domain.Event{
|
||||
ID: strconv.Itoa(getInt(res["Id"])),
|
||||
SportID: int32(getInt(res["SportId"])),
|
||||
LeagueID: int32(getInt(res["LeagueId"])),
|
||||
LeagueName: getString(res["Leaguename"]),
|
||||
HomeTeam: getString(res["HomeTeam"]),
|
||||
HomeTeamID: int32(getInt(res["HomeTeamId"])),
|
||||
AwayTeam: getString(res["AwayTeam"]),
|
||||
AwayTeamID: int32(getInt(res["AwayTeamId"])),
|
||||
StartTime: time.Now().UTC().Format(time.RFC3339),
|
||||
TimerStatus: "1",
|
||||
IsLive: true,
|
||||
Status: "live",
|
||||
Source: "bwin",
|
||||
}
|
||||
|
||||
if err := s.store.SaveEvent(ctx, event); err != nil {
|
||||
fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, market := range []string{"Markets, optionMarkets"} {
|
||||
for _, m := range getMapArray(res[market]) {
|
||||
name := getMap(m["name"])
|
||||
marketName := getString(name["value"])
|
||||
|
||||
market := domain.Market{
|
||||
EventID: event.ID,
|
||||
MarketID: getString(m["id"]),
|
||||
MarketCategory: getString(m["category"]),
|
||||
MarketName: marketName,
|
||||
Source: "bwin",
|
||||
}
|
||||
|
||||
results := getMapArray(m["results"])
|
||||
market.Odds = results
|
||||
|
||||
s.store.SaveNonLiveMarket(ctx, market)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) parseFootball(ctx context.Context, res json.RawMessage) error {
|
||||
var footballRes domain.FootballOddsResponse
|
||||
if err := json.Unmarshal(res, &footballRes); err != nil {
|
||||
|
|
@ -630,6 +748,13 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
|
|||
continue
|
||||
}
|
||||
|
||||
marketOdds, err := convertRawMessage(market.Odds)
|
||||
if err != nil {
|
||||
s.logger.Error("failed to conver json.RawMessage to []map[string]interface{} for market_id: ", market.ID)
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
marketRecord := domain.Market{
|
||||
EventID: eventID,
|
||||
FI: fi,
|
||||
|
|
@ -638,7 +763,9 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
|
|||
MarketName: market.Name,
|
||||
MarketID: marketIDstr,
|
||||
UpdatedAt: updatedAt,
|
||||
Odds: market.Odds,
|
||||
Odds: marketOdds,
|
||||
// bwin won't reach this code so bet365 is hardcoded for now
|
||||
Source: "bet365",
|
||||
}
|
||||
|
||||
err = s.store.SaveNonLiveMarket(ctx, marketRecord)
|
||||
|
|
@ -679,3 +806,49 @@ func (s *ServiceImpl) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingI
|
|||
func (s *ServiceImpl) GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset domain.ValidInt64) ([]domain.Odd, error) {
|
||||
return s.store.GetPaginatedPrematchOddsByUpcomingID(ctx, upcomingID, limit, offset)
|
||||
}
|
||||
|
||||
func getString(v interface{}) string {
|
||||
if str, ok := v.(string); ok {
|
||||
return str
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getInt(v interface{}) int {
|
||||
if n, ok := v.(float64); ok {
|
||||
return int(n)
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func getMap(v interface{}) map[string]interface{} {
|
||||
if m, ok := v.(map[string]interface{}); ok {
|
||||
return m
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMapArray(v interface{}) []map[string]interface{} {
|
||||
result := []map[string]interface{}{}
|
||||
if arr, ok := v.([]interface{}); ok {
|
||||
for _, item := range arr {
|
||||
if m, ok := item.(map[string]interface{}); ok {
|
||||
result = append(result, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func convertRawMessage(rawMessages []json.RawMessage) ([]map[string]interface{}, error) {
|
||||
var result []map[string]interface{}
|
||||
for _, raw := range rawMessages {
|
||||
var m map[string]interface{}
|
||||
if err := json.Unmarshal(raw, &m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, m)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,14 +80,8 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
|||
continue
|
||||
}
|
||||
|
||||
sportID, err := strconv.ParseInt(event.SportID, 10, 64)
|
||||
if err != nil {
|
||||
s.logger.Error("Sport ID is invalid", "event_id", outcome.EventID, "error", err)
|
||||
isDeleted = false
|
||||
continue
|
||||
}
|
||||
// TODO: optimize this because the result is being fetched for each outcome which will have the same event id but different market id
|
||||
result, err := s.fetchResult(ctx, outcome.EventID, outcome.OddID, outcome.MarketID, sportID, outcome)
|
||||
result, err := s.fetchResult(ctx, outcome.EventID, outcome.OddID, outcome.MarketID, int64(event.SportID), outcome)
|
||||
if err != nil {
|
||||
if err == ErrEventIsNotActive {
|
||||
s.logger.Warn("Event is not active", "event_id", outcome.EventID, "error", err)
|
||||
|
|
|
|||
|
|
@ -71,18 +71,28 @@ func (h *Handler) RandomBet(c *fiber.Ctx) error {
|
|||
userID := c.Locals("user_id").(int64)
|
||||
// role := c.Locals("role").(domain.Role)
|
||||
|
||||
leagueIDQuery := c.Query("league_id")
|
||||
sportIDQuery := c.Query("sport_id")
|
||||
leagueIDQuery, err := strconv.Atoi(c.Query("league_id"))
|
||||
if err != nil {
|
||||
h.logger.Error("invalid league id", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil)
|
||||
}
|
||||
|
||||
sportIDQuery, err := strconv.Atoi(c.Query("sport_id"))
|
||||
if err != nil {
|
||||
h.logger.Error("invalid sport id", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "invalid sport id", nil, nil)
|
||||
}
|
||||
|
||||
firstStartTimeQuery := c.Query("first_start_time")
|
||||
lastStartTimeQuery := c.Query("last_start_time")
|
||||
|
||||
leagueID := domain.ValidString{
|
||||
Value: leagueIDQuery,
|
||||
Valid: leagueIDQuery != "",
|
||||
leagueID := domain.ValidInt32{
|
||||
Value: int32(leagueIDQuery),
|
||||
Valid: leagueIDQuery != 0,
|
||||
}
|
||||
sportID := domain.ValidString{
|
||||
Value: sportIDQuery,
|
||||
Valid: sportIDQuery != "",
|
||||
sportID := domain.ValidInt32{
|
||||
Value: int32(sportIDQuery),
|
||||
Valid: sportIDQuery != 0,
|
||||
}
|
||||
|
||||
var firstStartTime domain.ValidTime
|
||||
|
|
@ -122,7 +132,6 @@ func (h *Handler) RandomBet(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
var res domain.CreateBetRes
|
||||
var err error
|
||||
for i := 0; i < int(req.NumberOfBets); i++ {
|
||||
res, err = h.betSvc.PlaceRandomBet(c.Context(), userID, req.BranchID, leagueID, sportID, firstStartTime, lastStartTime)
|
||||
|
||||
|
|
|
|||
|
|
@ -107,18 +107,27 @@ func (h *Handler) GetRawOddsByMarketID(c *fiber.Ctx) error {
|
|||
func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error {
|
||||
page := c.QueryInt("page", 1)
|
||||
pageSize := c.QueryInt("page_size", 10)
|
||||
leagueIDQuery := c.Query("league_id")
|
||||
sportIDQuery := c.Query("sport_id")
|
||||
leagueIDQuery, err := strconv.Atoi(c.Query("league_id"))
|
||||
if err != nil {
|
||||
h.logger.Error("invalid league id", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil)
|
||||
}
|
||||
|
||||
sportIDQuery, err := strconv.Atoi(c.Query("sport_id"))
|
||||
if err != nil {
|
||||
h.logger.Error("invalid sport id", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "invalid sport id", nil, nil)
|
||||
}
|
||||
firstStartTimeQuery := c.Query("first_start_time")
|
||||
lastStartTimeQuery := c.Query("last_start_time")
|
||||
|
||||
leagueID := domain.ValidString{
|
||||
Value: leagueIDQuery,
|
||||
Valid: leagueIDQuery != "",
|
||||
leagueID := domain.ValidInt32{
|
||||
Value: int32(leagueIDQuery),
|
||||
Valid: leagueIDQuery != 0,
|
||||
}
|
||||
sportID := domain.ValidString{
|
||||
Value: sportIDQuery,
|
||||
Valid: sportIDQuery != "",
|
||||
sportID := domain.ValidInt32{
|
||||
Value: int32(sportIDQuery),
|
||||
Valid: sportIDQuery != 0,
|
||||
}
|
||||
|
||||
var firstStartTime domain.ValidTime
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user