Enetpulse fixes

This commit is contained in:
Yared Yemane 2025-10-14 14:21:27 +03:00
parent af7c792dee
commit 9cb008225b
17 changed files with 3041 additions and 285 deletions

View File

@ -1,2 +0,0 @@
DROP TABLE IF EXISTS enetpulse_sports;
DROP TABLE IF EXISTS enetpulse_tournament_templates;

View File

@ -1,64 +0,0 @@
CREATE TABLE IF NOT EXISTS enetpulse_sports (
id BIGSERIAL PRIMARY KEY,
sport_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id"
name VARCHAR(255) NOT NULL, -- from API "name"
updates_count INT DEFAULT 0, -- from API "n"
last_updated_at TIMESTAMPTZ, -- from API "ut"
status INT DEFAULT 1, -- optional status (active/inactive)
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS enetpulse_tournament_templates (
id BIGSERIAL PRIMARY KEY,
template_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id"
name VARCHAR(255) NOT NULL, -- from API "name"
sport_fk VARCHAR(50) NOT NULL REFERENCES enetpulse_sports(sport_id) ON DELETE CASCADE,
gender VARCHAR(20) DEFAULT 'unknown', -- from API "gender" {male, female, mixed, unknown}
updates_count INT DEFAULT 0, -- from API "n"
last_updated_at TIMESTAMPTZ, -- from API "ut"
status INT DEFAULT 1, -- optional status (active/inactive)
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS enetpulse_tournaments (
id BIGSERIAL PRIMARY KEY,
tournament_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id"
name VARCHAR(255) NOT NULL, -- from API "name"
-- Link to the template it belongs to:
tournament_template_fk VARCHAR(50) NOT NULL
REFERENCES enetpulse_tournament_templates(template_id) ON DELETE CASCADE,
updates_count INT DEFAULT 0, -- from API "n"
last_updated_at TIMESTAMPTZ, -- from API "ut"
status INT DEFAULT 1, -- optional active/inactive flag
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
-- Create table for tournament stages
CREATE TABLE IF NOT EXISTS enetpulse_tournament_stages (
id BIGSERIAL PRIMARY KEY,
stage_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id"
name VARCHAR(255) NOT NULL, -- from API "name"
tournament_fk VARCHAR(50) NOT NULL REFERENCES enetpulse_tournaments(tournament_id) ON DELETE CASCADE,
-- from API "tournamentFK"
gender VARCHAR(20) DEFAULT 'unknown', -- from API "gender" {male, female, mixed, unknown}
country_fk VARCHAR(50), -- from API "countryFK"
country_name VARCHAR(255), -- from API "country_name"
start_date TIMESTAMPTZ, -- from API "startdate"
end_date TIMESTAMPTZ, -- from API "enddate"
updates_count INT DEFAULT 0, -- from API "n"
last_updated_at TIMESTAMPTZ, -- from API "ut"
status INT DEFAULT 1, -- optional status (active/inactive)
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
-- Index to quickly query by tournament_fk
CREATE INDEX IF NOT EXISTS idx_enetpulse_tournament_stages_tournament_fk
ON enetpulse_tournament_stages (tournament_fk);

View File

@ -1,2 +1,5 @@
DROP TABLE IF EXISTS enetpulse_sports;
DROP TABLE IF EXISTS enetpulse_tournament_templates;
DROP TABLE IF EXISTS enetpulse_tournaments;
DROP TABLE IF EXISTS enetpulse_tournament_stages;
DROP TABLE IF EXISTS enetpulse_fixtures;

View File

@ -21,3 +21,207 @@ CREATE TABLE IF NOT EXISTS enetpulse_tournament_templates (
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS enetpulse_tournaments (
id BIGSERIAL PRIMARY KEY,
tournament_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id"
name VARCHAR(255) NOT NULL, -- from API "name"
-- Link to the template it belongs to:
tournament_template_fk VARCHAR(50) NOT NULL
REFERENCES enetpulse_tournament_templates(template_id) ON DELETE CASCADE,
updates_count INT DEFAULT 0, -- from API "n"
last_updated_at TIMESTAMPTZ, -- from API "ut"
status INT DEFAULT 1, -- optional active/inactive flag
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS enetpulse_tournament_stages (
id BIGSERIAL PRIMARY KEY,
stage_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id"
name VARCHAR(255) NOT NULL, -- from API "name"
tournament_fk VARCHAR(50) NOT NULL REFERENCES enetpulse_tournaments(tournament_id) ON DELETE CASCADE,
-- from API "tournamentFK"
gender VARCHAR(20) DEFAULT 'unknown', -- from API "gender" {male, female, mixed, unknown}
country_fk VARCHAR(50), -- from API "countryFK"
country_name VARCHAR(255), -- from API "country_name"
start_date TIMESTAMPTZ, -- from API "startdate"
end_date TIMESTAMPTZ, -- from API "enddate"
updates_count INT DEFAULT 0, -- from API "n"
last_updated_at TIMESTAMPTZ, -- from API "ut"
status INT DEFAULT 1, -- optional status (active/inactive)
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS idx_enetpulse_tournament_stages_tournament_fk
ON enetpulse_tournament_stages (tournament_fk);
CREATE TABLE IF NOT EXISTS enetpulse_fixtures (
id BIGSERIAL PRIMARY KEY,
fixture_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id"
name VARCHAR(255) NOT NULL, -- fixture name (e.g. 12 de Junio-Sol de America)
sport_fk VARCHAR(50) NOT NULL REFERENCES enetpulse_sports(sport_id) ON DELETE CASCADE,
tournament_fk VARCHAR(50), -- raw tournamentFK (optional)
tournament_template_fk VARCHAR(50) REFERENCES enetpulse_tournament_templates(template_id) ON DELETE CASCADE,
tournament_stage_fk VARCHAR(50) REFERENCES enetpulse_tournament_stages(stage_id) ON DELETE CASCADE,
tournament_stage_name VARCHAR(255),
tournament_name VARCHAR(255),
tournament_template_name VARCHAR(255),
sport_name VARCHAR(255),
gender VARCHAR(20),
start_date TIMESTAMPTZ NOT NULL, -- startdate
status_type VARCHAR(50), -- Not started, Live, Finished
status_desc_fk VARCHAR(50), -- status_descFK
round_type_fk VARCHAR(50), -- round_typeFK
updates_count INT DEFAULT 0, -- n
last_updated_at TIMESTAMPTZ, -- ut
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS enetpulse_results (
id BIGSERIAL PRIMARY KEY,
result_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id"
name VARCHAR(255) NOT NULL, -- event name (e.g. Brentford-Manchester City)
sport_fk VARCHAR(50) NOT NULL REFERENCES enetpulse_sports(sport_id) ON DELETE CASCADE,
tournament_fk VARCHAR(50),
tournament_template_fk VARCHAR(50) REFERENCES enetpulse_tournament_templates(template_id) ON DELETE CASCADE,
tournament_stage_fk VARCHAR(50) REFERENCES enetpulse_tournament_stages(stage_id) ON DELETE CASCADE,
tournament_stage_name VARCHAR(255),
tournament_name VARCHAR(255),
tournament_template_name VARCHAR(255),
sport_name VARCHAR(255),
start_date TIMESTAMPTZ NOT NULL, -- startdate
status_type VARCHAR(50), -- e.g. Finished
status_desc_fk VARCHAR(50), -- status_descFK
round_type_fk VARCHAR(50), -- round_typeFK
updates_count INT DEFAULT 0, -- n
last_updated_at TIMESTAMPTZ, -- ut
-- Optional metadata (dynamic but common fields are included)
round VARCHAR(50),
live VARCHAR(10),
venue_name VARCHAR(255),
livestats_plus VARCHAR(10),
livestats_type VARCHAR(50),
commentary VARCHAR(50),
lineup_confirmed BOOLEAN,
verified BOOLEAN,
spectators INT,
-- Time-related metadata
game_started TIMESTAMPTZ,
first_half_ended TIMESTAMPTZ,
second_half_started TIMESTAMPTZ,
second_half_ended TIMESTAMPTZ,
game_ended TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
-- Event Participants (teams involved in the result)
CREATE TABLE IF NOT EXISTS enetpulse_result_participants (
id BIGSERIAL PRIMARY KEY,
participant_map_id VARCHAR(50) NOT NULL UNIQUE, -- from event_participants.*.id
result_fk VARCHAR(50) NOT NULL REFERENCES enetpulse_results(result_id) ON DELETE CASCADE,
participant_fk VARCHAR(50) NOT NULL, -- team/player FK (from API participantFK)
number INT, -- 1 or 2 (home/away indicator)
name VARCHAR(255), -- team/player name
gender VARCHAR(20),
type VARCHAR(50),
country_fk VARCHAR(50),
country_name VARCHAR(100),
-- Result details
ordinary_time VARCHAR(10),
running_score VARCHAR(10),
halftime VARCHAR(10),
final_result VARCHAR(10),
last_updated_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- Referees / Match officials
CREATE TABLE IF NOT EXISTS enetpulse_result_referees (
id BIGSERIAL PRIMARY KEY,
result_fk VARCHAR(50) NOT NULL REFERENCES enetpulse_results(result_id) ON DELETE CASCADE,
referee_fk VARCHAR(50),
assistant1_referee_fk VARCHAR(50),
assistant2_referee_fk VARCHAR(50),
fourth_referee_fk VARCHAR(50),
var1_referee_fk VARCHAR(50),
var2_referee_fk VARCHAR(50),
last_updated_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS enetpulse_outcome_types (
id BIGSERIAL PRIMARY KEY,
outcome_type_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id"
name VARCHAR(100) NOT NULL, -- e.g. "1x2"
description VARCHAR(255), -- e.g. "1x2 - 3Way"
updates_count INT DEFAULT 0, -- maps to "n"
last_updated_at TIMESTAMPTZ, -- maps to "ut"
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
-- Table for pre-match odds (main outcome entries)
CREATE TABLE IF NOT EXISTS enetpulse_preodds (
id BIGSERIAL PRIMARY KEY,
preodds_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id"
event_fk BIGINT NOT NULL, -- maps to objectFK/event
outcome_type_fk INT, -- outcome_typeFK
outcome_scope_fk INT, -- outcome_scopeFK
outcome_subtype_fk INT, -- outcome_subtypeFK
event_participant_number INT, -- event_participant_number
iparam VARCHAR(50),
iparam2 VARCHAR(50),
dparam VARCHAR(50),
dparam2 VARCHAR(50),
sparam VARCHAR(50),
updates_count INT DEFAULT 0, -- maps to "n"
last_updated_at TIMESTAMPTZ, -- maps to "ut"
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
-- Table for nested betting offers within preodds
CREATE TABLE IF NOT EXISTS enetpulse_preodds_bettingoffers (
id BIGSERIAL PRIMARY KEY,
bettingoffer_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id"
preodds_fk VARCHAR(50) NOT NULL REFERENCES enetpulse_preodds(preodds_id) ON DELETE CASCADE,
bettingoffer_status_fk INT, -- bettingoffer_statusFK
odds_provider_fk INT, -- odds_providerFK
odds NUMERIC(10,4), -- current odds
odds_old NUMERIC(10,4), -- previous odds
active BOOLEAN, -- maps "yes"/"no" to boolean
coupon_key VARCHAR(255), -- couponKey
updates_count INT DEFAULT 0, -- maps to "n"
last_updated_at TIMESTAMPTZ, -- maps to "ut"
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);

View File

@ -68,6 +68,9 @@ SELECT
FROM enetpulse_tournament_templates
ORDER BY name;
-- -- name: DeleteEnetpulseTournamentTemplateByID :exec
-- DELETE FROM enetpulse_tournament_templates WHERE template_id = $1;
-- name: CreateEnetpulseTournament :one
INSERT INTO enetpulse_tournaments (
tournament_id,
@ -130,5 +133,243 @@ FROM enetpulse_tournament_stages
WHERE tournament_fk = $1
ORDER BY created_at DESC;
-- name: CreateEnetpulseFixture :one
INSERT INTO enetpulse_fixtures (
fixture_id,
name,
sport_fk,
tournament_fk,
tournament_template_fk,
tournament_stage_fk,
tournament_stage_name,
tournament_name,
tournament_template_name,
sport_name,
gender,
start_date,
status_type,
status_desc_fk,
round_type_fk,
updates_count,
last_updated_at,
created_at,
updated_at
) VALUES (
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP
)
ON CONFLICT (fixture_id) DO UPDATE
SET
name = EXCLUDED.name,
sport_fk = EXCLUDED.sport_fk,
tournament_fk = EXCLUDED.tournament_fk,
tournament_template_fk = EXCLUDED.tournament_template_fk,
tournament_stage_fk = EXCLUDED.tournament_stage_fk,
tournament_stage_name = EXCLUDED.tournament_stage_name,
tournament_name = EXCLUDED.tournament_name,
tournament_template_name = EXCLUDED.tournament_template_name,
sport_name = EXCLUDED.sport_name,
gender = EXCLUDED.gender,
start_date = EXCLUDED.start_date,
status_type = EXCLUDED.status_type,
status_desc_fk = EXCLUDED.status_desc_fk,
round_type_fk = EXCLUDED.round_type_fk,
updates_count = EXCLUDED.updates_count,
last_updated_at = EXCLUDED.last_updated_at,
updated_at = CURRENT_TIMESTAMP
RETURNING *;
-- name: GetAllEnetpulseFixtures :many
SELECT *
FROM enetpulse_fixtures
ORDER BY created_at DESC;
-- name: CreateEnetpulseResult :one
INSERT INTO enetpulse_results (
result_id,
name,
sport_fk,
tournament_fk,
tournament_template_fk,
tournament_stage_fk,
tournament_stage_name,
tournament_name,
tournament_template_name,
sport_name,
start_date,
status_type,
status_desc_fk,
round_type_fk,
updates_count,
last_updated_at,
round,
live,
venue_name,
livestats_plus,
livestats_type,
commentary,
lineup_confirmed,
verified,
spectators,
game_started,
first_half_ended,
second_half_started,
second_half_ended,
game_ended
) VALUES (
$1, $2, $3, $4, $5, $6,
$7, $8, $9, $10, $11,
$12, $13, $14, $15, $16,
$17, $18, $19, $20, $21,
$22, $23, $24, $25, $26,
$27, $28, $29, $30
)
ON CONFLICT (result_id) DO UPDATE
SET
name = EXCLUDED.name,
sport_fk = EXCLUDED.sport_fk,
tournament_fk = EXCLUDED.tournament_fk,
tournament_template_fk = EXCLUDED.tournament_template_fk,
tournament_stage_fk = EXCLUDED.tournament_stage_fk,
tournament_stage_name = EXCLUDED.tournament_stage_name,
tournament_name = EXCLUDED.tournament_name,
tournament_template_name = EXCLUDED.tournament_template_name,
sport_name = EXCLUDED.sport_name,
start_date = EXCLUDED.start_date,
status_type = EXCLUDED.status_type,
status_desc_fk = EXCLUDED.status_desc_fk,
round_type_fk = EXCLUDED.round_type_fk,
updates_count = EXCLUDED.updates_count,
last_updated_at = EXCLUDED.last_updated_at,
round = EXCLUDED.round,
live = EXCLUDED.live,
venue_name = EXCLUDED.venue_name,
livestats_plus = EXCLUDED.livestats_plus,
livestats_type = EXCLUDED.livestats_type,
commentary = EXCLUDED.commentary,
lineup_confirmed = EXCLUDED.lineup_confirmed,
verified = EXCLUDED.verified,
spectators = EXCLUDED.spectators,
game_started = EXCLUDED.game_started,
first_half_ended = EXCLUDED.first_half_ended,
second_half_started = EXCLUDED.second_half_started,
second_half_ended = EXCLUDED.second_half_ended,
game_ended = EXCLUDED.game_ended,
updated_at = CURRENT_TIMESTAMP
RETURNING *;
-- name: GetAllEnetpulseResults :many
SELECT *
FROM enetpulse_results
ORDER BY created_at DESC;
-- name: CreateEnetpulseOutcomeType :one
INSERT INTO enetpulse_outcome_types (
outcome_type_id,
name,
description,
updates_count,
last_updated_at,
created_at,
updated_at
) VALUES (
$1, $2, $3, $4, $5, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
)
ON CONFLICT (outcome_type_id) DO UPDATE
SET
name = EXCLUDED.name,
description = EXCLUDED.description,
updates_count = EXCLUDED.updates_count,
last_updated_at = EXCLUDED.last_updated_at,
updated_at = CURRENT_TIMESTAMP
RETURNING *;
-- name: GetAllEnetpulseOutcomeTypes :many
SELECT *
FROM enetpulse_outcome_types
ORDER BY created_at DESC;
-- name: CreateEnetpulsePreodds :one
INSERT INTO enetpulse_preodds (
preodds_id,
event_fk,
outcome_type_fk,
outcome_scope_fk,
outcome_subtype_fk,
event_participant_number,
iparam,
iparam2,
dparam,
dparam2,
sparam,
updates_count,
last_updated_at,
created_at,
updated_at
) VALUES (
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP
)
ON CONFLICT (preodds_id) DO UPDATE
SET
event_fk = EXCLUDED.event_fk,
outcome_type_fk = EXCLUDED.outcome_type_fk,
outcome_scope_fk = EXCLUDED.outcome_scope_fk,
outcome_subtype_fk = EXCLUDED.outcome_subtype_fk,
event_participant_number = EXCLUDED.event_participant_number,
iparam = EXCLUDED.iparam,
iparam2 = EXCLUDED.iparam2,
dparam = EXCLUDED.dparam,
dparam2 = EXCLUDED.dparam2,
sparam = EXCLUDED.sparam,
updates_count = EXCLUDED.updates_count,
last_updated_at = EXCLUDED.last_updated_at,
updated_at = CURRENT_TIMESTAMP
RETURNING *;
-- name: GetAllEnetpulsePreodds :many
SELECT *
FROM enetpulse_preodds
ORDER BY created_at DESC;
-- name: CreateEnetpulsePreoddsBettingOffer :one
INSERT INTO enetpulse_preodds_bettingoffers (
bettingoffer_id,
preodds_fk,
bettingoffer_status_fk,
odds_provider_fk,
odds,
odds_old,
active,
coupon_key,
updates_count,
last_updated_at,
created_at,
updated_at
) VALUES (
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP
)
ON CONFLICT (bettingoffer_id) DO UPDATE
SET
preodds_fk = EXCLUDED.preodds_fk,
bettingoffer_status_fk = EXCLUDED.bettingoffer_status_fk,
odds_provider_fk = EXCLUDED.odds_provider_fk,
odds = EXCLUDED.odds,
odds_old = EXCLUDED.odds_old,
active = EXCLUDED.active,
coupon_key = EXCLUDED.coupon_key,
updates_count = EXCLUDED.updates_count,
last_updated_at = EXCLUDED.last_updated_at,
updated_at = CURRENT_TIMESTAMP
RETURNING *;
-- name: GetAllEnetpulsePreoddsBettingOffers :many
SELECT *
FROM enetpulse_preodds_bettingoffers
ORDER BY created_at DESC;

View File

@ -4,7 +4,7 @@ services:
postgres:
image: postgres:16-alpine
ports:
- 5422:5432
- "5422:5432"
environment:
- POSTGRES_PASSWORD=secret
- POSTGRES_USER=root
@ -19,6 +19,7 @@ services:
volumes:
- postgres_data:/var/lib/postgresql/data
- ./exports:/exports
mongo:
container_name: fortunebet-mongo
image: mongo:7.0.11
@ -37,6 +38,7 @@ services:
interval: 10s
timeout: 5s
retries: 5
migrate:
image: migrate/migrate
volumes:
@ -54,6 +56,7 @@ services:
]
networks:
- app
redis:
image: redis:7-alpine
ports:
@ -66,17 +69,17 @@ services:
timeout: 5s
retries: 5
zookeeper:
image: confluentinc/cp-zookeeper:7.5.0
container_name: zookeeper
ports:
- "2181:2181"
- "22181:2181" # remapped host port (Windows-safe)
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
networks:
- app
kafka:
image: confluentinc/cp-kafka:7.5.0
depends_on:
@ -88,19 +91,19 @@ services:
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
ports:
- "9092:9092"
- "29092:29092"
networks:
- app
app:
build:
context: .
dockerfile: Dockerfile
target: runner
ports:
- ${PORT}:8080
- "${PORT}:8080"
environment:
- DB_URL=postgresql://root:secret@postgres:5432/gh?sslmode=disable
- MONGO_URI=mongodb://root:secret@mongo:27017

View File

@ -11,6 +11,519 @@ import (
"github.com/jackc/pgx/v5/pgtype"
)
const CreateEnetpulseFixture = `-- name: CreateEnetpulseFixture :one
INSERT INTO enetpulse_fixtures (
fixture_id,
name,
sport_fk,
tournament_fk,
tournament_template_fk,
tournament_stage_fk,
tournament_stage_name,
tournament_name,
tournament_template_name,
sport_name,
gender,
start_date,
status_type,
status_desc_fk,
round_type_fk,
updates_count,
last_updated_at,
created_at,
updated_at
) VALUES (
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP
)
ON CONFLICT (fixture_id) DO UPDATE
SET
name = EXCLUDED.name,
sport_fk = EXCLUDED.sport_fk,
tournament_fk = EXCLUDED.tournament_fk,
tournament_template_fk = EXCLUDED.tournament_template_fk,
tournament_stage_fk = EXCLUDED.tournament_stage_fk,
tournament_stage_name = EXCLUDED.tournament_stage_name,
tournament_name = EXCLUDED.tournament_name,
tournament_template_name = EXCLUDED.tournament_template_name,
sport_name = EXCLUDED.sport_name,
gender = EXCLUDED.gender,
start_date = EXCLUDED.start_date,
status_type = EXCLUDED.status_type,
status_desc_fk = EXCLUDED.status_desc_fk,
round_type_fk = EXCLUDED.round_type_fk,
updates_count = EXCLUDED.updates_count,
last_updated_at = EXCLUDED.last_updated_at,
updated_at = CURRENT_TIMESTAMP
RETURNING id, fixture_id, name, sport_fk, tournament_fk, tournament_template_fk, tournament_stage_fk, tournament_stage_name, tournament_name, tournament_template_name, sport_name, gender, start_date, status_type, status_desc_fk, round_type_fk, updates_count, last_updated_at, created_at, updated_at
`
type CreateEnetpulseFixtureParams struct {
FixtureID string `json:"fixture_id"`
Name string `json:"name"`
SportFk string `json:"sport_fk"`
TournamentFk pgtype.Text `json:"tournament_fk"`
TournamentTemplateFk pgtype.Text `json:"tournament_template_fk"`
TournamentStageFk pgtype.Text `json:"tournament_stage_fk"`
TournamentStageName pgtype.Text `json:"tournament_stage_name"`
TournamentName pgtype.Text `json:"tournament_name"`
TournamentTemplateName pgtype.Text `json:"tournament_template_name"`
SportName pgtype.Text `json:"sport_name"`
Gender pgtype.Text `json:"gender"`
StartDate pgtype.Timestamptz `json:"start_date"`
StatusType pgtype.Text `json:"status_type"`
StatusDescFk pgtype.Text `json:"status_desc_fk"`
RoundTypeFk pgtype.Text `json:"round_type_fk"`
UpdatesCount pgtype.Int4 `json:"updates_count"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
}
func (q *Queries) CreateEnetpulseFixture(ctx context.Context, arg CreateEnetpulseFixtureParams) (EnetpulseFixture, error) {
row := q.db.QueryRow(ctx, CreateEnetpulseFixture,
arg.FixtureID,
arg.Name,
arg.SportFk,
arg.TournamentFk,
arg.TournamentTemplateFk,
arg.TournamentStageFk,
arg.TournamentStageName,
arg.TournamentName,
arg.TournamentTemplateName,
arg.SportName,
arg.Gender,
arg.StartDate,
arg.StatusType,
arg.StatusDescFk,
arg.RoundTypeFk,
arg.UpdatesCount,
arg.LastUpdatedAt,
)
var i EnetpulseFixture
err := row.Scan(
&i.ID,
&i.FixtureID,
&i.Name,
&i.SportFk,
&i.TournamentFk,
&i.TournamentTemplateFk,
&i.TournamentStageFk,
&i.TournamentStageName,
&i.TournamentName,
&i.TournamentTemplateName,
&i.SportName,
&i.Gender,
&i.StartDate,
&i.StatusType,
&i.StatusDescFk,
&i.RoundTypeFk,
&i.UpdatesCount,
&i.LastUpdatedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const CreateEnetpulseOutcomeType = `-- name: CreateEnetpulseOutcomeType :one
INSERT INTO enetpulse_outcome_types (
outcome_type_id,
name,
description,
updates_count,
last_updated_at,
created_at,
updated_at
) VALUES (
$1, $2, $3, $4, $5, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
)
ON CONFLICT (outcome_type_id) DO UPDATE
SET
name = EXCLUDED.name,
description = EXCLUDED.description,
updates_count = EXCLUDED.updates_count,
last_updated_at = EXCLUDED.last_updated_at,
updated_at = CURRENT_TIMESTAMP
RETURNING id, outcome_type_id, name, description, updates_count, last_updated_at, created_at, updated_at
`
type CreateEnetpulseOutcomeTypeParams struct {
OutcomeTypeID string `json:"outcome_type_id"`
Name string `json:"name"`
Description pgtype.Text `json:"description"`
UpdatesCount pgtype.Int4 `json:"updates_count"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
}
func (q *Queries) CreateEnetpulseOutcomeType(ctx context.Context, arg CreateEnetpulseOutcomeTypeParams) (EnetpulseOutcomeType, error) {
row := q.db.QueryRow(ctx, CreateEnetpulseOutcomeType,
arg.OutcomeTypeID,
arg.Name,
arg.Description,
arg.UpdatesCount,
arg.LastUpdatedAt,
)
var i EnetpulseOutcomeType
err := row.Scan(
&i.ID,
&i.OutcomeTypeID,
&i.Name,
&i.Description,
&i.UpdatesCount,
&i.LastUpdatedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const CreateEnetpulsePreodds = `-- name: CreateEnetpulsePreodds :one
INSERT INTO enetpulse_preodds (
preodds_id,
event_fk,
outcome_type_fk,
outcome_scope_fk,
outcome_subtype_fk,
event_participant_number,
iparam,
iparam2,
dparam,
dparam2,
sparam,
updates_count,
last_updated_at,
created_at,
updated_at
) VALUES (
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP
)
ON CONFLICT (preodds_id) DO UPDATE
SET
event_fk = EXCLUDED.event_fk,
outcome_type_fk = EXCLUDED.outcome_type_fk,
outcome_scope_fk = EXCLUDED.outcome_scope_fk,
outcome_subtype_fk = EXCLUDED.outcome_subtype_fk,
event_participant_number = EXCLUDED.event_participant_number,
iparam = EXCLUDED.iparam,
iparam2 = EXCLUDED.iparam2,
dparam = EXCLUDED.dparam,
dparam2 = EXCLUDED.dparam2,
sparam = EXCLUDED.sparam,
updates_count = EXCLUDED.updates_count,
last_updated_at = EXCLUDED.last_updated_at,
updated_at = CURRENT_TIMESTAMP
RETURNING id, preodds_id, event_fk, outcome_type_fk, outcome_scope_fk, outcome_subtype_fk, event_participant_number, iparam, iparam2, dparam, dparam2, sparam, updates_count, last_updated_at, created_at, updated_at
`
type CreateEnetpulsePreoddsParams struct {
PreoddsID string `json:"preodds_id"`
EventFk int64 `json:"event_fk"`
OutcomeTypeFk pgtype.Int4 `json:"outcome_type_fk"`
OutcomeScopeFk pgtype.Int4 `json:"outcome_scope_fk"`
OutcomeSubtypeFk pgtype.Int4 `json:"outcome_subtype_fk"`
EventParticipantNumber pgtype.Int4 `json:"event_participant_number"`
Iparam pgtype.Text `json:"iparam"`
Iparam2 pgtype.Text `json:"iparam2"`
Dparam pgtype.Text `json:"dparam"`
Dparam2 pgtype.Text `json:"dparam2"`
Sparam pgtype.Text `json:"sparam"`
UpdatesCount pgtype.Int4 `json:"updates_count"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
}
func (q *Queries) CreateEnetpulsePreodds(ctx context.Context, arg CreateEnetpulsePreoddsParams) (EnetpulsePreodd, error) {
row := q.db.QueryRow(ctx, CreateEnetpulsePreodds,
arg.PreoddsID,
arg.EventFk,
arg.OutcomeTypeFk,
arg.OutcomeScopeFk,
arg.OutcomeSubtypeFk,
arg.EventParticipantNumber,
arg.Iparam,
arg.Iparam2,
arg.Dparam,
arg.Dparam2,
arg.Sparam,
arg.UpdatesCount,
arg.LastUpdatedAt,
)
var i EnetpulsePreodd
err := row.Scan(
&i.ID,
&i.PreoddsID,
&i.EventFk,
&i.OutcomeTypeFk,
&i.OutcomeScopeFk,
&i.OutcomeSubtypeFk,
&i.EventParticipantNumber,
&i.Iparam,
&i.Iparam2,
&i.Dparam,
&i.Dparam2,
&i.Sparam,
&i.UpdatesCount,
&i.LastUpdatedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const CreateEnetpulsePreoddsBettingOffer = `-- name: CreateEnetpulsePreoddsBettingOffer :one
INSERT INTO enetpulse_preodds_bettingoffers (
bettingoffer_id,
preodds_fk,
bettingoffer_status_fk,
odds_provider_fk,
odds,
odds_old,
active,
coupon_key,
updates_count,
last_updated_at,
created_at,
updated_at
) VALUES (
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP
)
ON CONFLICT (bettingoffer_id) DO UPDATE
SET
preodds_fk = EXCLUDED.preodds_fk,
bettingoffer_status_fk = EXCLUDED.bettingoffer_status_fk,
odds_provider_fk = EXCLUDED.odds_provider_fk,
odds = EXCLUDED.odds,
odds_old = EXCLUDED.odds_old,
active = EXCLUDED.active,
coupon_key = EXCLUDED.coupon_key,
updates_count = EXCLUDED.updates_count,
last_updated_at = EXCLUDED.last_updated_at,
updated_at = CURRENT_TIMESTAMP
RETURNING id, bettingoffer_id, preodds_fk, bettingoffer_status_fk, odds_provider_fk, odds, odds_old, active, coupon_key, updates_count, last_updated_at, created_at, updated_at
`
type CreateEnetpulsePreoddsBettingOfferParams struct {
BettingofferID string `json:"bettingoffer_id"`
PreoddsFk string `json:"preodds_fk"`
BettingofferStatusFk pgtype.Int4 `json:"bettingoffer_status_fk"`
OddsProviderFk pgtype.Int4 `json:"odds_provider_fk"`
Odds pgtype.Numeric `json:"odds"`
OddsOld pgtype.Numeric `json:"odds_old"`
Active pgtype.Bool `json:"active"`
CouponKey pgtype.Text `json:"coupon_key"`
UpdatesCount pgtype.Int4 `json:"updates_count"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
}
func (q *Queries) CreateEnetpulsePreoddsBettingOffer(ctx context.Context, arg CreateEnetpulsePreoddsBettingOfferParams) (EnetpulsePreoddsBettingoffer, error) {
row := q.db.QueryRow(ctx, CreateEnetpulsePreoddsBettingOffer,
arg.BettingofferID,
arg.PreoddsFk,
arg.BettingofferStatusFk,
arg.OddsProviderFk,
arg.Odds,
arg.OddsOld,
arg.Active,
arg.CouponKey,
arg.UpdatesCount,
arg.LastUpdatedAt,
)
var i EnetpulsePreoddsBettingoffer
err := row.Scan(
&i.ID,
&i.BettingofferID,
&i.PreoddsFk,
&i.BettingofferStatusFk,
&i.OddsProviderFk,
&i.Odds,
&i.OddsOld,
&i.Active,
&i.CouponKey,
&i.UpdatesCount,
&i.LastUpdatedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const CreateEnetpulseResult = `-- name: CreateEnetpulseResult :one
INSERT INTO enetpulse_results (
result_id,
name,
sport_fk,
tournament_fk,
tournament_template_fk,
tournament_stage_fk,
tournament_stage_name,
tournament_name,
tournament_template_name,
sport_name,
start_date,
status_type,
status_desc_fk,
round_type_fk,
updates_count,
last_updated_at,
round,
live,
venue_name,
livestats_plus,
livestats_type,
commentary,
lineup_confirmed,
verified,
spectators,
game_started,
first_half_ended,
second_half_started,
second_half_ended,
game_ended
) VALUES (
$1, $2, $3, $4, $5, $6,
$7, $8, $9, $10, $11,
$12, $13, $14, $15, $16,
$17, $18, $19, $20, $21,
$22, $23, $24, $25, $26,
$27, $28, $29, $30
)
ON CONFLICT (result_id) DO UPDATE
SET
name = EXCLUDED.name,
sport_fk = EXCLUDED.sport_fk,
tournament_fk = EXCLUDED.tournament_fk,
tournament_template_fk = EXCLUDED.tournament_template_fk,
tournament_stage_fk = EXCLUDED.tournament_stage_fk,
tournament_stage_name = EXCLUDED.tournament_stage_name,
tournament_name = EXCLUDED.tournament_name,
tournament_template_name = EXCLUDED.tournament_template_name,
sport_name = EXCLUDED.sport_name,
start_date = EXCLUDED.start_date,
status_type = EXCLUDED.status_type,
status_desc_fk = EXCLUDED.status_desc_fk,
round_type_fk = EXCLUDED.round_type_fk,
updates_count = EXCLUDED.updates_count,
last_updated_at = EXCLUDED.last_updated_at,
round = EXCLUDED.round,
live = EXCLUDED.live,
venue_name = EXCLUDED.venue_name,
livestats_plus = EXCLUDED.livestats_plus,
livestats_type = EXCLUDED.livestats_type,
commentary = EXCLUDED.commentary,
lineup_confirmed = EXCLUDED.lineup_confirmed,
verified = EXCLUDED.verified,
spectators = EXCLUDED.spectators,
game_started = EXCLUDED.game_started,
first_half_ended = EXCLUDED.first_half_ended,
second_half_started = EXCLUDED.second_half_started,
second_half_ended = EXCLUDED.second_half_ended,
game_ended = EXCLUDED.game_ended,
updated_at = CURRENT_TIMESTAMP
RETURNING id, result_id, name, sport_fk, tournament_fk, tournament_template_fk, tournament_stage_fk, tournament_stage_name, tournament_name, tournament_template_name, sport_name, start_date, status_type, status_desc_fk, round_type_fk, updates_count, last_updated_at, round, live, venue_name, livestats_plus, livestats_type, commentary, lineup_confirmed, verified, spectators, game_started, first_half_ended, second_half_started, second_half_ended, game_ended, created_at, updated_at
`
type CreateEnetpulseResultParams struct {
ResultID string `json:"result_id"`
Name string `json:"name"`
SportFk string `json:"sport_fk"`
TournamentFk pgtype.Text `json:"tournament_fk"`
TournamentTemplateFk pgtype.Text `json:"tournament_template_fk"`
TournamentStageFk pgtype.Text `json:"tournament_stage_fk"`
TournamentStageName pgtype.Text `json:"tournament_stage_name"`
TournamentName pgtype.Text `json:"tournament_name"`
TournamentTemplateName pgtype.Text `json:"tournament_template_name"`
SportName pgtype.Text `json:"sport_name"`
StartDate pgtype.Timestamptz `json:"start_date"`
StatusType pgtype.Text `json:"status_type"`
StatusDescFk pgtype.Text `json:"status_desc_fk"`
RoundTypeFk pgtype.Text `json:"round_type_fk"`
UpdatesCount pgtype.Int4 `json:"updates_count"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
Round pgtype.Text `json:"round"`
Live pgtype.Text `json:"live"`
VenueName pgtype.Text `json:"venue_name"`
LivestatsPlus pgtype.Text `json:"livestats_plus"`
LivestatsType pgtype.Text `json:"livestats_type"`
Commentary pgtype.Text `json:"commentary"`
LineupConfirmed pgtype.Bool `json:"lineup_confirmed"`
Verified pgtype.Bool `json:"verified"`
Spectators pgtype.Int4 `json:"spectators"`
GameStarted pgtype.Timestamptz `json:"game_started"`
FirstHalfEnded pgtype.Timestamptz `json:"first_half_ended"`
SecondHalfStarted pgtype.Timestamptz `json:"second_half_started"`
SecondHalfEnded pgtype.Timestamptz `json:"second_half_ended"`
GameEnded pgtype.Timestamptz `json:"game_ended"`
}
func (q *Queries) CreateEnetpulseResult(ctx context.Context, arg CreateEnetpulseResultParams) (EnetpulseResult, error) {
row := q.db.QueryRow(ctx, CreateEnetpulseResult,
arg.ResultID,
arg.Name,
arg.SportFk,
arg.TournamentFk,
arg.TournamentTemplateFk,
arg.TournamentStageFk,
arg.TournamentStageName,
arg.TournamentName,
arg.TournamentTemplateName,
arg.SportName,
arg.StartDate,
arg.StatusType,
arg.StatusDescFk,
arg.RoundTypeFk,
arg.UpdatesCount,
arg.LastUpdatedAt,
arg.Round,
arg.Live,
arg.VenueName,
arg.LivestatsPlus,
arg.LivestatsType,
arg.Commentary,
arg.LineupConfirmed,
arg.Verified,
arg.Spectators,
arg.GameStarted,
arg.FirstHalfEnded,
arg.SecondHalfStarted,
arg.SecondHalfEnded,
arg.GameEnded,
)
var i EnetpulseResult
err := row.Scan(
&i.ID,
&i.ResultID,
&i.Name,
&i.SportFk,
&i.TournamentFk,
&i.TournamentTemplateFk,
&i.TournamentStageFk,
&i.TournamentStageName,
&i.TournamentName,
&i.TournamentTemplateName,
&i.SportName,
&i.StartDate,
&i.StatusType,
&i.StatusDescFk,
&i.RoundTypeFk,
&i.UpdatesCount,
&i.LastUpdatedAt,
&i.Round,
&i.Live,
&i.VenueName,
&i.LivestatsPlus,
&i.LivestatsType,
&i.Commentary,
&i.LineupConfirmed,
&i.Verified,
&i.Spectators,
&i.GameStarted,
&i.FirstHalfEnded,
&i.SecondHalfStarted,
&i.SecondHalfEnded,
&i.GameEnded,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const CreateEnetpulseSport = `-- name: CreateEnetpulseSport :one
INSERT INTO enetpulse_sports (
sport_id,
@ -63,6 +576,7 @@ func (q *Queries) CreateEnetpulseSport(ctx context.Context, arg CreateEnetpulseS
}
const CreateEnetpulseTournament = `-- name: CreateEnetpulseTournament :one
INSERT INTO enetpulse_tournaments (
tournament_id,
name,
@ -90,6 +604,8 @@ type CreateEnetpulseTournamentParams struct {
Status pgtype.Int4 `json:"status"`
}
// -- name: DeleteEnetpulseTournamentTemplateByID :exec
// DELETE FROM enetpulse_tournament_templates WHERE template_id = $1;
func (q *Queries) CreateEnetpulseTournament(ctx context.Context, arg CreateEnetpulseTournamentParams) (EnetpulseTournament, error) {
row := q.db.QueryRow(ctx, CreateEnetpulseTournament,
arg.TournamentID,
@ -250,6 +766,231 @@ func (q *Queries) CreateEnetpulseTournamentTemplate(ctx context.Context, arg Cre
return i, err
}
const GetAllEnetpulseFixtures = `-- name: GetAllEnetpulseFixtures :many
SELECT id, fixture_id, name, sport_fk, tournament_fk, tournament_template_fk, tournament_stage_fk, tournament_stage_name, tournament_name, tournament_template_name, sport_name, gender, start_date, status_type, status_desc_fk, round_type_fk, updates_count, last_updated_at, created_at, updated_at
FROM enetpulse_fixtures
ORDER BY created_at DESC
`
func (q *Queries) GetAllEnetpulseFixtures(ctx context.Context) ([]EnetpulseFixture, error) {
rows, err := q.db.Query(ctx, GetAllEnetpulseFixtures)
if err != nil {
return nil, err
}
defer rows.Close()
var items []EnetpulseFixture
for rows.Next() {
var i EnetpulseFixture
if err := rows.Scan(
&i.ID,
&i.FixtureID,
&i.Name,
&i.SportFk,
&i.TournamentFk,
&i.TournamentTemplateFk,
&i.TournamentStageFk,
&i.TournamentStageName,
&i.TournamentName,
&i.TournamentTemplateName,
&i.SportName,
&i.Gender,
&i.StartDate,
&i.StatusType,
&i.StatusDescFk,
&i.RoundTypeFk,
&i.UpdatesCount,
&i.LastUpdatedAt,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllEnetpulseOutcomeTypes = `-- name: GetAllEnetpulseOutcomeTypes :many
SELECT id, outcome_type_id, name, description, updates_count, last_updated_at, created_at, updated_at
FROM enetpulse_outcome_types
ORDER BY created_at DESC
`
func (q *Queries) GetAllEnetpulseOutcomeTypes(ctx context.Context) ([]EnetpulseOutcomeType, error) {
rows, err := q.db.Query(ctx, GetAllEnetpulseOutcomeTypes)
if err != nil {
return nil, err
}
defer rows.Close()
var items []EnetpulseOutcomeType
for rows.Next() {
var i EnetpulseOutcomeType
if err := rows.Scan(
&i.ID,
&i.OutcomeTypeID,
&i.Name,
&i.Description,
&i.UpdatesCount,
&i.LastUpdatedAt,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllEnetpulsePreodds = `-- name: GetAllEnetpulsePreodds :many
SELECT id, preodds_id, event_fk, outcome_type_fk, outcome_scope_fk, outcome_subtype_fk, event_participant_number, iparam, iparam2, dparam, dparam2, sparam, updates_count, last_updated_at, created_at, updated_at
FROM enetpulse_preodds
ORDER BY created_at DESC
`
func (q *Queries) GetAllEnetpulsePreodds(ctx context.Context) ([]EnetpulsePreodd, error) {
rows, err := q.db.Query(ctx, GetAllEnetpulsePreodds)
if err != nil {
return nil, err
}
defer rows.Close()
var items []EnetpulsePreodd
for rows.Next() {
var i EnetpulsePreodd
if err := rows.Scan(
&i.ID,
&i.PreoddsID,
&i.EventFk,
&i.OutcomeTypeFk,
&i.OutcomeScopeFk,
&i.OutcomeSubtypeFk,
&i.EventParticipantNumber,
&i.Iparam,
&i.Iparam2,
&i.Dparam,
&i.Dparam2,
&i.Sparam,
&i.UpdatesCount,
&i.LastUpdatedAt,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllEnetpulsePreoddsBettingOffers = `-- name: GetAllEnetpulsePreoddsBettingOffers :many
SELECT id, bettingoffer_id, preodds_fk, bettingoffer_status_fk, odds_provider_fk, odds, odds_old, active, coupon_key, updates_count, last_updated_at, created_at, updated_at
FROM enetpulse_preodds_bettingoffers
ORDER BY created_at DESC
`
func (q *Queries) GetAllEnetpulsePreoddsBettingOffers(ctx context.Context) ([]EnetpulsePreoddsBettingoffer, error) {
rows, err := q.db.Query(ctx, GetAllEnetpulsePreoddsBettingOffers)
if err != nil {
return nil, err
}
defer rows.Close()
var items []EnetpulsePreoddsBettingoffer
for rows.Next() {
var i EnetpulsePreoddsBettingoffer
if err := rows.Scan(
&i.ID,
&i.BettingofferID,
&i.PreoddsFk,
&i.BettingofferStatusFk,
&i.OddsProviderFk,
&i.Odds,
&i.OddsOld,
&i.Active,
&i.CouponKey,
&i.UpdatesCount,
&i.LastUpdatedAt,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllEnetpulseResults = `-- name: GetAllEnetpulseResults :many
SELECT id, result_id, name, sport_fk, tournament_fk, tournament_template_fk, tournament_stage_fk, tournament_stage_name, tournament_name, tournament_template_name, sport_name, start_date, status_type, status_desc_fk, round_type_fk, updates_count, last_updated_at, round, live, venue_name, livestats_plus, livestats_type, commentary, lineup_confirmed, verified, spectators, game_started, first_half_ended, second_half_started, second_half_ended, game_ended, created_at, updated_at
FROM enetpulse_results
ORDER BY created_at DESC
`
func (q *Queries) GetAllEnetpulseResults(ctx context.Context) ([]EnetpulseResult, error) {
rows, err := q.db.Query(ctx, GetAllEnetpulseResults)
if err != nil {
return nil, err
}
defer rows.Close()
var items []EnetpulseResult
for rows.Next() {
var i EnetpulseResult
if err := rows.Scan(
&i.ID,
&i.ResultID,
&i.Name,
&i.SportFk,
&i.TournamentFk,
&i.TournamentTemplateFk,
&i.TournamentStageFk,
&i.TournamentStageName,
&i.TournamentName,
&i.TournamentTemplateName,
&i.SportName,
&i.StartDate,
&i.StatusType,
&i.StatusDescFk,
&i.RoundTypeFk,
&i.UpdatesCount,
&i.LastUpdatedAt,
&i.Round,
&i.Live,
&i.VenueName,
&i.LivestatsPlus,
&i.LivestatsType,
&i.Commentary,
&i.LineupConfirmed,
&i.Verified,
&i.Spectators,
&i.GameStarted,
&i.FirstHalfEnded,
&i.SecondHalfStarted,
&i.SecondHalfEnded,
&i.GameEnded,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllEnetpulseSports = `-- name: GetAllEnetpulseSports :many
SELECT
id,

View File

@ -256,6 +256,143 @@ type DisabledOdd struct {
CreatedAt pgtype.Timestamp `json:"created_at"`
}
type EnetpulseFixture struct {
ID int64 `json:"id"`
FixtureID string `json:"fixture_id"`
Name string `json:"name"`
SportFk string `json:"sport_fk"`
TournamentFk pgtype.Text `json:"tournament_fk"`
TournamentTemplateFk pgtype.Text `json:"tournament_template_fk"`
TournamentStageFk pgtype.Text `json:"tournament_stage_fk"`
TournamentStageName pgtype.Text `json:"tournament_stage_name"`
TournamentName pgtype.Text `json:"tournament_name"`
TournamentTemplateName pgtype.Text `json:"tournament_template_name"`
SportName pgtype.Text `json:"sport_name"`
Gender pgtype.Text `json:"gender"`
StartDate pgtype.Timestamptz `json:"start_date"`
StatusType pgtype.Text `json:"status_type"`
StatusDescFk pgtype.Text `json:"status_desc_fk"`
RoundTypeFk pgtype.Text `json:"round_type_fk"`
UpdatesCount pgtype.Int4 `json:"updates_count"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type EnetpulseOutcomeType struct {
ID int64 `json:"id"`
OutcomeTypeID string `json:"outcome_type_id"`
Name string `json:"name"`
Description pgtype.Text `json:"description"`
UpdatesCount pgtype.Int4 `json:"updates_count"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type EnetpulsePreodd struct {
ID int64 `json:"id"`
PreoddsID string `json:"preodds_id"`
EventFk int64 `json:"event_fk"`
OutcomeTypeFk pgtype.Int4 `json:"outcome_type_fk"`
OutcomeScopeFk pgtype.Int4 `json:"outcome_scope_fk"`
OutcomeSubtypeFk pgtype.Int4 `json:"outcome_subtype_fk"`
EventParticipantNumber pgtype.Int4 `json:"event_participant_number"`
Iparam pgtype.Text `json:"iparam"`
Iparam2 pgtype.Text `json:"iparam2"`
Dparam pgtype.Text `json:"dparam"`
Dparam2 pgtype.Text `json:"dparam2"`
Sparam pgtype.Text `json:"sparam"`
UpdatesCount pgtype.Int4 `json:"updates_count"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type EnetpulsePreoddsBettingoffer struct {
ID int64 `json:"id"`
BettingofferID string `json:"bettingoffer_id"`
PreoddsFk string `json:"preodds_fk"`
BettingofferStatusFk pgtype.Int4 `json:"bettingoffer_status_fk"`
OddsProviderFk pgtype.Int4 `json:"odds_provider_fk"`
Odds pgtype.Numeric `json:"odds"`
OddsOld pgtype.Numeric `json:"odds_old"`
Active pgtype.Bool `json:"active"`
CouponKey pgtype.Text `json:"coupon_key"`
UpdatesCount pgtype.Int4 `json:"updates_count"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type EnetpulseResult struct {
ID int64 `json:"id"`
ResultID string `json:"result_id"`
Name string `json:"name"`
SportFk string `json:"sport_fk"`
TournamentFk pgtype.Text `json:"tournament_fk"`
TournamentTemplateFk pgtype.Text `json:"tournament_template_fk"`
TournamentStageFk pgtype.Text `json:"tournament_stage_fk"`
TournamentStageName pgtype.Text `json:"tournament_stage_name"`
TournamentName pgtype.Text `json:"tournament_name"`
TournamentTemplateName pgtype.Text `json:"tournament_template_name"`
SportName pgtype.Text `json:"sport_name"`
StartDate pgtype.Timestamptz `json:"start_date"`
StatusType pgtype.Text `json:"status_type"`
StatusDescFk pgtype.Text `json:"status_desc_fk"`
RoundTypeFk pgtype.Text `json:"round_type_fk"`
UpdatesCount pgtype.Int4 `json:"updates_count"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
Round pgtype.Text `json:"round"`
Live pgtype.Text `json:"live"`
VenueName pgtype.Text `json:"venue_name"`
LivestatsPlus pgtype.Text `json:"livestats_plus"`
LivestatsType pgtype.Text `json:"livestats_type"`
Commentary pgtype.Text `json:"commentary"`
LineupConfirmed pgtype.Bool `json:"lineup_confirmed"`
Verified pgtype.Bool `json:"verified"`
Spectators pgtype.Int4 `json:"spectators"`
GameStarted pgtype.Timestamptz `json:"game_started"`
FirstHalfEnded pgtype.Timestamptz `json:"first_half_ended"`
SecondHalfStarted pgtype.Timestamptz `json:"second_half_started"`
SecondHalfEnded pgtype.Timestamptz `json:"second_half_ended"`
GameEnded pgtype.Timestamptz `json:"game_ended"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type EnetpulseResultParticipant struct {
ID int64 `json:"id"`
ParticipantMapID string `json:"participant_map_id"`
ResultFk string `json:"result_fk"`
ParticipantFk string `json:"participant_fk"`
Number pgtype.Int4 `json:"number"`
Name pgtype.Text `json:"name"`
Gender pgtype.Text `json:"gender"`
Type pgtype.Text `json:"type"`
CountryFk pgtype.Text `json:"country_fk"`
CountryName pgtype.Text `json:"country_name"`
OrdinaryTime pgtype.Text `json:"ordinary_time"`
RunningScore pgtype.Text `json:"running_score"`
Halftime pgtype.Text `json:"halftime"`
FinalResult pgtype.Text `json:"final_result"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type EnetpulseResultReferee struct {
ID int64 `json:"id"`
ResultFk string `json:"result_fk"`
RefereeFk pgtype.Text `json:"referee_fk"`
Assistant1RefereeFk pgtype.Text `json:"assistant1_referee_fk"`
Assistant2RefereeFk pgtype.Text `json:"assistant2_referee_fk"`
FourthRefereeFk pgtype.Text `json:"fourth_referee_fk"`
Var1RefereeFk pgtype.Text `json:"var1_referee_fk"`
Var2RefereeFk pgtype.Text `json:"var2_referee_fk"`
LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type EnetpulseSport struct {
ID int64 `json:"id"`
SportID string `json:"sport_id"`

View File

@ -46,8 +46,9 @@ var (
)
type EnetPulseConfig struct {
UserName string `mapstructure:"username"` // "https://api.aleaplay.com"
Token string `mapstructure:"token"` // Your operator ID with Alea
UserName string `mapstructure:"username"`
Token string `mapstructure:"token"`
ProviderID string `mapstructure:"provider_id"`
}
type AleaPlayConfig struct {
@ -188,6 +189,7 @@ func (c *Config) loadEnv() error {
c.EnetPulseConfig.Token = os.Getenv("ENETPULSE_TOKEN")
c.EnetPulseConfig.UserName = os.Getenv("ENETPULSE_USERNAME")
c.EnetPulseConfig.ProviderID = os.Getenv("ENETPULSE_PROVIDER_ID")
c.CHAPA_TRANSFER_TYPE = os.Getenv("CHAPA_TRANSFER_TYPE")
c.CHAPA_PAYMENT_TYPE = os.Getenv("CHAPA_PAYMENT_TYPE")
@ -427,34 +429,34 @@ func (c *Config) loadEnv() error {
Platform: popOKPlatform,
}
AtlasBaseUrl := os.Getenv("ATLAS_BASE_URL")
if AtlasBaseUrl == "" {
return ErrInvalidAtlasBaseUrl
}
AtlasSecretKey := os.Getenv("ATLAS_SECRET_KEY")
if AtlasSecretKey == "" {
return ErrInvalidAtlasSecretKey
}
AtlasBrandID := os.Getenv("ATLAS_BRAND_ID")
if AtlasBrandID == "" {
return ErrInvalidAtlasBrandID
}
AtlasPartnerID := os.Getenv("ATLAS_PARTNER_ID")
if AtlasPartnerID == "" {
return ErrInvalidAtlasPartnerID
}
AtlasOperatorID := os.Getenv("ATLAS_OPERATOR_ID")
if AtlasOperatorID == "" {
return ErrInvalidAtlasOperatorID
}
// AtlasBaseUrl := os.Getenv("ATLAS_BASE_URL")
// if AtlasBaseUrl == "" {
// return ErrInvalidAtlasBaseUrl
// }
// AtlasSecretKey := os.Getenv("ATLAS_SECRET_KEY")
// if AtlasSecretKey == "" {
// return ErrInvalidAtlasSecretKey
// }
// AtlasBrandID := os.Getenv("ATLAS_BRAND_ID")
// if AtlasBrandID == "" {
// return ErrInvalidAtlasBrandID
// }
// AtlasPartnerID := os.Getenv("ATLAS_PARTNER_ID")
// if AtlasPartnerID == "" {
// return ErrInvalidAtlasPartnerID
// }
// AtlasOperatorID := os.Getenv("ATLAS_OPERATOR_ID")
// if AtlasOperatorID == "" {
// return ErrInvalidAtlasOperatorID
// }
c.Atlas = AtlasConfig{
BaseURL: AtlasBaseUrl,
SecretKey: AtlasSecretKey,
CasinoID: AtlasBrandID,
PartnerID: AtlasPartnerID,
OperatorID: AtlasOperatorID,
}
// c.Atlas = AtlasConfig{
// BaseURL: AtlasBaseUrl,
// SecretKey: AtlasSecretKey,
// CasinoID: AtlasBrandID,
// PartnerID: AtlasPartnerID,
// OperatorID: AtlasOperatorID,
// }
betToken := os.Getenv("BET365_TOKEN")
if betToken == "" {

View File

@ -462,3 +462,209 @@ type CreateEnetpulseTournamentStage struct {
CountryName string `json:"country_name"` // country name from API
Status int `json:"status"` // active/inactive
}
// For insertion
type CreateEnetpulseFixture struct {
FixtureID string
Name string
SportFK string
TournamentFK string
TournamentTemplateFK string
TournamentStageFK string
TournamentStageName string
TournamentName string
TournamentTemplateName string
SportName string
Gender string
StartDate time.Time
StatusType string
StatusDescFK string
RoundTypeFK string
UpdatesCount int
LastUpdatedAt time.Time
}
// Full domain model
type EnetpulseFixture struct {
FixtureID string
Name string
SportFK string
TournamentFK string
TournamentTemplateFK string
TournamentStageFK string
TournamentStageName string
TournamentName string
TournamentTemplateName string
SportName string
Gender string
StartDate time.Time
StatusType string
StatusDescFK string
RoundTypeFK string
UpdatesCount int
LastUpdatedAt time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type CreateEnetpulseResult struct {
ResultID string `json:"result_id"`
Name string `json:"name"`
SportFK string `json:"sport_fk"`
TournamentFK string `json:"tournament_fk"`
TournamentTemplateFK string `json:"tournament_template_fk"`
TournamentStageFK string `json:"tournament_stage_fk"`
TournamentStageName string `json:"tournament_stage_name"`
TournamentName string `json:"tournament_name"`
TournamentTemplateName string `json:"tournament_template_name"`
SportName string `json:"sport_name"`
StartDate time.Time `json:"start_date"`
StatusType string `json:"status_type"`
StatusDescFK string `json:"status_desc_fk"`
RoundTypeFK string `json:"round_type_fk"`
UpdatesCount int32 `json:"updates_count"`
LastUpdatedAt time.Time `json:"last_updated_at"`
// Optional metadata
Round string `json:"round"`
Live string `json:"live"`
VenueName string `json:"venue_name"`
LivestatsPlus string `json:"livestats_plus"`
LivestatsType string `json:"livestats_type"`
Commentary string `json:"commentary"`
LineupConfirmed bool `json:"lineup_confirmed"`
Verified bool `json:"verified"`
Spectators int32 `json:"spectators"`
// Time-related metadata
GameStarted *time.Time `json:"game_started"`
FirstHalfEnded *time.Time `json:"first_half_ended"`
SecondHalfStarted *time.Time `json:"second_half_started"`
SecondHalfEnded *time.Time `json:"second_half_ended"`
GameEnded *time.Time `json:"game_ended"`
}
// ✅ Used for reading result records
type EnetpulseResult struct {
ID int64 `json:"id"`
ResultID string `json:"result_id"`
Name string `json:"name"`
SportFK string `json:"sport_fk"`
TournamentFK string `json:"tournament_fk"`
TournamentTemplateFK string `json:"tournament_template_fk"`
TournamentStageFK string `json:"tournament_stage_fk"`
TournamentStageName string `json:"tournament_stage_name"`
TournamentName string `json:"tournament_name"`
TournamentTemplateName string `json:"tournament_template_name"`
SportName string `json:"sport_name"`
StartDate time.Time `json:"start_date"`
StatusType string `json:"status_type"`
StatusDescFK string `json:"status_desc_fk"`
RoundTypeFK string `json:"round_type_fk"`
UpdatesCount int32 `json:"updates_count"`
LastUpdatedAt *time.Time `json:"last_updated_at"`
Round string `json:"round"`
Live string `json:"live"`
VenueName string `json:"venue_name"`
LivestatsPlus string `json:"livestats_plus"`
LivestatsType string `json:"livestats_type"`
Commentary string `json:"commentary"`
LineupConfirmed bool `json:"lineup_confirmed"`
Verified bool `json:"verified"`
Spectators int32 `json:"spectators"`
GameStarted *time.Time `json:"game_started"`
FirstHalfEnded *time.Time `json:"first_half_ended"`
SecondHalfStarted *time.Time `json:"second_half_started"`
SecondHalfEnded *time.Time `json:"second_half_ended"`
GameEnded *time.Time `json:"game_ended"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
}
type EnetpulseOutcomeType struct {
ID int64 `json:"id"`
OutcomeTypeID string `json:"outcome_type_id"` // changed from int64 → string
Name string `json:"name"`
Description string `json:"description"`
UpdatesCount int32 `json:"updates_count"`
LastUpdatedAt time.Time `json:"last_updated_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// CreateEnetpulseOutcomeType represents the payload to create or update an outcome type.
type CreateEnetpulseOutcomeType struct {
OutcomeTypeID string `json:"outcome_type_id"` // changed from int64 → string
Name string `json:"name"`
Description string `json:"description"`
UpdatesCount int32 `json:"updates_count"`
LastUpdatedAt time.Time `json:"last_updated_at"`
}
type EnetpulsePreodds struct {
PreoddsID string `json:"preodds_id"`
EventFK string `json:"event_fk"`
OutcomeTypeFK string `json:"outcome_type_fk"`
OutcomeScopeFK string `json:"outcome_scope_fk"`
OutcomeSubtypeFK string `json:"outcome_subtype_fk"`
EventParticipantNumber int `json:"event_participant_number"`
IParam string `json:"iparam"`
IParam2 string `json:"iparam2"`
DParam string `json:"dparam"`
DParam2 string `json:"dparam2"`
SParam string `json:"sparam"`
UpdatesCount int `json:"updates_count"`
LastUpdatedAt time.Time `json:"last_updated_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// CreateEnetpulsePreodds is used when inserting a new preodds record
type CreateEnetpulsePreodds struct {
PreoddsID string `json:"preodds_id"`
EventFK string `json:"event_fk"`
OutcomeTypeFK string `json:"outcome_type_fk"`
OutcomeScopeFK string `json:"outcome_scope_fk"`
OutcomeSubtypeFK string `json:"outcome_subtype_fk"`
EventParticipantNumber int `json:"event_participant_number"`
IParam string `json:"iparam"`
IParam2 string `json:"iparam2"`
DParam string `json:"dparam"`
DParam2 string `json:"dparam2"`
SParam string `json:"sparam"`
UpdatesCount int `json:"updates_count"`
LastUpdatedAt time.Time `json:"last_updated_at"`
}
type CreateEnetpulsePreoddsBettingOffer struct {
BettingOfferID string
PreoddsFK string
BettingOfferStatusFK int32
OddsProviderFK int32
Odds float64
OddsOld float64
Active string
CouponKey string
UpdatesCount int
LastUpdatedAt time.Time
}
// EnetpulsePreoddsBettingOffer represents the DB record of a betting offer
type EnetpulsePreoddsBettingOffer struct {
ID int64 `json:"id"`
BettingOfferID string `json:"betting_offer_id"`
PreoddsFK string `json:"preodds_fk"`
BettingOfferStatusFK int32 `json:"betting_offer_status_fk"`
OddsProviderFK int32 `json:"odds_provider_fk"`
Odds float64 `json:"odds"`
OddsOld float64 `json:"odds_old"`
Active string `json:"active"`
CouponKey string `json:"coupon_key"`
UpdatesCount int `json:"updates_count"`
LastUpdatedAt time.Time `json:"last_updated_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

View File

@ -3,6 +3,9 @@ package repository
import (
"context"
"fmt"
"math"
"math/big"
"strconv"
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
@ -140,6 +143,165 @@ func (s *Store) GetTournamentStagesByTournamentFK(ctx context.Context, tournamen
return stages, nil
}
// Create a new fixture
func (s *Store) CreateEnetpulseFixture(
ctx context.Context,
fixture domain.CreateEnetpulseFixture,
) (domain.EnetpulseFixture, error) {
// Convert domain model to DB params (sqlc-generated struct or parameters)
dbFixture, err := s.queries.CreateEnetpulseFixture(
ctx,
ConvertCreateEnetpulseFixture(fixture), // your converter
)
if err != nil {
return domain.EnetpulseFixture{}, err
}
return ConvertDBEnetpulseFixture(dbFixture), nil // convert DB row to domain
}
// Fetch all fixtures
func (s *Store) GetAllEnetpulseFixtures(ctx context.Context) ([]domain.EnetpulseFixture, error) {
dbFixtures, err := s.queries.GetAllEnetpulseFixtures(ctx)
if err != nil {
return nil, err
}
var fixtures []domain.EnetpulseFixture
for _, dbFixture := range dbFixtures {
fixtures = append(fixtures, ConvertDBEnetpulseFixture(dbFixture))
}
return fixtures, nil
}
func (s *Store) CreateEnetpulseResult(
ctx context.Context,
result domain.CreateEnetpulseResult,
) (domain.EnetpulseResult, error) {
dbResult, err := s.queries.CreateEnetpulseResult(
ctx,
ConvertCreateEnetpulseResult(result),
)
if err != nil {
return domain.EnetpulseResult{}, err
}
return ConvertDBEnetpulseResult(dbResult), nil
}
// GetAllEnetpulseResults retrieves all Enetpulse results.
func (s *Store) GetAllEnetpulseResults(ctx context.Context) ([]domain.EnetpulseResult, error) {
dbResults, err := s.queries.GetAllEnetpulseResults(ctx)
if err != nil {
return nil, err
}
results := make([]domain.EnetpulseResult, 0, len(dbResults))
for _, dbR := range dbResults {
results = append(results, ConvertDBEnetpulseResult(dbR))
}
return results, nil
}
// CreateEnetpulseOutcomeType inserts or updates an EnetPulse outcome type record.
func (s *Store) CreateEnetpulseOutcomeType(
ctx context.Context,
outcomeType domain.CreateEnetpulseOutcomeType,
) (domain.EnetpulseOutcomeType, error) {
dbOutcome, err := s.queries.CreateEnetpulseOutcomeType(
ctx,
ConvertCreateEnetpulseOutcomeType(outcomeType),
)
if err != nil {
return domain.EnetpulseOutcomeType{}, err
}
return ConvertDBEnetpulseOutcomeType(dbOutcome), nil
}
// GetAllEnetpulseOutcomeTypes retrieves all outcome types.
func (s *Store) GetAllEnetpulseOutcomeTypes(ctx context.Context) ([]domain.EnetpulseOutcomeType, error) {
dbOutcomes, err := s.queries.GetAllEnetpulseOutcomeTypes(ctx)
if err != nil {
return nil, err
}
outcomes := make([]domain.EnetpulseOutcomeType, 0, len(dbOutcomes))
for _, dbO := range dbOutcomes {
outcomes = append(outcomes, ConvertDBEnetpulseOutcomeType(dbO))
}
return outcomes, nil
}
// CreateEnetpulsePreodds inserts or updates a preodds record.
func (s *Store) CreateEnetpulsePreodds(
ctx context.Context,
preodds domain.CreateEnetpulsePreodds,
) (domain.EnetpulsePreodds, error) {
// Convert domain to DB params
params, err := ConvertCreateEnetpulsePreodds(preodds)
if err != nil {
return domain.EnetpulsePreodds{}, err
}
// Insert into DB
dbPreodds, err := s.queries.CreateEnetpulsePreodds(ctx, params)
if err != nil {
return domain.EnetpulsePreodds{}, err
}
return ConvertDBEnetpulsePreodds(dbPreodds), nil
}
// GetAllEnetpulsePreodds retrieves all preodds records.
func (s *Store) GetAllEnetpulsePreodds(ctx context.Context) ([]domain.EnetpulsePreodds, error) {
dbPreodds, err := s.queries.GetAllEnetpulsePreodds(ctx)
if err != nil {
return nil, err
}
preodds := make([]domain.EnetpulsePreodds, 0, len(dbPreodds))
for _, dbP := range dbPreodds {
preodds = append(preodds, ConvertDBEnetpulsePreodds(dbP))
}
return preodds, nil
}
// CreateEnetpulsePreoddsBettingOffer inserts or updates a betting offer
func (s *Store) CreateEnetpulsePreoddsBettingOffer(
ctx context.Context,
bettingOffer domain.CreateEnetpulsePreoddsBettingOffer,
) (domain.EnetpulsePreoddsBettingOffer, error) {
params := ConvertCreateEnetpulsePreoddsBettingOffer(bettingOffer)
dbOffer, err := s.queries.CreateEnetpulsePreoddsBettingOffer(ctx, params)
if err != nil {
return domain.EnetpulsePreoddsBettingOffer{}, err
}
return ConvertDBEnetpulsePreoddsBettingOffer(dbOffer), nil
}
// GetAllEnetpulsePreoddsBettingOffers retrieves all betting offers
func (s *Store) GetAllEnetpulsePreoddsBettingOffers(ctx context.Context) ([]domain.EnetpulsePreoddsBettingOffer, error) {
dbOffers, err := s.queries.GetAllEnetpulsePreoddsBettingOffers(ctx)
if err != nil {
return nil, err
}
offers := make([]domain.EnetpulsePreoddsBettingOffer, 0, len(dbOffers))
for _, dbO := range dbOffers {
offers = append(offers, ConvertDBEnetpulsePreoddsBettingOffer(dbO))
}
return offers, nil
}
// func ConvertCreateEnetpulseTournamentStage(stage domain.CreateEnetpulseTournamentStage) dbgen.EnetpulseTournamentStage {
// return dbgen.EnetpulseTournamentStage{
// StageID: stage.StageID,
@ -157,6 +319,54 @@ func (s *Store) GetTournamentStagesByTournamentFK(ctx context.Context, tournamen
// }
// }
// ConvertCreateEnetpulseFixture converts the domain model to the SQLC params struct.
func ConvertCreateEnetpulseFixture(f domain.CreateEnetpulseFixture) dbgen.CreateEnetpulseFixtureParams {
return dbgen.CreateEnetpulseFixtureParams{
FixtureID: f.FixtureID,
Name: f.Name,
SportFk: f.SportFK,
TournamentFk: pgtype.Text{String: f.TournamentFK, Valid: f.TournamentFK != ""},
TournamentTemplateFk: pgtype.Text{String: f.TournamentTemplateFK, Valid: f.TournamentTemplateFK != ""},
TournamentStageFk: pgtype.Text{String: f.TournamentStageFK, Valid: f.TournamentStageFK != ""},
TournamentStageName: pgtype.Text{String: f.TournamentStageName, Valid: f.TournamentStageName != ""},
TournamentName: pgtype.Text{String: f.TournamentName, Valid: f.TournamentName != ""},
TournamentTemplateName: pgtype.Text{String: f.TournamentTemplateName, Valid: f.TournamentTemplateName != ""},
SportName: pgtype.Text{String: f.SportName, Valid: f.SportName != ""},
Gender: pgtype.Text{String: f.Gender, Valid: f.Gender != ""},
StartDate: pgtype.Timestamptz{Time: f.StartDate, Valid: !f.StartDate.IsZero()},
StatusType: pgtype.Text{String: f.StatusType, Valid: f.StatusType != ""},
StatusDescFk: pgtype.Text{String: f.StatusDescFK, Valid: f.StatusDescFK != ""},
RoundTypeFk: pgtype.Text{String: f.RoundTypeFK, Valid: f.RoundTypeFK != ""},
UpdatesCount: pgtype.Int4{Int32: int32(f.UpdatesCount), Valid: true},
LastUpdatedAt: pgtype.Timestamptz{Time: f.LastUpdatedAt, Valid: !f.LastUpdatedAt.IsZero()},
}
}
// ConvertDBEnetpulseFixture converts the DB row to the domain model.
func ConvertDBEnetpulseFixture(dbF dbgen.EnetpulseFixture) domain.EnetpulseFixture {
return domain.EnetpulseFixture{
FixtureID: dbF.FixtureID,
Name: dbF.Name,
SportFK: dbF.SportFk,
TournamentFK: dbF.TournamentFk.String,
TournamentTemplateFK: dbF.TournamentTemplateFk.String,
TournamentStageFK: dbF.TournamentStageFk.String,
TournamentStageName: dbF.TournamentStageName.String,
TournamentName: dbF.TournamentName.String,
TournamentTemplateName: dbF.TournamentTemplateName.String,
SportName: dbF.SportName.String,
Gender: dbF.Gender.String,
StartDate: dbF.StartDate.Time,
StatusType: dbF.StatusType.String,
StatusDescFK: dbF.StatusDescFk.String,
RoundTypeFK: dbF.RoundTypeFk.String,
UpdatesCount: int(dbF.UpdatesCount.Int32),
LastUpdatedAt: dbF.LastUpdatedAt.Time,
CreatedAt: dbF.CreatedAt.Time,
UpdatedAt: dbF.UpdatedAt.Time,
}
}
func ConvertCreateEnetpulseTournamentStage(stage domain.CreateEnetpulseTournamentStage) dbgen.CreateEnetpulseTournamentStageParams {
return dbgen.CreateEnetpulseTournamentStageParams{
StageID: stage.StageID,
@ -321,3 +531,222 @@ func ConvertDBEnetpulseTournament(dbT dbgen.EnetpulseTournament) domain.Enetpuls
}(),
}
}
func ConvertCreateEnetpulseResult(input domain.CreateEnetpulseResult) dbgen.CreateEnetpulseResultParams {
return dbgen.CreateEnetpulseResultParams{
ResultID: input.ResultID,
Name: input.Name,
SportFk: input.SportFK,
TournamentFk: pgtype.Text{String: input.TournamentFK, Valid: input.TournamentFK != ""},
TournamentTemplateFk: pgtype.Text{String: input.TournamentTemplateFK, Valid: input.TournamentTemplateFK != ""},
TournamentStageFk: pgtype.Text{String: input.TournamentStageFK, Valid: input.TournamentStageFK != ""},
TournamentStageName: pgtype.Text{String: input.TournamentStageName, Valid: input.TournamentStageName != ""},
TournamentName: pgtype.Text{String: input.TournamentName, Valid: input.TournamentName != ""},
TournamentTemplateName: pgtype.Text{String: input.TournamentTemplateName, Valid: input.TournamentTemplateName != ""},
SportName: pgtype.Text{String: input.SportName, Valid: input.SportName != ""},
StartDate: pgtype.Timestamptz{Time: input.StartDate, Valid: !input.StartDate.IsZero()},
StatusType: pgtype.Text{String: input.StatusType, Valid: input.StatusType != ""},
StatusDescFk: pgtype.Text{String: input.StatusDescFK, Valid: input.StatusDescFK != ""},
RoundTypeFk: pgtype.Text{String: input.RoundTypeFK, Valid: input.RoundTypeFK != ""},
UpdatesCount: pgtype.Int4{Int32: int32(input.UpdatesCount), Valid: true},
LastUpdatedAt: pgtype.Timestamptz{Time: input.LastUpdatedAt, Valid: !input.LastUpdatedAt.IsZero()},
Round: pgtype.Text{String: input.Round, Valid: input.Round != ""},
Live: pgtype.Text{String: input.Live, Valid: input.Live != ""},
VenueName: pgtype.Text{String: input.VenueName, Valid: input.VenueName != ""},
LivestatsPlus: pgtype.Text{String: input.LivestatsPlus, Valid: input.LivestatsPlus != ""},
LivestatsType: pgtype.Text{String: input.LivestatsType, Valid: input.LivestatsType != ""},
Commentary: pgtype.Text{String: input.Commentary, Valid: input.Commentary != ""},
LineupConfirmed: pgtype.Bool{Bool: input.LineupConfirmed, Valid: true},
Verified: pgtype.Bool{Bool: input.Verified, Valid: true},
Spectators: pgtype.Int4{Int32: int32(input.Spectators), Valid: true},
GameStarted: pgtype.Timestamptz{Time: *input.GameStarted, Valid: !input.GameStarted.IsZero()},
FirstHalfEnded: pgtype.Timestamptz{Time: *input.FirstHalfEnded, Valid: !input.FirstHalfEnded.IsZero()},
SecondHalfStarted: pgtype.Timestamptz{Time: *input.SecondHalfStarted, Valid: !input.SecondHalfStarted.IsZero()},
SecondHalfEnded: pgtype.Timestamptz{Time: *input.SecondHalfEnded, Valid: !input.SecondHalfEnded.IsZero()},
GameEnded: pgtype.Timestamptz{Time: *input.GameEnded, Valid: !input.GameEnded.IsZero()},
}
}
// ConvertDBEnetpulseResult maps SQLC result → domain model
func ConvertDBEnetpulseResult(db dbgen.EnetpulseResult) domain.EnetpulseResult {
return domain.EnetpulseResult{
ID: db.ID,
ResultID: db.ResultID,
Name: db.Name,
SportFK: db.SportFk,
TournamentFK: db.TournamentFk.String,
TournamentTemplateFK: db.TournamentTemplateFk.String,
TournamentStageFK: db.TournamentStageFk.String,
TournamentStageName: db.TournamentStageName.String,
TournamentName: db.TournamentName.String,
TournamentTemplateName: db.TournamentTemplateName.String,
SportName: db.SportName.String,
StartDate: db.StartDate.Time,
StatusType: db.StatusType.String,
StatusDescFK: db.StatusDescFk.String,
RoundTypeFK: db.RoundTypeFk.String,
UpdatesCount: db.UpdatesCount.Int32,
LastUpdatedAt: &db.LastUpdatedAt.Time,
Round: db.Round.String,
Live: db.Live.String,
VenueName: db.VenueName.String,
LivestatsPlus: db.LivestatsPlus.String,
LivestatsType: db.LivestatsType.String,
Commentary: db.Commentary.String,
LineupConfirmed: db.LineupConfirmed.Bool,
Verified: db.Verified.Bool,
Spectators: db.Spectators.Int32,
GameStarted: &db.GameStarted.Time,
FirstHalfEnded: &db.FirstHalfEnded.Time,
SecondHalfStarted: &db.SecondHalfStarted.Time,
SecondHalfEnded: &db.SecondHalfEnded.Time,
GameEnded: &db.GameEnded.Time,
CreatedAt: db.CreatedAt.Time,
UpdatedAt: &db.UpdatedAt.Time,
}
}
// ConvertCreateEnetpulseOutcomeType converts the domain struct to SQLC params.
func ConvertCreateEnetpulseOutcomeType(o domain.CreateEnetpulseOutcomeType) dbgen.CreateEnetpulseOutcomeTypeParams {
return dbgen.CreateEnetpulseOutcomeTypeParams{
OutcomeTypeID: o.OutcomeTypeID,
Name: o.Name,
Description: pgtype.Text{String: o.Description, Valid: o.Description != ""}, // TODO: thiso.Description,
UpdatesCount: pgtype.Int4{Int32: int32(o.UpdatesCount), Valid: true},
LastUpdatedAt: pgtype.Timestamptz{Time: o.LastUpdatedAt, Valid: !o.LastUpdatedAt.IsZero()},
}
}
// ConvertDBEnetpulseOutcomeType converts SQLC DB model to domain model.
func ConvertDBEnetpulseOutcomeType(dbO dbgen.EnetpulseOutcomeType) domain.EnetpulseOutcomeType {
return domain.EnetpulseOutcomeType{
ID: dbO.ID,
OutcomeTypeID: dbO.OutcomeTypeID,
Name: dbO.Name,
Description: dbO.Description.String,
UpdatesCount: dbO.UpdatesCount.Int32,
LastUpdatedAt: dbO.LastUpdatedAt.Time,
CreatedAt: dbO.CreatedAt.Time,
UpdatedAt: dbO.UpdatedAt.Time,
}
}
func ConvertCreateEnetpulsePreodds(p domain.CreateEnetpulsePreodds) (dbgen.CreateEnetpulsePreoddsParams, error) {
eventFK, err := strconv.ParseInt(p.EventFK, 10, 64)
if err != nil {
return dbgen.CreateEnetpulsePreoddsParams{}, fmt.Errorf("invalid EventFK: %w", err)
}
outcomeTypeFK, err := strconv.ParseInt(p.OutcomeTypeFK, 10, 32)
if err != nil {
return dbgen.CreateEnetpulsePreoddsParams{}, fmt.Errorf("invalid OutcomeTypeFK: %w", err)
}
outcomeScopeFK, err := strconv.ParseInt(p.OutcomeScopeFK, 10, 32)
if err != nil {
return dbgen.CreateEnetpulsePreoddsParams{}, fmt.Errorf("invalid OutcomeScopeFK: %w", err)
}
outcomeSubtypeFK, err := strconv.ParseInt(p.OutcomeSubtypeFK, 10, 32)
if err != nil {
return dbgen.CreateEnetpulsePreoddsParams{}, fmt.Errorf("invalid OutcomeSubtypeFK: %w", err)
}
return dbgen.CreateEnetpulsePreoddsParams{
PreoddsID: p.PreoddsID,
EventFk: eventFK,
OutcomeTypeFk: pgtype.Int4{Int32: int32(outcomeTypeFK), Valid: true},
OutcomeScopeFk: pgtype.Int4{Int32: int32(outcomeScopeFK), Valid: true},
OutcomeSubtypeFk: pgtype.Int4{Int32: int32(outcomeSubtypeFK), Valid: true},
EventParticipantNumber: pgtype.Int4{Int32: int32(p.EventParticipantNumber), Valid: true},
Iparam: pgtype.Text{String: p.IParam, Valid: p.IParam != ""},
Iparam2: pgtype.Text{String: p.IParam2, Valid: p.IParam2 != ""},
Dparam: pgtype.Text{String: p.DParam, Valid: p.DParam != ""},
Dparam2: pgtype.Text{String: p.DParam2, Valid: p.DParam2 != ""},
Sparam: pgtype.Text{String: p.SParam, Valid: p.SParam != ""},
UpdatesCount: pgtype.Int4{Int32: int32(p.UpdatesCount), Valid: true},
LastUpdatedAt: pgtype.Timestamptz{Time: p.LastUpdatedAt, Valid: !p.LastUpdatedAt.IsZero()},
}, nil
}
func ConvertDBEnetpulsePreodds(dbP dbgen.EnetpulsePreodd) domain.EnetpulsePreodds {
return domain.EnetpulsePreodds{
PreoddsID: dbP.PreoddsID,
EventFK: fmt.Sprintf("%v", dbP.EventFk),
OutcomeTypeFK: fmt.Sprintf("%v", dbP.OutcomeTypeFk),
OutcomeScopeFK: fmt.Sprintf("%v", dbP.OutcomeScopeFk),
OutcomeSubtypeFK: fmt.Sprintf("%v", dbP.OutcomeSubtypeFk),
EventParticipantNumber: int(dbP.EventParticipantNumber.Int32),
IParam: dbP.Iparam.String,
IParam2: dbP.Iparam2.String,
DParam: dbP.Dparam.String,
DParam2: dbP.Dparam2.String,
SParam: dbP.Sparam.String,
UpdatesCount: int(dbP.UpdatesCount.Int32),
LastUpdatedAt: dbP.LastUpdatedAt.Time,
CreatedAt: dbP.CreatedAt.Time,
UpdatedAt: dbP.UpdatedAt.Time,
}
}
func ConvertCreateEnetpulsePreoddsBettingOffer(o domain.CreateEnetpulsePreoddsBettingOffer) dbgen.CreateEnetpulsePreoddsBettingOfferParams {
// Convert float64 to int64 with scale 2
oddsInt := big.NewInt(int64(math.Round(o.Odds * 100)))
oddsOldInt := big.NewInt(int64(math.Round(o.OddsOld * 100)))
return dbgen.CreateEnetpulsePreoddsBettingOfferParams{
BettingofferID: o.BettingOfferID,
PreoddsFk: o.PreoddsFK,
BettingofferStatusFk: pgtype.Int4{Int32: o.BettingOfferStatusFK, Valid: true},
OddsProviderFk: pgtype.Int4{Int32: o.OddsProviderFK, Valid: true},
Odds: pgtype.Numeric{
Int: oddsInt,
Exp: -2, // scale 2 decimal places
Valid: true,
},
OddsOld: pgtype.Numeric{
Int: oddsOldInt,
Exp: -2,
Valid: true,
},
Active: pgtype.Bool{Bool: o.Active == "yes", Valid: true},
CouponKey: pgtype.Text{
String: o.CouponKey,
Valid: o.CouponKey != "",
},
UpdatesCount: pgtype.Int4{Int32: int32(o.UpdatesCount), Valid: true},
LastUpdatedAt: pgtype.Timestamptz{Time: o.LastUpdatedAt, Valid: !o.LastUpdatedAt.IsZero()},
}
}
// Convert DB result to domain struct
func ConvertDBEnetpulsePreoddsBettingOffer(o dbgen.EnetpulsePreoddsBettingoffer) domain.EnetpulsePreoddsBettingOffer {
var odds, oddsOld float64
if o.Odds.Valid {
odds, _ = o.Odds.Int.Float64() // Convert pgtype.Numeric to float64
}
if o.OddsOld.Valid {
oddsOld, _ = o.OddsOld.Int.Float64()
}
active := "no"
if o.Active.Valid && o.Active.Bool {
active = "yes"
}
return domain.EnetpulsePreoddsBettingOffer{
ID: o.ID,
BettingOfferID: o.BettingofferID,
PreoddsFK: o.PreoddsFk,
BettingOfferStatusFK: o.BettingofferStatusFk.Int32,
OddsProviderFK: o.OddsProviderFk.Int32,
Odds: odds,
OddsOld: oddsOld,
Active: active,
CouponKey: o.CouponKey.String,
UpdatesCount: int(o.UpdatesCount.Int32),
LastUpdatedAt: o.LastUpdatedAt.Time,
CreatedAt: o.CreatedAt.Time,
UpdatedAt: o.UpdatedAt.Time,
}
}

View File

@ -7,6 +7,7 @@ import (
"io"
"net/http"
"strconv"
"strings"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
@ -142,6 +143,10 @@ func (s *Service) FetchAndStoreTournamentTemplates(ctx context.Context) error {
}
for _, sport := range sports {
if sport.SportID != "1" {
continue
} else {
// 2⃣ Compose URL for each sport using its Enetpulse sportFK
url := fmt.Sprintf(
"http://eapi.enetpulse.com/tournament_template/list/?sportFK=%s&username=%s&token=%s",
@ -232,6 +237,8 @@ func (s *Service) FetchAndStoreTournamentTemplates(ctx context.Context) error {
continue
}
}
break
}
}
fmt.Println("✅ Successfully fetched and stored all tournament templates")
@ -452,6 +459,767 @@ func (s *Service) GetAllTournamentStages(ctx context.Context) ([]domain.Enetpuls
return stages, nil
}
func (s *Service) FetchAndStoreFixtures(ctx context.Context, date string) error {
// 1⃣ Fetch all sports from the database
sports, err := s.store.GetAllEnetpulseSports(ctx)
if err != nil {
return fmt.Errorf("failed to fetch sports from DB: %w", err)
}
// Struct for decoding each fixture from API
type Fixture struct {
FixtureID string `json:"id"`
Name string `json:"name"`
SportFK string `json:"sportFK"`
TournamentFK string `json:"tournamentFK"`
TournamentName string `json:"tournament_name"`
StartDate string `json:"startdate"`
StatusType string `json:"status_type"`
HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"`
HomeTeamID string `json:"home_team_id"`
AwayTeamID string `json:"away_team_id"`
HomeKitImage string `json:"home_kit_image"`
AwayKitImage string `json:"away_kit_image"`
}
// 2⃣ Loop through each sport
for _, sport := range sports {
if sport.SportID != "1" {
continue
}
url := fmt.Sprintf(
"http://eapi.enetpulse.com/event/fixtures/?username=%s&token=%s&sportFK=%s&language_typeFK=3&date=%s",
s.cfg.EnetPulseConfig.UserName,
s.cfg.EnetPulseConfig.Token,
sport.SportID,
date,
)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
fmt.Printf("creating fixtures request for sport %s: %v\n", sport.SportID, err)
continue
}
resp, err := s.httpClient.Do(req)
if err != nil {
fmt.Printf("requesting fixtures for sport %s: %v\n", sport.SportID, err)
continue
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
fmt.Printf("failed to fetch fixtures for sport %s (status %d): %s\n",
sport.SportID, resp.StatusCode, string(body))
continue
}
// 3⃣ Decode API response
var fixturesResp struct {
Events map[string]Fixture `json:"events"`
}
if err := json.NewDecoder(resp.Body).Decode(&fixturesResp); err != nil {
fmt.Printf("decoding fixtures response for sport %s: %v\n", sport.SportID, err)
continue
}
// 4⃣ Iterate over fixtures and store as events
for _, fx := range fixturesResp.Events {
// Conversions
sportID, _ := strconv.Atoi(fx.SportFK)
homeTeamID, _ := strconv.ParseInt(fx.HomeTeamID, 10, 64)
awayTeamID, _ := strconv.ParseInt(fx.AwayTeamID, 10, 64)
leagueID, _ := strconv.ParseInt(fx.TournamentFK, 10, 64)
startDate, _ := time.Parse("2006-01-02 15:04:05", fx.StartDate)
event := domain.CreateEvent{
SourceEventID: fx.FixtureID,
SportID: int32(sportID),
MatchName: fx.Name,
HomeTeam: fx.HomeTeam,
AwayTeam: fx.AwayTeam,
HomeTeamID: homeTeamID,
AwayTeamID: awayTeamID,
HomeTeamImage: fx.HomeKitImage,
AwayTeamImage: fx.AwayKitImage,
LeagueID: leagueID,
LeagueName: fx.TournamentName,
StartTime: startDate,
IsLive: false, // default, can update later from live feed
Status: domain.STATUS_PENDING, // map to enum if needed
Source: "EnetPulse", // custom enum constant
DefaultWinningUpperLimit: 0, // default, can adjust
}
// 5⃣ Save event in DB (UPSERT)
if err := s.store.SaveEvent(ctx, event); err != nil {
fmt.Printf("failed storing event %s: %v\n", fx.FixtureID, err)
continue
}
}
fmt.Printf("✅ Successfully fetched and stored events for sport %s\n", sport.SportID)
break
}
fmt.Println("✅ Completed fetching and storing events for all sports")
return nil
}
func (s *Service) FetchFixtures(ctx context.Context, date string) ([]domain.EnetpulseFixture, error) {
var allFixtures []domain.EnetpulseFixture
// 1⃣ Fetch all sports from the database
sports, err := s.store.GetAllEnetpulseSports(ctx)
if err != nil {
return nil, fmt.Errorf("failed to fetch sports from DB: %w", err)
}
// Struct for decoding each fixture from API
type Fixture struct {
FixtureID string `json:"id"`
Name string `json:"name"`
SportFK string `json:"sportFK"`
TournamentFK string `json:"tournamentFK"`
TournamentTemplateFK string `json:"tournament_templateFK"`
TournamentStageFK string `json:"tournament_stageFK"`
TournamentStageName string `json:"tournament_stage_name"`
TournamentName string `json:"tournament_name"`
TournamentTemplateName string `json:"tournament_template_name"`
SportName string `json:"sport_name"`
Gender string `json:"gender"`
StartDate string `json:"startdate"`
StatusType string `json:"status_type"`
StatusDescFK string `json:"status_descFK"`
RoundTypeFK string `json:"round_typeFK"`
UpdatesCount string `json:"n"`
LastUpdatedAt string `json:"ut"`
}
// 2⃣ Loop through each sport
for _, sport := range sports {
// Only fetch for sport "1" (Football)
if sport.SportID != "1" {
continue
}
url := fmt.Sprintf(
"http://eapi.enetpulse.com/event/fixtures/?username=%s&token=%s&sportFK=%s&language_typeFK=3&date=%s",
s.cfg.EnetPulseConfig.UserName,
s.cfg.EnetPulseConfig.Token,
sport.SportID,
date,
)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
fmt.Printf("creating fixtures request for sport %s: %v\n", sport.SportID, err)
continue
}
resp, err := s.httpClient.Do(req)
if err != nil {
fmt.Printf("requesting fixtures for sport %s: %v\n", sport.SportID, err)
continue
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
fmt.Printf("failed to fetch fixtures for sport %s (status %d): %s\n",
sport.SportID, resp.StatusCode, string(body))
continue
}
// 3⃣ Decode API response
var fixturesResp struct {
Events map[string]Fixture `json:"events"`
}
if err := json.NewDecoder(resp.Body).Decode(&fixturesResp); err != nil {
fmt.Printf("decoding fixtures response for sport %s: %v\n", sport.SportID, err)
continue
}
// 4⃣ Iterate over fixtures and store them
for _, fx := range fixturesResp.Events {
tournamentFK, _ := strconv.Atoi(fx.TournamentFK)
tournamentTemplateFK, _ := strconv.Atoi(fx.TournamentTemplateFK)
tournamentStageFK, _ := strconv.Atoi(fx.TournamentStageFK)
statusDescFK, _ := strconv.Atoi(fx.StatusDescFK)
roundTypeFK, _ := strconv.Atoi(fx.RoundTypeFK)
updatesCount, _ := strconv.Atoi(fx.UpdatesCount)
startDate, _ := time.Parse(time.RFC3339, fx.StartDate)
lastUpdatedAt, _ := time.Parse(time.RFC3339, fx.LastUpdatedAt)
createFixture := domain.CreateEnetpulseFixture{
FixtureID: fx.FixtureID,
Name: fx.Name,
SportFK: fx.SportFK,
TournamentFK: strconv.Itoa(tournamentFK),
TournamentTemplateFK: strconv.Itoa(tournamentTemplateFK),
TournamentStageFK: strconv.Itoa(tournamentStageFK),
TournamentStageName: fx.TournamentStageName,
TournamentName: fx.TournamentName,
TournamentTemplateName: fx.TournamentTemplateName,
SportName: fx.SportName,
Gender: fx.Gender,
StartDate: startDate,
StatusType: fx.StatusType,
StatusDescFK: strconv.Itoa(statusDescFK),
RoundTypeFK: strconv.Itoa(roundTypeFK),
UpdatesCount: updatesCount,
LastUpdatedAt: lastUpdatedAt,
}
dbFixture, err := s.store.CreateEnetpulseFixture(ctx, createFixture)
if err != nil {
fmt.Printf("failed storing fixture %s: %v\n", fx.FixtureID, err)
continue
}
allFixtures = append(allFixtures, dbFixture)
}
fmt.Printf("✅ Successfully fetched and stored fixtures for sport %s\n", sport.SportID)
break // stop after first relevant sport
}
fmt.Println("✅ Completed fetching and storing fixtures for all sports")
return allFixtures, nil
}
func (s *Service) GetAllFixtures(ctx context.Context) ([]domain.EnetpulseFixture, error) {
// 1⃣ Fetch all from store
fixtures, err := s.store.GetAllEnetpulseFixtures(ctx)
if err != nil {
return nil, fmt.Errorf("failed to fetch fixtures from DB: %w", err)
}
return fixtures, nil
}
func (s *Service) FetchAndStoreResults(ctx context.Context) error {
// 1⃣ Fetch all sports (if you want to limit to one, adjust the loop as in your template fetcher)
sports, err := s.store.GetAllEnetpulseSports(ctx)
if err != nil {
return fmt.Errorf("failed to fetch sports from DB: %w", err)
}
type Result struct {
ID string `json:"id"`
Name string `json:"name"`
SportFK string `json:"sportFK"`
TournamentFK string `json:"tournamentFK"`
TournamentTemplateFK string `json:"tournament_templateFK"`
TournamentStageFK string `json:"tournament_stageFK"`
TournamentStageName string `json:"tournament_stage_name"`
TournamentName string `json:"tournament_name"`
TournamentTemplateName string `json:"tournament_template_name"`
SportName string `json:"sport_name"`
StartDate string `json:"startdate"`
StatusType string `json:"status_type"`
StatusDescFK string `json:"status_descFK"`
RoundTypeFK string `json:"round_typeFK"`
N string `json:"n"`
UT string `json:"ut"`
Round string `json:"round"`
Live string `json:"live"`
VenueName string `json:"venue_name"`
LivestatsPlus string `json:"livestats_plus"`
LivestatsType string `json:"livestats_type"`
Commentary string `json:"commentary"`
LineupConfirmed bool `json:"lineup_confirmed"`
Verified bool `json:"verified"`
Spectators int32 `json:"spectators"`
GameStarted string `json:"game_started"`
FirstHalfEnded string `json:"first_half_ended"`
SecondHalfStarted string `json:"second_half_started"`
SecondHalfEnded string `json:"second_half_ended"`
GameEnded string `json:"game_ended"`
}
for _, sport := range sports {
if sport.SportID != "1" { // ⚽ Example: Only Football
continue
}
url := fmt.Sprintf(
// "https://eapi.enetpulse.com/event/results/?username=kirubelapiusr&token=b1d35ee5fb8371938c6ca1b4fd6c75cc&sportFK=1&language_typeFK=3&date=2025-10-12"
"http://eapi.enetpulse.com/event/results/?sportFK=%s&date=%s&username=%s&token=%s",
sport.SportID,
time.DateOnly,
s.cfg.EnetPulseConfig.UserName,
s.cfg.EnetPulseConfig.Token,
)
fmt.Println("Fetching results:", url)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return fmt.Errorf("creating results request for sport %s: %w", sport.SportID, err)
}
resp, err := s.httpClient.Do(req)
if err != nil {
return fmt.Errorf("requesting results for sport %s: %w", sport.SportID, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("failed to fetch results for sport %s (status %d): %s",
sport.SportID, resp.StatusCode, string(body))
}
var raw struct {
EventResults json.RawMessage `json:"results"`
}
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("reading results response for sport %s: %w", sport.SportID, err)
}
if err := json.Unmarshal(bodyBytes, &raw); err != nil {
return fmt.Errorf("unmarshalling raw results for sport %s: %w", sport.SportID, err)
}
results := map[string]Result{}
if len(raw.EventResults) > 0 && raw.EventResults[0] == '{' {
if err := json.Unmarshal(raw.EventResults, &results); err != nil {
return fmt.Errorf("decoding results (object) for sport %s: %w", sport.SportID, err)
}
} else {
fmt.Printf("No results found for sport %s\n", sport.SportID)
continue
}
for _, r := range results {
updatesCount := 0
if r.N != "" {
if n, err := strconv.Atoi(r.N); err == nil {
updatesCount = n
}
}
lastUpdatedAt, _ := time.Parse(time.RFC3339, r.UT)
startDate, _ := time.Parse(time.RFC3339, r.StartDate)
gameStarted, _ := time.Parse(time.RFC3339, r.GameStarted)
firstHalfEnded, _ := time.Parse(time.RFC3339, r.FirstHalfEnded)
secondHalfStarted, _ := time.Parse(time.RFC3339, r.SecondHalfStarted)
secondHalfEnded, _ := time.Parse(time.RFC3339, r.SecondHalfEnded)
gameEnded, _ := time.Parse(time.RFC3339, r.GameEnded)
createResult := domain.CreateEnetpulseResult{
ResultID: r.ID,
Name: r.Name,
SportFK: r.SportFK,
TournamentFK: r.TournamentFK,
TournamentTemplateFK: r.TournamentTemplateFK,
TournamentStageFK: r.TournamentStageFK,
TournamentStageName: r.TournamentStageName,
TournamentName: r.TournamentName,
TournamentTemplateName: r.TournamentTemplateName,
SportName: r.SportName,
StartDate: startDate,
StatusType: r.StatusType,
StatusDescFK: r.StatusDescFK,
RoundTypeFK: r.RoundTypeFK,
UpdatesCount: int32(updatesCount),
LastUpdatedAt: lastUpdatedAt,
Round: r.Round,
Live: r.Live,
VenueName: r.VenueName,
LivestatsPlus: r.LivestatsPlus,
LivestatsType: r.LivestatsType,
Commentary: r.Commentary,
LineupConfirmed: r.LineupConfirmed,
Verified: r.Verified,
Spectators: r.Spectators,
GameStarted: &gameStarted,
FirstHalfEnded: &firstHalfEnded,
SecondHalfStarted: &secondHalfStarted,
SecondHalfEnded: &secondHalfEnded,
GameEnded: &gameEnded,
}
if _, err := s.store.CreateEnetpulseResult(ctx, createResult); err != nil {
fmt.Printf("❌ failed to store result %s: %v\n", r.ID, err)
continue
}
}
break // limit to one sport if necessary
}
fmt.Println("✅ Successfully fetched and stored EnetPulse results")
return nil
}
func (s *Service) GetAllResults(ctx context.Context) ([]domain.EnetpulseResult, error) {
results, err := s.store.GetAllEnetpulseResults(ctx)
if err != nil {
return nil, fmt.Errorf("failed to fetch results from DB: %w", err)
}
fmt.Printf("✅ Retrieved %d results from DB\n", len(results))
return results, nil
}
// FetchAndStoreOutcomeTypes fetches outcome types from EnetPulse API and stores them in the DB.
func (s *Service) FetchAndStoreOutcomeTypes(ctx context.Context) error {
// 1⃣ Compose EnetPulse API URL
url := fmt.Sprintf(
"http://eapi.enetpulse.com/static/outcome_type/?language_typeFK=3&username=%s&token=%s",
s.cfg.EnetPulseConfig.UserName,
s.cfg.EnetPulseConfig.Token,
)
// 2⃣ Create HTTP request
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return fmt.Errorf("failed to create outcome types request: %w", err)
}
// 3⃣ Execute request
resp, err := s.httpClient.Do(req)
if err != nil {
return fmt.Errorf("failed to call EnetPulse outcome_type API: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("unexpected status %d fetching outcome types: %s", resp.StatusCode, string(body))
}
// 4⃣ Decode JSON response
var outcomeResp struct {
OutcomeTypes map[string]struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
N string `json:"n"`
UT string `json:"ut"`
} `json:"outcome_type"`
}
if err := json.NewDecoder(resp.Body).Decode(&outcomeResp); err != nil {
return fmt.Errorf("failed to decode outcome types JSON: %w", err)
}
// 5⃣ Iterate and store each outcome type
for _, ot := range outcomeResp.OutcomeTypes {
updatesCount := 0
if ot.N != "" {
if n, err := strconv.Atoi(ot.N); err == nil {
updatesCount = n
}
}
lastUpdatedAt, err := time.Parse(time.RFC3339, ot.UT)
if err != nil {
lastUpdatedAt = time.Time{}
}
createOutcome := domain.CreateEnetpulseOutcomeType{
OutcomeTypeID: ot.ID,
Name: ot.Name,
Description: ot.Description,
UpdatesCount: int32(updatesCount),
LastUpdatedAt: lastUpdatedAt,
}
// 6⃣ Save to DB (upsert)
if _, err := s.store.CreateEnetpulseOutcomeType(ctx, createOutcome); err != nil {
// Optionally log the failure, continue to next
continue
}
}
// s.logger.Info("✅ Successfully fetched and stored all EnetPulse outcome types")
return nil
}
// GetAllOutcomeTypes retrieves all stored outcome types from the DB.
func (s *Service) GetAllOutcomeTypes(ctx context.Context) ([]domain.EnetpulseOutcomeType, error) {
outcomes, err := s.store.GetAllEnetpulseOutcomeTypes(ctx)
if err != nil {
return nil, fmt.Errorf("failed to fetch outcome types from DB: %w", err)
}
// s.logger.Info("✅ Fetched outcome types from DB", zap.Int("count", len(outcomes)))
return outcomes, nil
}
func (s *Service) FetchAndStorePreodds(ctx context.Context) error {
// 1⃣ Fetch all events from DB
fixtures, err := s.store.GetAllEnetpulseFixtures(ctx)
if err != nil {
return fmt.Errorf("failed to fetch fixtures: %w", err)
}
// providerIDStr := strconv.Itoa(int(s.cfg.EnetPulseConfig.ProviderID))
// 2⃣ Loop through each fixture/event
for _, fixture := range fixtures {
url := fmt.Sprintf(
"http://eapi.enetpulse.com/preodds/event/?objectFK=%s&odds_providerFK=%s&username=%s&token=%s",
fixture.FixtureID,
s.cfg.EnetPulseConfig.ProviderID,
s.cfg.EnetPulseConfig.UserName,
s.cfg.EnetPulseConfig.Token,
)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
// optionally log error and continue to next fixture
continue
}
resp, err := s.httpClient.Do(req)
if err != nil {
continue
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
continue
}
// Decode API response
var preoddsResp struct {
Preodds map[string]struct {
ID string `json:"id"`
OutcomeTypeFK string `json:"outcome_typeFK"`
OutcomeScopeFK string `json:"outcome_scopeFK"`
OutcomeSubtypeFK string `json:"outcome_subtypeFK"`
EventParticipantNumber string `json:"event_participant_number"`
Iparam string `json:"iparam"`
Iparam2 string `json:"iparam2"`
Dparam string `json:"dparam"`
Dparam2 string `json:"dparam2"`
Sparam string `json:"sparam"`
N string `json:"n"`
UT string `json:"ut"`
BettingOffers []struct {
ID string `json:"id"`
BettingOfferStatusFK int32 `json:"bettingoffer_status_fk"`
OddsProviderFK int32 `json:"odds_provider_fk"`
Odds float64 `json:"odds"`
OddsOld float64 `json:"odds_old"`
Active string `json:"active"`
CouponKey string `json:"coupon_key"`
N string `json:"n"`
UT string `json:"ut"`
} `json:"bettingoffers"`
} `json:"preodds"`
}
if err := json.NewDecoder(resp.Body).Decode(&preoddsResp); err != nil {
continue
}
// Iterate and store preodds and nested betting offers
for _, p := range preoddsResp.Preodds {
updatesCount := 0
if p.N != "" {
if n, err := strconv.Atoi(p.N); err == nil {
updatesCount = n
}
}
lastUpdatedAt, _ := time.Parse(time.RFC3339, p.UT)
eventParticipantNumber := int32(0)
if p.EventParticipantNumber != "" {
if epn, err := strconv.Atoi(p.EventParticipantNumber); err == nil {
eventParticipantNumber = int32(epn)
}
}
createPreodds := domain.CreateEnetpulsePreodds{
PreoddsID: p.ID,
EventFK: fixture.FixtureID,
OutcomeTypeFK: string(p.OutcomeTypeFK),
OutcomeScopeFK: string(p.OutcomeScopeFK),
OutcomeSubtypeFK: string(p.OutcomeSubtypeFK),
EventParticipantNumber: int(eventParticipantNumber),
IParam: p.Iparam,
IParam2: p.Iparam2,
DParam: p.Dparam,
DParam2: p.Dparam2,
SParam: p.Sparam,
UpdatesCount: int(updatesCount),
LastUpdatedAt: lastUpdatedAt,
}
storedPreodds, err := s.store.CreateEnetpulsePreodds(ctx, createPreodds)
if err != nil {
continue
}
for _, o := range p.BettingOffers {
bettingUpdates := 0
if o.N != "" {
if n, err := strconv.Atoi(o.N); err == nil {
bettingUpdates = n
}
}
bettingLastUpdatedAt, _ := time.Parse(time.RFC3339, o.UT)
createOffer := domain.CreateEnetpulsePreoddsBettingOffer{
BettingOfferID: o.ID,
PreoddsFK: storedPreodds.PreoddsID,
BettingOfferStatusFK: o.BettingOfferStatusFK,
OddsProviderFK: o.OddsProviderFK,
Odds: o.Odds,
OddsOld: o.OddsOld,
Active: o.Active,
CouponKey: o.CouponKey,
UpdatesCount: int(bettingUpdates),
LastUpdatedAt: bettingLastUpdatedAt,
}
_, _ = s.store.CreateEnetpulsePreoddsBettingOffer(ctx, createOffer)
}
}
}
return nil
}
// helper function to parse string to int32 safely
func ParseStringToInt32(s string) int32 {
if s == "" {
return 0
}
i, _ := strconv.Atoi(s)
return int32(i)
}
func (s *Service) GetAllPreodds(ctx context.Context) ([]domain.EnetpulsePreodds, error) {
preodds, err := s.store.GetAllEnetpulsePreodds(ctx)
if err != nil {
return nil, fmt.Errorf("failed to fetch preodds from DB: %w", err)
}
return preodds, nil
}
// FetchAndStoreBettingOffers fetches betting offers from EnetPulse API and stores them in the DB.
func (s *Service) StoreBettingOffers(ctx context.Context, preoddsID string, oddsProviderIDs []int32) error {
// 1⃣ Compose API URL
providers := make([]string, len(oddsProviderIDs))
for i, p := range oddsProviderIDs {
providers[i] = strconv.Itoa(int(p))
}
url := fmt.Sprintf(
"http://eapi.enetpulse.com/preodds_bettingoffer/?preoddsFK=%s&odds_providerFK=%s&username=%s&token=%s",
preoddsID,
strings.Join(providers, ","),
s.cfg.EnetPulseConfig.UserName,
s.cfg.EnetPulseConfig.Token,
)
// 2⃣ Create HTTP request
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return fmt.Errorf("failed to create betting offer request: %w", err)
}
// 3⃣ Execute request
resp, err := s.httpClient.Do(req)
if err != nil {
return fmt.Errorf("failed to call EnetPulse betting offer API: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("unexpected status %d fetching betting offers: %s", resp.StatusCode, string(body))
}
// 4⃣ Decode JSON response
var offerResp struct {
BettingOffers map[string]struct {
ID string `json:"id"`
PreoddsFK string `json:"preodds_fk"`
BettingOfferStatusFK int32 `json:"bettingoffer_status_fk"`
OddsProviderFK int32 `json:"odds_provider_fk"`
Odds float64 `json:"odds"`
OddsOld float64 `json:"odds_old"`
Active string `json:"active"`
CouponKey string `json:"coupon_key"`
N string `json:"n"`
UT string `json:"ut"`
} `json:"bettingoffer"`
}
if err := json.NewDecoder(resp.Body).Decode(&offerResp); err != nil {
return fmt.Errorf("failed to decode betting offers JSON: %w", err)
}
// 5⃣ Iterate and store each betting offer
for _, o := range offerResp.BettingOffers {
updatesCount := 0
if o.N != "" {
if n, err := strconv.Atoi(o.N); err == nil {
updatesCount = n
}
}
lastUpdatedAt, err := time.Parse(time.RFC3339, o.UT)
if err != nil {
lastUpdatedAt = time.Time{}
}
createOffer := domain.CreateEnetpulsePreoddsBettingOffer{
BettingOfferID: o.ID,
PreoddsFK: preoddsID,
BettingOfferStatusFK: o.BettingOfferStatusFK,
OddsProviderFK: o.OddsProviderFK,
Odds: o.Odds,
OddsOld: o.OddsOld,
Active: o.Active,
CouponKey: o.CouponKey,
UpdatesCount: int(updatesCount),
LastUpdatedAt: lastUpdatedAt,
}
// 6⃣ Save to DB
if _, err := s.store.CreateEnetpulsePreoddsBettingOffer(ctx, createOffer); err != nil {
// optionally log the failure and continue
continue
}
}
return nil
}
// GetAllBettingOffers retrieves all stored betting offers from the DB.
func (s *Service) GetAllBettingOffers(ctx context.Context) ([]domain.EnetpulsePreoddsBettingOffer, error) {
offers, err := s.store.GetAllEnetpulsePreoddsBettingOffers(ctx)
if err != nil {
return nil, fmt.Errorf("failed to fetch betting offers from DB: %w", err)
}
return offers, nil
}
// helper to safely parse string to int32
// func parseStringToInt32(s string) int32 {
// if s == "" {
// return 0
// }
// i, err := strconv.Atoi(s)
// if err != nil {
// return 0
// }
// return int32(i)
// }
func (s *Service) FetchTournamentTemplates(ctx context.Context) (*domain.TournamentTemplatesResponse, error) {
url := fmt.Sprintf(
"http://eapi.enetpulse.com/tournamenttemplate/list/?username=%s&token=%s",
@ -757,72 +1525,72 @@ func (s *Service) FetchDailyEvents(ctx context.Context, req domain.DailyEventsRe
return &dailyResp, nil
}
func (s *Service) FetchFixtures(ctx context.Context, params domain.FixturesRequest) (*domain.FixturesResponse, error) {
// Build base URL
url := fmt.Sprintf("http://eapi.enetpulse.com/event/fixtures/?username=%s&token=%s",
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
// func (s *Service) FetchFixtures(ctx context.Context, params domain.FixturesRequest) (*domain.FixturesResponse, error) {
// // Build base URL
// url := fmt.Sprintf("http://eapi.enetpulse.com/event/fixtures/?username=%s&token=%s",
// s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
// Required filter: one of sportFK | tournament_templateFK | tournament_stageFK
if params.SportFK != 0 {
url += fmt.Sprintf("&sportFK=%d", params.SportFK)
}
if params.TournamentTemplateFK != 0 {
url += fmt.Sprintf("&tournament_templateFK=%d", params.TournamentTemplateFK)
}
if params.TournamentStageFK != 0 {
url += fmt.Sprintf("&tournament_stageFK=%d", params.TournamentStageFK)
}
// // Required filter: one of sportFK | tournament_templateFK | tournament_stageFK
// if params.SportFK != 0 {
// url += fmt.Sprintf("&sportFK=%d", params.SportFK)
// }
// if params.TournamentTemplateFK != 0 {
// url += fmt.Sprintf("&tournament_templateFK=%d", params.TournamentTemplateFK)
// }
// if params.TournamentStageFK != 0 {
// url += fmt.Sprintf("&tournament_stageFK=%d", params.TournamentStageFK)
// }
// Optional filters
if params.LanguageTypeFK != 0 {
url += fmt.Sprintf("&language_typeFK=%d", params.LanguageTypeFK)
} else {
url += "&language_typeFK=3" // default to English
}
if params.Date != "" {
url += fmt.Sprintf("&date=%s", params.Date)
}
if params.Live != "" {
url += fmt.Sprintf("&live=%s", params.Live)
}
if params.IncludeVenue {
url += "&includeVenue=yes"
}
if !params.IncludeEventProperties {
url += "&includeEventProperties=no"
}
if params.IncludeCountryCodes {
url += "&includeCountryCodes=yes"
}
if params.IncludeFirstLastName {
url += "&includeFirstLastName=yes"
}
// // Optional filters
// if params.LanguageTypeFK != 0 {
// url += fmt.Sprintf("&language_typeFK=%d", params.LanguageTypeFK)
// } else {
// url += "&language_typeFK=3" // default to English
// }
// if params.Date != "" {
// url += fmt.Sprintf("&date=%s", params.Date)
// }
// if params.Live != "" {
// url += fmt.Sprintf("&live=%s", params.Live)
// }
// if params.IncludeVenue {
// url += "&includeVenue=yes"
// }
// if !params.IncludeEventProperties {
// url += "&includeEventProperties=no"
// }
// if params.IncludeCountryCodes {
// url += "&includeCountryCodes=yes"
// }
// if params.IncludeFirstLastName {
// url += "&includeFirstLastName=yes"
// }
// Make request
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, fmt.Errorf("creating fixtures request: %w", err)
}
// // Make request
// req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
// if err != nil {
// return nil, fmt.Errorf("creating fixtures request: %w", err)
// }
resp, err := s.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("requesting fixtures: %w", err)
}
defer resp.Body.Close()
// resp, err := s.httpClient.Do(req)
// if err != nil {
// return nil, fmt.Errorf("requesting fixtures: %w", err)
// }
// defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
}
// if resp.StatusCode != http.StatusOK {
// body, _ := io.ReadAll(resp.Body)
// return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
// }
// Decode response
var fixturesResp domain.FixturesResponse
if err := json.NewDecoder(resp.Body).Decode(&fixturesResp); err != nil {
return nil, fmt.Errorf("decoding fixtures response: %w", err)
}
// // Decode response
// var fixturesResp domain.FixturesResponse
// if err := json.NewDecoder(resp.Body).Decode(&fixturesResp); err != nil {
// return nil, fmt.Errorf("decoding fixtures response: %w", err)
// }
return &fixturesResp, nil
}
// return &fixturesResp, nil
// }
func (s *Service) FetchResults(ctx context.Context, params domain.ResultsRequest) (*domain.ResultsResponse, error) {
// Build base URL

View File

@ -84,9 +84,9 @@ func (s *ServiceImpl) ProcessBet365Odds(ctx context.Context) error {
Value: domain.STATUS_PENDING,
Valid: true,
},
Source: domain.ValidEventSource{
Value: domain.EVENT_SOURCE_BET365,
},
// Source: domain.ValidEventSource{
// Value: domain.EVENT_SOURCE_BET365,
// },
})
if err != nil {
s.mongoLogger.Error(

View File

@ -236,10 +236,10 @@ func (s *Service) FetchB365ResultAndUpdateBets(ctx context.Context) error {
Value: time.Now(),
Valid: true,
},
Source: domain.ValidEventSource{
Value: domain.EVENT_SOURCE_BET365,
Valid: true,
},
// Source: domain.ValidEventSource{
// Value: domain.EVENT_SOURCE_BET365,
// Valid: true,
// },
})
if err != nil {
@ -733,10 +733,10 @@ func (s *Service) CheckAndUpdateExpiredB365Events(ctx context.Context) (int64, e
Value: time.Now(),
Valid: true,
},
Source: domain.ValidEventSource{
Value: domain.EVENT_SOURCE_BET365,
Valid: true,
},
// Source: domain.ValidEventSource{
// Value: domain.EVENT_SOURCE_BET365,
// Valid: true,
// },
})
if err != nil {
s.mongoLogger.Error(
@ -955,7 +955,7 @@ func (s *Service) GetBet365ResultForEvent(ctx context.Context, b365EventID strin
zap.String("b365EventID", b365EventID),
zap.Error(err),
)
return json.RawMessage{}, nil, fmt.Errorf("invalid API response for event %d", b365EventID)
return json.RawMessage{}, nil, fmt.Errorf("invalid API response for event %s", b365EventID)
}
var commonResp domain.CommonResultResponse

View File

@ -252,60 +252,89 @@ func StartEnetPulseCron(enetPulseSvc *enetpulse.Service, mongoLogger *zap.Logger
task func()
}{
{
spec: "0 0,10,20,30,40,50 * * * *", // Every 10 minutes
spec: "0 0 */2 * * *", // Every 2 hours
task: func() {
ctx := context.Background()
// 1⃣ Sports
mongoLogger.Info("Began fetching and storing sports cron task")
if err := enetPulseSvc.FetchAndStoreSports(context.Background()); err != nil {
mongoLogger.Error("Failed to fetch and store sports",
zap.Error(err),
)
if err := enetPulseSvc.FetchAndStoreSports(ctx); err != nil {
mongoLogger.Error("Failed to fetch and store sports", zap.Error(err))
} else {
mongoLogger.Info("Completed fetching and storing sports without errors")
mongoLogger.Info("✅ Completed fetching and storing sports")
}
// 2⃣ Tournament Templates
mongoLogger.Info("Began fetching and storing tournament templates cron task")
if err := enetPulseSvc.FetchAndStoreTournamentTemplates(context.Background()); err != nil {
mongoLogger.Error("Failed to fetch and store tournament templates",
zap.Error(err),
)
if err := enetPulseSvc.FetchAndStoreTournamentTemplates(ctx); err != nil {
mongoLogger.Error("Failed to fetch and store tournament templates", zap.Error(err))
} else {
mongoLogger.Info("Completed fetching and storing tournament templates without errors")
mongoLogger.Info("✅ Completed fetching and storing tournament templates")
}
// 3⃣ Tournaments
mongoLogger.Info("Began fetching and storing tournaments cron task")
if err := enetPulseSvc.FetchAndStoreTournaments(context.Background()); err != nil {
mongoLogger.Error("Failed to fetch and store tournaments",
zap.Error(err),
)
if err := enetPulseSvc.FetchAndStoreTournaments(ctx); err != nil {
mongoLogger.Error("Failed to fetch and store tournaments", zap.Error(err))
} else {
mongoLogger.Info("Completed fetching and storing tournaments without errors")
mongoLogger.Info("✅ Completed fetching and storing tournaments")
}
// 4⃣ Tournament Stages
mongoLogger.Info("Began fetching and storing tournament stages cron task")
if err := enetPulseSvc.FetchAndStoreTournamentStages(context.Background()); err != nil {
mongoLogger.Error("Failed to fetch and store tournament stages",
zap.Error(err),
)
if err := enetPulseSvc.FetchAndStoreTournamentStages(ctx); err != nil {
mongoLogger.Error("Failed to fetch and store tournament stages", zap.Error(err))
} else {
mongoLogger.Info("Completed fetching and storing tournament stages without errors")
mongoLogger.Info("✅ Completed fetching and storing tournament stages")
}
// 5⃣ Fixtures
mongoLogger.Info("Began fetching and storing fixtures cron task")
today := time.Now().Format("2006-01-02")
if err := enetPulseSvc.FetchAndStoreFixtures(ctx, today); err != nil {
mongoLogger.Error("Failed to fetch and store fixtures", zap.Error(err))
} else {
mongoLogger.Info("✅ Completed fetching and storing fixtures")
}
// 6⃣ Results
mongoLogger.Info("Began fetching and storing results cron task")
if err := enetPulseSvc.FetchAndStoreResults(ctx); err != nil {
mongoLogger.Error("Failed to fetch and store results", zap.Error(err))
} else {
mongoLogger.Info("✅ Completed fetching and storing results")
}
// 7 Outcome Types
mongoLogger.Info("Began fetching and storing outcome_types cron task")
if err := enetPulseSvc.FetchAndStoreOutcomeTypes(ctx); err != nil {
mongoLogger.Error("Failed to fetch and store outcome_types", zap.Error(err))
} else {
mongoLogger.Info("✅ Completed fetching and storing outcome_types")
}
// 8 Outcome Types
mongoLogger.Info("Began fetching and storing preodds cron task")
if err := enetPulseSvc.FetchAndStorePreodds(ctx); err != nil {
mongoLogger.Error("Failed to fetch and store preodds", zap.Error(err))
} else {
mongoLogger.Info("✅ Completed fetching and storing preodds")
}
},
},
}
for _, job := range schedule {
// Run the task immediately at startup
// Run immediately at startup
job.task()
// Schedule the task
if _, err := c.AddFunc(job.spec, job.task); err != nil {
mongoLogger.Error("Failed to schedule EnetPulse cron job",
zap.Error(err),
)
mongoLogger.Error("Failed to schedule EnetPulse cron job", zap.Error(err))
}
}
c.Start()
log.Println("EnetPulse cron jobs started for sports, tournament templates, tournaments, and tournament stages")
mongoLogger.Info("EnetPulse cron jobs started for sports, tournament templates, tournaments, and tournament stages")
log.Println("EnetPulse cron jobs started for sports, tournament templates, tournaments, tournament stages, fixtures, and results")
mongoLogger.Info("EnetPulse cron jobs started for sports, tournament templates, tournaments, tournament stages, fixtures, and results")
}

View File

@ -178,6 +178,63 @@ func (h *Handler) GetAllTournamentStages(c *fiber.Ctx) error {
})
}
// GetFixturesByDate godoc
// @Summary Get all stored fixtures
// @Description Fetches all fixtures stored in the database
// @Tags EnetPulse - Fixtures
// @Accept json
// @Produce json
// @Success 200 {object} domain.Response{data=[]domain.EnetpulseFixture}
// @Failure 502 {object} domain.ErrorResponse
// @Router /api/v1/enetpulse/fixtures [get]
func (h *Handler) GetFixturesByDate(c *fiber.Ctx) error {
// Call service to get all fixtures from DB
fixtures, err := h.enetPulseSvc.GetAllFixtures(c.Context())
if err != nil {
log.Println("GetAllFixtures error:", err)
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
Message: "Failed to fetch fixtures from database",
Error: err.Error(),
})
}
return c.Status(fiber.StatusOK).JSON(domain.Response{
Message: "Fixtures fetched successfully",
Data: fixtures,
StatusCode: fiber.StatusOK,
Success: true,
})
}
// GetAllResults godoc
// @Summary Get all results
// @Description Fetches all EnetPulse match results stored in the database
// @Tags EnetPulse - Results
// @Accept json
// @Produce json
// @Success 200 {object} domain.Response{data=[]domain.EnetpulseResult}
// @Failure 502 {object} domain.ErrorResponse
// @Router /api/v1/enetpulse/results [get]
func (h *Handler) GetAllResults(c *fiber.Ctx) error {
// Call service
results, err := h.enetPulseSvc.GetAllResults(c.Context())
if err != nil {
log.Println("GetAllResults error:", err)
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
Message: "Failed to fetch EnetPulse results",
Error: err.Error(),
})
}
return c.Status(fiber.StatusOK).JSON(domain.Response{
Message: "EnetPulse results fetched successfully",
Data: results,
StatusCode: fiber.StatusOK,
Success: true,
})
}
// Helper: parse comma-separated string into []int
func parseIntSlice(input string) []int {
if input == "" {

View File

@ -259,7 +259,7 @@ func (a *App) initAppRoutes() {
tenant.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetTenantOddsByMarketID)
tenant.Post("/odds/settings", a.CompanyOnly, h.SaveOddsSetting)
groupV1.Get("/events", a.authMiddleware, h.GetAllEvents)
groupV1.Get("/events", h.GetAllEvents)
groupV1.Get("/events/:id", a.authMiddleware, h.GetEventByID)
groupV1.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved)
groupV1.Patch("/events/:id/is_monitored", a.authMiddleware, a.SuperAdminOnly, h.SetEventIsMonitored)
@ -275,6 +275,8 @@ func (a *App) initAppRoutes() {
groupV1.Get("/tournament_templates", h.GetAllTournamentTemplates)
groupV1.Get("/tournaments", h.GetAllTournamentTemplates)
groupV1.Get("/tournament_stages", h.GetAllTournamentStages)
groupV1.Get("/fixtures", h.GetFixturesByDate)
groupV1.Get("/results", h.GetAllResults)
// Leagues
tenant.Get("/leagues", h.GetAllLeagues)