events pagination + ticket and bet validation
This commit is contained in:
parent
cab7dbe2fa
commit
991199c3dc
|
|
@ -76,6 +76,8 @@ CREATE TABLE IF NOT EXISTS bet_outcomes (
|
||||||
market_name VARCHAR(255) NOT NULL,
|
market_name VARCHAR(255) NOT NULL,
|
||||||
odd REAL NOT NULL,
|
odd REAL NOT NULL,
|
||||||
odd_name VARCHAR(255) NOT NULL,
|
odd_name VARCHAR(255) NOT NULL,
|
||||||
|
odd_header VARCHAR(255) NOT NULL,
|
||||||
|
odd_handicap VARCHAR(255) NOT NULL,
|
||||||
expires TIMESTAMP NOT NULL
|
expires TIMESTAMP NOT NULL
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS ticket_outcomes (
|
CREATE TABLE IF NOT EXISTS ticket_outcomes (
|
||||||
|
|
@ -89,6 +91,8 @@ CREATE TABLE IF NOT EXISTS ticket_outcomes (
|
||||||
market_name VARCHAR(255) NOT NULL,
|
market_name VARCHAR(255) NOT NULL,
|
||||||
odd REAL NOT NULL,
|
odd REAL NOT NULL,
|
||||||
odd_name VARCHAR(255) NOT NULL,
|
odd_name VARCHAR(255) NOT NULL,
|
||||||
|
odd_header VARCHAR(255) NOT NULL,
|
||||||
|
odd_handicap VARCHAR(255) NOT NULL,
|
||||||
expires TIMESTAMP NOT NULL
|
expires TIMESTAMP NOT NULL
|
||||||
);
|
);
|
||||||
CREATE VIEW bet_with_outcomes AS
|
CREATE VIEW bet_with_outcomes AS
|
||||||
|
|
@ -321,6 +325,34 @@ VALUES (
|
||||||
NULL,
|
NULL,
|
||||||
FALSE
|
FALSE
|
||||||
);
|
);
|
||||||
|
INSERT INTO users (
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
password,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
suspended_at,
|
||||||
|
suspended
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
'Kirubel',
|
||||||
|
'Kibru',
|
||||||
|
'kirubeljkl679 @gmail.com',
|
||||||
|
NULL,
|
||||||
|
crypt('password@123', gen_salt('bf'))::bytea,
|
||||||
|
'super_admin',
|
||||||
|
TRUE,
|
||||||
|
FALSE,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
NULL,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
INSERT INTO supported_operations (name, description)
|
INSERT INTO supported_operations (name, description)
|
||||||
VALUES ('SportBook', 'Sportbook operations'),
|
VALUES ('SportBook', 'Sportbook operations'),
|
||||||
('Virtual', 'Virtual operations'),
|
('Virtual', 'Virtual operations'),
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,11 @@ INSERT INTO bet_outcomes (
|
||||||
market_name,
|
market_name,
|
||||||
odd,
|
odd,
|
||||||
odd_name,
|
odd_name,
|
||||||
|
odd_header,
|
||||||
|
odd_handicap,
|
||||||
expires
|
expires
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
|
||||||
-- name: GetAllBets :many
|
-- name: GetAllBets :many
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM bet_with_outcomes;
|
FROM bet_with_outcomes;
|
||||||
|
|
@ -46,6 +48,11 @@ UPDATE bets
|
||||||
SET cashed_out = $2,
|
SET cashed_out = $2,
|
||||||
updated_at = CURRENT_TIMESTAMP
|
updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
-- name: UpdateStatus :exec
|
||||||
|
UPDATE bets
|
||||||
|
SET status = $2,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $1;
|
||||||
-- name: DeleteBet :exec
|
-- name: DeleteBet :exec
|
||||||
DELETE FROM bets
|
DELETE FROM bets
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,50 @@
|
||||||
-- name: InsertEvent :exec
|
-- name: InsertEvent :exec
|
||||||
INSERT INTO events (
|
INSERT INTO events (
|
||||||
id, sport_id, match_name, home_team, away_team,
|
id,
|
||||||
home_team_id, away_team_id, home_kit_image, away_kit_image,
|
sport_id,
|
||||||
league_id, league_name, league_cc, start_time, score,
|
match_name,
|
||||||
match_minute, timer_status, added_time, match_period,
|
home_team,
|
||||||
is_live, status
|
away_team,
|
||||||
) VALUES (
|
home_team_id,
|
||||||
$1, $2, $3, $4, $5,
|
away_team_id,
|
||||||
$6, $7, $8, $9,
|
home_kit_image,
|
||||||
$10, $11, $12, $13, $14,
|
away_kit_image,
|
||||||
$15, $16, $17, $18,
|
league_id,
|
||||||
$19, $20
|
league_name,
|
||||||
)
|
league_cc,
|
||||||
ON CONFLICT (id) DO UPDATE SET
|
start_time,
|
||||||
sport_id = EXCLUDED.sport_id,
|
score,
|
||||||
|
match_minute,
|
||||||
|
timer_status,
|
||||||
|
added_time,
|
||||||
|
match_period,
|
||||||
|
is_live,
|
||||||
|
status
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
$14,
|
||||||
|
$15,
|
||||||
|
$16,
|
||||||
|
$17,
|
||||||
|
$18,
|
||||||
|
$19,
|
||||||
|
$20
|
||||||
|
) ON CONFLICT (id) DO
|
||||||
|
UPDATE
|
||||||
|
SET sport_id = EXCLUDED.sport_id,
|
||||||
match_name = EXCLUDED.match_name,
|
match_name = EXCLUDED.match_name,
|
||||||
home_team = EXCLUDED.home_team,
|
home_team = EXCLUDED.home_team,
|
||||||
away_team = EXCLUDED.away_team,
|
away_team = EXCLUDED.away_team,
|
||||||
|
|
@ -35,18 +66,41 @@ ON CONFLICT (id) DO UPDATE SET
|
||||||
fetched_at = now();
|
fetched_at = now();
|
||||||
-- name: InsertUpcomingEvent :exec
|
-- name: InsertUpcomingEvent :exec
|
||||||
INSERT INTO events (
|
INSERT INTO events (
|
||||||
id, sport_id, match_name, home_team, away_team,
|
id,
|
||||||
home_team_id, away_team_id, home_kit_image, away_kit_image,
|
sport_id,
|
||||||
league_id, league_name, league_cc, start_time,
|
match_name,
|
||||||
is_live, status
|
home_team,
|
||||||
) VALUES (
|
away_team,
|
||||||
$1, $2, $3, $4, $5,
|
home_team_id,
|
||||||
$6, $7, $8, $9,
|
away_team_id,
|
||||||
$10, $11, $12, $13,
|
home_kit_image,
|
||||||
false, 'upcoming'
|
away_kit_image,
|
||||||
)
|
league_id,
|
||||||
ON CONFLICT (id) DO UPDATE SET
|
league_name,
|
||||||
sport_id = EXCLUDED.sport_id,
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
false,
|
||||||
|
'upcoming'
|
||||||
|
) ON CONFLICT (id) DO
|
||||||
|
UPDATE
|
||||||
|
SET sport_id = EXCLUDED.sport_id,
|
||||||
match_name = EXCLUDED.match_name,
|
match_name = EXCLUDED.match_name,
|
||||||
home_team = EXCLUDED.home_team,
|
home_team = EXCLUDED.home_team,
|
||||||
away_team = EXCLUDED.away_team,
|
away_team = EXCLUDED.away_team,
|
||||||
|
|
@ -61,14 +115,12 @@ ON CONFLICT (id) DO UPDATE SET
|
||||||
is_live = false,
|
is_live = false,
|
||||||
status = 'upcoming',
|
status = 'upcoming',
|
||||||
fetched_at = now();
|
fetched_at = now();
|
||||||
|
|
||||||
|
|
||||||
-- name: ListLiveEvents :many
|
-- name: ListLiveEvents :many
|
||||||
SELECT id FROM events WHERE is_live = true;
|
SELECT id
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = true;
|
||||||
-- name: GetAllUpcomingEvents :many
|
-- name: GetAllUpcomingEvents :many
|
||||||
SELECT
|
SELECT id,
|
||||||
id,
|
|
||||||
sport_id,
|
sport_id,
|
||||||
match_name,
|
match_name,
|
||||||
home_team,
|
home_team,
|
||||||
|
|
@ -88,9 +140,35 @@ FROM events
|
||||||
WHERE is_live = false
|
WHERE is_live = false
|
||||||
AND status = 'upcoming'
|
AND status = 'upcoming'
|
||||||
ORDER BY start_time ASC;
|
ORDER BY start_time ASC;
|
||||||
|
-- name: GetTotalEvents :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = false
|
||||||
|
AND status = 'upcoming';
|
||||||
|
-- name: GetPaginatedUpcomingEvents :many
|
||||||
|
SELECT id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status,
|
||||||
|
fetched_at
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = false
|
||||||
|
AND status = 'upcoming'
|
||||||
|
ORDER BY start_time ASC
|
||||||
|
LIMIT $1 OFFSET $2;
|
||||||
-- name: GetUpcomingByID :one
|
-- name: GetUpcomingByID :one
|
||||||
SELECT
|
SELECT id,
|
||||||
id,
|
|
||||||
sport_id,
|
sport_id,
|
||||||
match_name,
|
match_name,
|
||||||
home_team,
|
home_team,
|
||||||
|
|
|
||||||
|
|
@ -83,16 +83,18 @@ SELECT event_id,
|
||||||
FROM odds
|
FROM odds
|
||||||
WHERE is_active = true
|
WHERE is_active = true
|
||||||
AND source = 'b365api';
|
AND source = 'b365api';
|
||||||
-- name: GetRawOddsByMarketID :many
|
-- name: GetRawOddsByMarketID :one
|
||||||
SELECT id,
|
SELECT id,
|
||||||
|
market_name,
|
||||||
|
handicap,
|
||||||
raw_odds,
|
raw_odds,
|
||||||
fetched_at
|
fetched_at
|
||||||
FROM odds
|
FROM odds
|
||||||
WHERE market_id = $1
|
WHERE market_id = $1
|
||||||
AND fi = $2
|
AND fi = $2
|
||||||
AND is_active = true
|
AND is_active = true
|
||||||
AND source = 'b365api'
|
AND source = 'b365api';
|
||||||
LIMIT $3 OFFSET $4;
|
|
||||||
-- name: GetPrematchOddsByUpcomingID :many
|
-- name: GetPrematchOddsByUpcomingID :many
|
||||||
SELECT o.event_id,
|
SELECT o.event_id,
|
||||||
o.fi,
|
o.fi,
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,24 @@ INSERT INTO ticket_outcomes (
|
||||||
market_name,
|
market_name,
|
||||||
odd,
|
odd,
|
||||||
odd_name,
|
odd_name,
|
||||||
|
odd_header,
|
||||||
|
odd_handicap,
|
||||||
expires
|
expires
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12
|
||||||
|
);
|
||||||
-- name: GetAllTickets :many
|
-- name: GetAllTickets :many
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM ticket_with_outcomes;
|
FROM ticket_with_outcomes;
|
||||||
|
|
|
||||||
100
docs/docs.go
100
docs/docs.go
|
|
@ -1303,6 +1303,20 @@ const docTemplate = `{
|
||||||
"prematch"
|
"prematch"
|
||||||
],
|
],
|
||||||
"summary": "Retrieve all upcoming events",
|
"summary": "Retrieve all upcoming events",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Page number",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Page size",
|
||||||
|
"name": "page_size",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
|
|
@ -2667,6 +2681,14 @@ const docTemplate = `{
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"example": 1.5
|
"example": 1.5
|
||||||
},
|
},
|
||||||
|
"odd_handicap": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1"
|
||||||
|
},
|
||||||
|
"odd_header": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1"
|
||||||
|
},
|
||||||
"odd_id": {
|
"odd_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
|
|
@ -2764,9 +2786,15 @@ const docTemplate = `{
|
||||||
"fetched_at": {
|
"fetched_at": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"handicap": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"market_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"raw_odds": {
|
"raw_odds": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {}
|
"items": {}
|
||||||
|
|
@ -2825,6 +2853,14 @@ const docTemplate = `{
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"example": 1.5
|
"example": 1.5
|
||||||
},
|
},
|
||||||
|
"odd_handicap": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1"
|
||||||
|
},
|
||||||
|
"odd_header": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1"
|
||||||
|
},
|
||||||
"odd_id": {
|
"odd_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
|
|
@ -3069,45 +3105,18 @@ const docTemplate = `{
|
||||||
"handlers.CreateBetOutcomeReq": {
|
"handlers.CreateBetOutcomeReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"away_team_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Liverpool"
|
|
||||||
},
|
|
||||||
"bet_id": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 1
|
|
||||||
},
|
|
||||||
"event_id": {
|
"event_id": {
|
||||||
|
"description": "BetID int64 ` + "`" + `json:\"bet_id\" example:\"1\"` + "`" + `",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
},
|
||||||
"expires": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "2025-04-08T12:00:00Z"
|
|
||||||
},
|
|
||||||
"home_team_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Manchester"
|
|
||||||
},
|
|
||||||
"market_id": {
|
"market_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
},
|
||||||
"market_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Fulltime Result"
|
|
||||||
},
|
|
||||||
"odd": {
|
|
||||||
"type": "number",
|
|
||||||
"example": 1.5
|
|
||||||
},
|
|
||||||
"odd_id": {
|
"odd_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
|
||||||
"odd_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -3264,45 +3273,18 @@ const docTemplate = `{
|
||||||
"handlers.CreateTicketOutcomeReq": {
|
"handlers.CreateTicketOutcomeReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"away_team_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Liverpool"
|
|
||||||
},
|
|
||||||
"event_id": {
|
"event_id": {
|
||||||
|
"description": "TicketID int64 ` + "`" + `json:\"ticket_id\" example:\"1\"` + "`" + `",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
},
|
||||||
"expires": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "2025-04-08T12:00:00Z"
|
|
||||||
},
|
|
||||||
"home_team_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Manchester"
|
|
||||||
},
|
|
||||||
"market_id": {
|
"market_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
},
|
||||||
"market_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Fulltime Result"
|
|
||||||
},
|
|
||||||
"odd": {
|
|
||||||
"type": "number",
|
|
||||||
"example": 1.5
|
|
||||||
},
|
|
||||||
"odd_id": {
|
"odd_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
|
||||||
"odd_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "1"
|
|
||||||
},
|
|
||||||
"ticket_id": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -3858,11 +3840,17 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
|
"page": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"$ref": "#/definitions/response.Status"
|
"$ref": "#/definitions/response.Status"
|
||||||
},
|
},
|
||||||
"timestamp": {
|
"timestamp": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"type": "integer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1295,6 +1295,20 @@
|
||||||
"prematch"
|
"prematch"
|
||||||
],
|
],
|
||||||
"summary": "Retrieve all upcoming events",
|
"summary": "Retrieve all upcoming events",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Page number",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Page size",
|
||||||
|
"name": "page_size",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
|
|
@ -2659,6 +2673,14 @@
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"example": 1.5
|
"example": 1.5
|
||||||
},
|
},
|
||||||
|
"odd_handicap": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1"
|
||||||
|
},
|
||||||
|
"odd_header": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1"
|
||||||
|
},
|
||||||
"odd_id": {
|
"odd_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
|
|
@ -2756,9 +2778,15 @@
|
||||||
"fetched_at": {
|
"fetched_at": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"handicap": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"market_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"raw_odds": {
|
"raw_odds": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {}
|
"items": {}
|
||||||
|
|
@ -2817,6 +2845,14 @@
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"example": 1.5
|
"example": 1.5
|
||||||
},
|
},
|
||||||
|
"odd_handicap": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1"
|
||||||
|
},
|
||||||
|
"odd_header": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1"
|
||||||
|
},
|
||||||
"odd_id": {
|
"odd_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
|
|
@ -3061,45 +3097,18 @@
|
||||||
"handlers.CreateBetOutcomeReq": {
|
"handlers.CreateBetOutcomeReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"away_team_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Liverpool"
|
|
||||||
},
|
|
||||||
"bet_id": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 1
|
|
||||||
},
|
|
||||||
"event_id": {
|
"event_id": {
|
||||||
|
"description": "BetID int64 `json:\"bet_id\" example:\"1\"`",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
},
|
||||||
"expires": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "2025-04-08T12:00:00Z"
|
|
||||||
},
|
|
||||||
"home_team_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Manchester"
|
|
||||||
},
|
|
||||||
"market_id": {
|
"market_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
},
|
||||||
"market_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Fulltime Result"
|
|
||||||
},
|
|
||||||
"odd": {
|
|
||||||
"type": "number",
|
|
||||||
"example": 1.5
|
|
||||||
},
|
|
||||||
"odd_id": {
|
"odd_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
|
||||||
"odd_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -3256,45 +3265,18 @@
|
||||||
"handlers.CreateTicketOutcomeReq": {
|
"handlers.CreateTicketOutcomeReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"away_team_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Liverpool"
|
|
||||||
},
|
|
||||||
"event_id": {
|
"event_id": {
|
||||||
|
"description": "TicketID int64 `json:\"ticket_id\" example:\"1\"`",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
},
|
||||||
"expires": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "2025-04-08T12:00:00Z"
|
|
||||||
},
|
|
||||||
"home_team_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Manchester"
|
|
||||||
},
|
|
||||||
"market_id": {
|
"market_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
},
|
||||||
"market_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Fulltime Result"
|
|
||||||
},
|
|
||||||
"odd": {
|
|
||||||
"type": "number",
|
|
||||||
"example": 1.5
|
|
||||||
},
|
|
||||||
"odd_id": {
|
"odd_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
|
||||||
"odd_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "1"
|
|
||||||
},
|
|
||||||
"ticket_id": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -3850,11 +3832,17 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
|
"page": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"$ref": "#/definitions/response.Status"
|
"$ref": "#/definitions/response.Status"
|
||||||
},
|
},
|
||||||
"timestamp": {
|
"timestamp": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"type": "integer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,12 @@ definitions:
|
||||||
odd:
|
odd:
|
||||||
example: 1.5
|
example: 1.5
|
||||||
type: number
|
type: number
|
||||||
|
odd_handicap:
|
||||||
|
example: "1"
|
||||||
|
type: string
|
||||||
|
odd_header:
|
||||||
|
example: "1"
|
||||||
|
type: string
|
||||||
odd_id:
|
odd_id:
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
|
|
@ -97,8 +103,12 @@ definitions:
|
||||||
properties:
|
properties:
|
||||||
fetched_at:
|
fetched_at:
|
||||||
type: string
|
type: string
|
||||||
|
handicap:
|
||||||
|
type: string
|
||||||
id:
|
id:
|
||||||
type: integer
|
type: integer
|
||||||
|
market_name:
|
||||||
|
type: string
|
||||||
raw_odds:
|
raw_odds:
|
||||||
items: {}
|
items: {}
|
||||||
type: array
|
type: array
|
||||||
|
|
@ -143,6 +153,12 @@ definitions:
|
||||||
odd:
|
odd:
|
||||||
example: 1.5
|
example: 1.5
|
||||||
type: number
|
type: number
|
||||||
|
odd_handicap:
|
||||||
|
example: "1"
|
||||||
|
type: string
|
||||||
|
odd_header:
|
||||||
|
example: "1"
|
||||||
|
type: string
|
||||||
odd_id:
|
odd_id:
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
|
|
@ -317,36 +333,16 @@ definitions:
|
||||||
type: object
|
type: object
|
||||||
handlers.CreateBetOutcomeReq:
|
handlers.CreateBetOutcomeReq:
|
||||||
properties:
|
properties:
|
||||||
away_team_name:
|
|
||||||
example: Liverpool
|
|
||||||
type: string
|
|
||||||
bet_id:
|
|
||||||
example: 1
|
|
||||||
type: integer
|
|
||||||
event_id:
|
event_id:
|
||||||
|
description: BetID int64 `json:"bet_id" example:"1"`
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
expires:
|
|
||||||
example: "2025-04-08T12:00:00Z"
|
|
||||||
type: string
|
|
||||||
home_team_name:
|
|
||||||
example: Manchester
|
|
||||||
type: string
|
|
||||||
market_id:
|
market_id:
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
market_name:
|
|
||||||
example: Fulltime Result
|
|
||||||
type: string
|
|
||||||
odd:
|
|
||||||
example: 1.5
|
|
||||||
type: number
|
|
||||||
odd_id:
|
odd_id:
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
odd_name:
|
|
||||||
example: "1"
|
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
handlers.CreateBetReq:
|
handlers.CreateBetReq:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -455,36 +451,16 @@ definitions:
|
||||||
type: object
|
type: object
|
||||||
handlers.CreateTicketOutcomeReq:
|
handlers.CreateTicketOutcomeReq:
|
||||||
properties:
|
properties:
|
||||||
away_team_name:
|
|
||||||
example: Liverpool
|
|
||||||
type: string
|
|
||||||
event_id:
|
event_id:
|
||||||
|
description: TicketID int64 `json:"ticket_id" example:"1"`
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
expires:
|
|
||||||
example: "2025-04-08T12:00:00Z"
|
|
||||||
type: string
|
|
||||||
home_team_name:
|
|
||||||
example: Manchester
|
|
||||||
type: string
|
|
||||||
market_id:
|
market_id:
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
market_name:
|
|
||||||
example: Fulltime Result
|
|
||||||
type: string
|
|
||||||
odd:
|
|
||||||
example: 1.5
|
|
||||||
type: number
|
|
||||||
odd_id:
|
odd_id:
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
odd_name:
|
|
||||||
example: "1"
|
|
||||||
type: string
|
|
||||||
ticket_id:
|
|
||||||
example: 1
|
|
||||||
type: integer
|
|
||||||
type: object
|
type: object
|
||||||
handlers.CreateTicketReq:
|
handlers.CreateTicketReq:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -867,10 +843,14 @@ definitions:
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
metadata: {}
|
metadata: {}
|
||||||
|
page:
|
||||||
|
type: integer
|
||||||
status:
|
status:
|
||||||
$ref: '#/definitions/response.Status'
|
$ref: '#/definitions/response.Status'
|
||||||
timestamp:
|
timestamp:
|
||||||
type: string
|
type: string
|
||||||
|
total:
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
response.Status:
|
response.Status:
|
||||||
enum:
|
enum:
|
||||||
|
|
@ -1732,6 +1712,15 @@ paths:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: Retrieve all upcoming events from the database
|
description: Retrieve all upcoming events from the database
|
||||||
|
parameters:
|
||||||
|
- description: Page number
|
||||||
|
in: query
|
||||||
|
name: page
|
||||||
|
type: integer
|
||||||
|
- description: Page size
|
||||||
|
in: query
|
||||||
|
name: page_size
|
||||||
|
type: integer
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,8 @@ type CreateBetOutcomeParams struct {
|
||||||
MarketName string `json:"market_name"`
|
MarketName string `json:"market_name"`
|
||||||
Odd float32 `json:"odd"`
|
Odd float32 `json:"odd"`
|
||||||
OddName string `json:"odd_name"`
|
OddName string `json:"odd_name"`
|
||||||
|
OddHeader string `json:"odd_header"`
|
||||||
|
OddHandicap string `json:"odd_handicap"`
|
||||||
Expires pgtype.Timestamp `json:"expires"`
|
Expires pgtype.Timestamp `json:"expires"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,3 +258,20 @@ func (q *Queries) UpdateCashOut(ctx context.Context, arg UpdateCashOutParams) er
|
||||||
_, err := q.db.Exec(ctx, UpdateCashOut, arg.ID, arg.CashedOut)
|
_, err := q.db.Exec(ctx, UpdateCashOut, arg.ID, arg.CashedOut)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UpdateStatus = `-- name: UpdateStatus :exec
|
||||||
|
UPDATE bets
|
||||||
|
SET status = $2,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateStatusParams struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Status int32 `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateStatus(ctx context.Context, arg UpdateStatusParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, UpdateStatus, arg.ID, arg.Status)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@ func (r iteratorForCreateBetOutcome) Values() ([]interface{}, error) {
|
||||||
r.rows[0].MarketName,
|
r.rows[0].MarketName,
|
||||||
r.rows[0].Odd,
|
r.rows[0].Odd,
|
||||||
r.rows[0].OddName,
|
r.rows[0].OddName,
|
||||||
|
r.rows[0].OddHeader,
|
||||||
|
r.rows[0].OddHandicap,
|
||||||
r.rows[0].Expires,
|
r.rows[0].Expires,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -47,7 +49,7 @@ func (r iteratorForCreateBetOutcome) Err() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateBetOutcome(ctx context.Context, arg []CreateBetOutcomeParams) (int64, error) {
|
func (q *Queries) CreateBetOutcome(ctx context.Context, arg []CreateBetOutcomeParams) (int64, error) {
|
||||||
return q.db.CopyFrom(ctx, []string{"bet_outcomes"}, []string{"bet_id", "event_id", "odd_id", "home_team_name", "away_team_name", "market_id", "market_name", "odd", "odd_name", "expires"}, &iteratorForCreateBetOutcome{rows: arg})
|
return q.db.CopyFrom(ctx, []string{"bet_outcomes"}, []string{"bet_id", "event_id", "odd_id", "home_team_name", "away_team_name", "market_id", "market_name", "odd", "odd_name", "odd_header", "odd_handicap", "expires"}, &iteratorForCreateBetOutcome{rows: arg})
|
||||||
}
|
}
|
||||||
|
|
||||||
// iteratorForCreateTicketOutcome implements pgx.CopyFromSource.
|
// iteratorForCreateTicketOutcome implements pgx.CopyFromSource.
|
||||||
|
|
@ -79,6 +81,8 @@ func (r iteratorForCreateTicketOutcome) Values() ([]interface{}, error) {
|
||||||
r.rows[0].MarketName,
|
r.rows[0].MarketName,
|
||||||
r.rows[0].Odd,
|
r.rows[0].Odd,
|
||||||
r.rows[0].OddName,
|
r.rows[0].OddName,
|
||||||
|
r.rows[0].OddHeader,
|
||||||
|
r.rows[0].OddHandicap,
|
||||||
r.rows[0].Expires,
|
r.rows[0].Expires,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -88,5 +92,5 @@ func (r iteratorForCreateTicketOutcome) Err() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateTicketOutcome(ctx context.Context, arg []CreateTicketOutcomeParams) (int64, error) {
|
func (q *Queries) CreateTicketOutcome(ctx context.Context, arg []CreateTicketOutcomeParams) (int64, error) {
|
||||||
return q.db.CopyFrom(ctx, []string{"ticket_outcomes"}, []string{"ticket_id", "event_id", "odd_id", "home_team_name", "away_team_name", "market_id", "market_name", "odd", "odd_name", "expires"}, &iteratorForCreateTicketOutcome{rows: arg})
|
return q.db.CopyFrom(ctx, []string{"ticket_outcomes"}, []string{"ticket_id", "event_id", "odd_id", "home_team_name", "away_team_name", "market_id", "market_name", "odd", "odd_name", "odd_header", "odd_handicap", "expires"}, &iteratorForCreateTicketOutcome{rows: arg})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const GetAllUpcomingEvents = `-- name: GetAllUpcomingEvents :many
|
const GetAllUpcomingEvents = `-- name: GetAllUpcomingEvents :many
|
||||||
SELECT
|
SELECT id,
|
||||||
id,
|
|
||||||
sport_id,
|
sport_id,
|
||||||
match_name,
|
match_name,
|
||||||
home_team,
|
home_team,
|
||||||
|
|
@ -91,9 +90,107 @@ func (q *Queries) GetAllUpcomingEvents(ctx context.Context) ([]GetAllUpcomingEve
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GetPaginatedUpcomingEvents = `-- name: GetPaginatedUpcomingEvents :many
|
||||||
|
SELECT id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status,
|
||||||
|
fetched_at
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = false
|
||||||
|
AND status = 'upcoming'
|
||||||
|
ORDER BY start_time ASC
|
||||||
|
LIMIT $1 OFFSET $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetPaginatedUpcomingEventsParams struct {
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
Offset int32 `json:"offset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetPaginatedUpcomingEventsRow struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SportID pgtype.Text `json:"sport_id"`
|
||||||
|
MatchName pgtype.Text `json:"match_name"`
|
||||||
|
HomeTeam pgtype.Text `json:"home_team"`
|
||||||
|
AwayTeam pgtype.Text `json:"away_team"`
|
||||||
|
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||||
|
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||||
|
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||||
|
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||||
|
LeagueID pgtype.Text `json:"league_id"`
|
||||||
|
LeagueName pgtype.Text `json:"league_name"`
|
||||||
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
|
StartTime pgtype.Timestamp `json:"start_time"`
|
||||||
|
IsLive pgtype.Bool `json:"is_live"`
|
||||||
|
Status pgtype.Text `json:"status"`
|
||||||
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginatedUpcomingEventsParams) ([]GetPaginatedUpcomingEventsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetPaginatedUpcomingEvents, arg.Limit, arg.Offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetPaginatedUpcomingEventsRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetPaginatedUpcomingEventsRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.SportID,
|
||||||
|
&i.MatchName,
|
||||||
|
&i.HomeTeam,
|
||||||
|
&i.AwayTeam,
|
||||||
|
&i.HomeTeamID,
|
||||||
|
&i.AwayTeamID,
|
||||||
|
&i.HomeKitImage,
|
||||||
|
&i.AwayKitImage,
|
||||||
|
&i.LeagueID,
|
||||||
|
&i.LeagueName,
|
||||||
|
&i.LeagueCc,
|
||||||
|
&i.StartTime,
|
||||||
|
&i.IsLive,
|
||||||
|
&i.Status,
|
||||||
|
&i.FetchedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetTotalEvents = `-- name: GetTotalEvents :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = false
|
||||||
|
AND status = 'upcoming'
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetTotalEvents(ctx context.Context) (int64, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetTotalEvents)
|
||||||
|
var count int64
|
||||||
|
err := row.Scan(&count)
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
const GetUpcomingByID = `-- name: GetUpcomingByID :one
|
const GetUpcomingByID = `-- name: GetUpcomingByID :one
|
||||||
SELECT
|
SELECT id,
|
||||||
id,
|
|
||||||
sport_id,
|
sport_id,
|
||||||
match_name,
|
match_name,
|
||||||
home_team,
|
home_team,
|
||||||
|
|
@ -161,20 +258,51 @@ func (q *Queries) GetUpcomingByID(ctx context.Context, id string) (GetUpcomingBy
|
||||||
|
|
||||||
const InsertEvent = `-- name: InsertEvent :exec
|
const InsertEvent = `-- name: InsertEvent :exec
|
||||||
INSERT INTO events (
|
INSERT INTO events (
|
||||||
id, sport_id, match_name, home_team, away_team,
|
id,
|
||||||
home_team_id, away_team_id, home_kit_image, away_kit_image,
|
sport_id,
|
||||||
league_id, league_name, league_cc, start_time, score,
|
match_name,
|
||||||
match_minute, timer_status, added_time, match_period,
|
home_team,
|
||||||
is_live, status
|
away_team,
|
||||||
) VALUES (
|
home_team_id,
|
||||||
$1, $2, $3, $4, $5,
|
away_team_id,
|
||||||
$6, $7, $8, $9,
|
home_kit_image,
|
||||||
$10, $11, $12, $13, $14,
|
away_kit_image,
|
||||||
$15, $16, $17, $18,
|
league_id,
|
||||||
$19, $20
|
league_name,
|
||||||
)
|
league_cc,
|
||||||
ON CONFLICT (id) DO UPDATE SET
|
start_time,
|
||||||
sport_id = EXCLUDED.sport_id,
|
score,
|
||||||
|
match_minute,
|
||||||
|
timer_status,
|
||||||
|
added_time,
|
||||||
|
match_period,
|
||||||
|
is_live,
|
||||||
|
status
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
$14,
|
||||||
|
$15,
|
||||||
|
$16,
|
||||||
|
$17,
|
||||||
|
$18,
|
||||||
|
$19,
|
||||||
|
$20
|
||||||
|
) ON CONFLICT (id) DO
|
||||||
|
UPDATE
|
||||||
|
SET sport_id = EXCLUDED.sport_id,
|
||||||
match_name = EXCLUDED.match_name,
|
match_name = EXCLUDED.match_name,
|
||||||
home_team = EXCLUDED.home_team,
|
home_team = EXCLUDED.home_team,
|
||||||
away_team = EXCLUDED.away_team,
|
away_team = EXCLUDED.away_team,
|
||||||
|
|
@ -247,18 +375,41 @@ func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) error
|
||||||
|
|
||||||
const InsertUpcomingEvent = `-- name: InsertUpcomingEvent :exec
|
const InsertUpcomingEvent = `-- name: InsertUpcomingEvent :exec
|
||||||
INSERT INTO events (
|
INSERT INTO events (
|
||||||
id, sport_id, match_name, home_team, away_team,
|
id,
|
||||||
home_team_id, away_team_id, home_kit_image, away_kit_image,
|
sport_id,
|
||||||
league_id, league_name, league_cc, start_time,
|
match_name,
|
||||||
is_live, status
|
home_team,
|
||||||
) VALUES (
|
away_team,
|
||||||
$1, $2, $3, $4, $5,
|
home_team_id,
|
||||||
$6, $7, $8, $9,
|
away_team_id,
|
||||||
$10, $11, $12, $13,
|
home_kit_image,
|
||||||
false, 'upcoming'
|
away_kit_image,
|
||||||
)
|
league_id,
|
||||||
ON CONFLICT (id) DO UPDATE SET
|
league_name,
|
||||||
sport_id = EXCLUDED.sport_id,
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
false,
|
||||||
|
'upcoming'
|
||||||
|
) ON CONFLICT (id) DO
|
||||||
|
UPDATE
|
||||||
|
SET sport_id = EXCLUDED.sport_id,
|
||||||
match_name = EXCLUDED.match_name,
|
match_name = EXCLUDED.match_name,
|
||||||
home_team = EXCLUDED.home_team,
|
home_team = EXCLUDED.home_team,
|
||||||
away_team = EXCLUDED.away_team,
|
away_team = EXCLUDED.away_team,
|
||||||
|
|
@ -311,7 +462,9 @@ func (q *Queries) InsertUpcomingEvent(ctx context.Context, arg InsertUpcomingEve
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListLiveEvents = `-- name: ListLiveEvents :many
|
const ListLiveEvents = `-- name: ListLiveEvents :many
|
||||||
SELECT id FROM events WHERE is_live = true
|
SELECT id
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = true
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ListLiveEvents(ctx context.Context) ([]string, error) {
|
func (q *Queries) ListLiveEvents(ctx context.Context) ([]string, error) {
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ type BetOutcome struct {
|
||||||
MarketName string `json:"market_name"`
|
MarketName string `json:"market_name"`
|
||||||
Odd float32 `json:"odd"`
|
Odd float32 `json:"odd"`
|
||||||
OddName string `json:"odd_name"`
|
OddName string `json:"odd_name"`
|
||||||
|
OddHeader string `json:"odd_header"`
|
||||||
|
OddHandicap string `json:"odd_handicap"`
|
||||||
Expires pgtype.Timestamp `json:"expires"`
|
Expires pgtype.Timestamp `json:"expires"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,6 +213,8 @@ type TicketOutcome struct {
|
||||||
MarketName string `json:"market_name"`
|
MarketName string `json:"market_name"`
|
||||||
Odd float32 `json:"odd"`
|
Odd float32 `json:"odd"`
|
||||||
OddName string `json:"odd_name"`
|
OddName string `json:"odd_name"`
|
||||||
|
OddHeader string `json:"odd_header"`
|
||||||
|
OddHandicap string `json:"odd_handicap"`
|
||||||
Expires pgtype.Timestamp `json:"expires"`
|
Expires pgtype.Timestamp `json:"expires"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -247,8 +247,10 @@ func (q *Queries) GetPrematchOddsByUpcomingID(ctx context.Context, arg GetPremat
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetRawOddsByMarketID = `-- name: GetRawOddsByMarketID :many
|
const GetRawOddsByMarketID = `-- name: GetRawOddsByMarketID :one
|
||||||
SELECT id,
|
SELECT id,
|
||||||
|
market_name,
|
||||||
|
handicap,
|
||||||
raw_odds,
|
raw_odds,
|
||||||
fetched_at
|
fetched_at
|
||||||
FROM odds
|
FROM odds
|
||||||
|
|
@ -256,45 +258,32 @@ WHERE market_id = $1
|
||||||
AND fi = $2
|
AND fi = $2
|
||||||
AND is_active = true
|
AND is_active = true
|
||||||
AND source = 'b365api'
|
AND source = 'b365api'
|
||||||
LIMIT $3 OFFSET $4
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetRawOddsByMarketIDParams struct {
|
type GetRawOddsByMarketIDParams struct {
|
||||||
MarketID pgtype.Text `json:"market_id"`
|
MarketID pgtype.Text `json:"market_id"`
|
||||||
Fi pgtype.Text `json:"fi"`
|
Fi pgtype.Text `json:"fi"`
|
||||||
Limit int32 `json:"limit"`
|
|
||||||
Offset int32 `json:"offset"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetRawOddsByMarketIDRow struct {
|
type GetRawOddsByMarketIDRow struct {
|
||||||
ID int32 `json:"id"`
|
ID int32 `json:"id"`
|
||||||
|
MarketName pgtype.Text `json:"market_name"`
|
||||||
|
Handicap pgtype.Text `json:"handicap"`
|
||||||
RawOdds []byte `json:"raw_odds"`
|
RawOdds []byte `json:"raw_odds"`
|
||||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetRawOddsByMarketID(ctx context.Context, arg GetRawOddsByMarketIDParams) ([]GetRawOddsByMarketIDRow, error) {
|
func (q *Queries) GetRawOddsByMarketID(ctx context.Context, arg GetRawOddsByMarketIDParams) (GetRawOddsByMarketIDRow, error) {
|
||||||
rows, err := q.db.Query(ctx, GetRawOddsByMarketID,
|
row := q.db.QueryRow(ctx, GetRawOddsByMarketID, arg.MarketID, arg.Fi)
|
||||||
arg.MarketID,
|
|
||||||
arg.Fi,
|
|
||||||
arg.Limit,
|
|
||||||
arg.Offset,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
var items []GetRawOddsByMarketIDRow
|
|
||||||
for rows.Next() {
|
|
||||||
var i GetRawOddsByMarketIDRow
|
var i GetRawOddsByMarketIDRow
|
||||||
if err := rows.Scan(&i.ID, &i.RawOdds, &i.FetchedAt); err != nil {
|
err := row.Scan(
|
||||||
return nil, err
|
&i.ID,
|
||||||
}
|
&i.MarketName,
|
||||||
items = append(items, i)
|
&i.Handicap,
|
||||||
}
|
&i.RawOdds,
|
||||||
if err := rows.Err(); err != nil {
|
&i.FetchedAt,
|
||||||
return nil, err
|
)
|
||||||
}
|
return i, err
|
||||||
return items, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const InsertNonLiveOdd = `-- name: InsertNonLiveOdd :exec
|
const InsertNonLiveOdd = `-- name: InsertNonLiveOdd :exec
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ type CreateTicketOutcomeParams struct {
|
||||||
MarketName string `json:"market_name"`
|
MarketName string `json:"market_name"`
|
||||||
Odd float32 `json:"odd"`
|
Odd float32 `json:"odd"`
|
||||||
OddName string `json:"odd_name"`
|
OddName string `json:"odd_name"`
|
||||||
|
OddHeader string `json:"odd_header"`
|
||||||
|
OddHandicap string `json:"odd_handicap"`
|
||||||
Expires pgtype.Timestamp `json:"expires"`
|
Expires pgtype.Timestamp `json:"expires"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +133,7 @@ func (q *Queries) GetTicketByID(ctx context.Context, id int64) (TicketWithOutcom
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetTicketOutcome = `-- name: GetTicketOutcome :many
|
const GetTicketOutcome = `-- name: GetTicketOutcome :many
|
||||||
SELECT id, ticket_id, event_id, odd_id, home_team_name, away_team_name, market_id, market_name, odd, odd_name, expires
|
SELECT id, ticket_id, event_id, odd_id, home_team_name, away_team_name, market_id, market_name, odd, odd_name, odd_header, odd_handicap, expires
|
||||||
FROM ticket_outcomes
|
FROM ticket_outcomes
|
||||||
WHERE ticket_id = $1
|
WHERE ticket_id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -156,6 +158,8 @@ func (q *Queries) GetTicketOutcome(ctx context.Context, ticketID int64) ([]Ticke
|
||||||
&i.MarketName,
|
&i.MarketName,
|
||||||
&i.Odd,
|
&i.Odd,
|
||||||
&i.OddName,
|
&i.OddName,
|
||||||
|
&i.OddHeader,
|
||||||
|
&i.OddHandicap,
|
||||||
&i.Expires,
|
&i.Expires,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,9 @@ type BetOutcome struct {
|
||||||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||||
Odd float32 `json:"odd" example:"1.5"`
|
Odd float32 `json:"odd" example:"1.5"`
|
||||||
OddName string `json:"odd_name" example:"1"`
|
OddName string `json:"odd_name" example:"1"`
|
||||||
|
OddHeader string `json:"odd_header" example:"1"`
|
||||||
|
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||||
|
|
||||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,6 +29,8 @@ type CreateBetOutcome struct {
|
||||||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||||
Odd float32 `json:"odd" example:"1.5"`
|
Odd float32 `json:"odd" example:"1.5"`
|
||||||
OddName string `json:"odd_name" example:"1"`
|
OddName string `json:"odd_name" example:"1"`
|
||||||
|
OddHeader string `json:"odd_header" example:"1"`
|
||||||
|
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package domain
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type RawMessage interface{}
|
type RawMessage interface{}
|
||||||
|
|
||||||
type Market struct {
|
type Market struct {
|
||||||
|
|
@ -40,6 +40,8 @@ type Odd struct {
|
||||||
}
|
}
|
||||||
type RawOddsByMarketID struct {
|
type RawOddsByMarketID struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
|
MarketName string `json:"market_name"`
|
||||||
|
Handicap string `json:"handicap"`
|
||||||
RawOdds []RawMessage `json:"raw_odds"`
|
RawOdds []RawMessage `json:"raw_odds"`
|
||||||
FetchedAt time.Time `json:"fetched_at"`
|
FetchedAt time.Time `json:"fetched_at"`
|
||||||
}
|
}
|
||||||
|
|
@ -6,13 +6,15 @@ type TicketOutcome struct {
|
||||||
ID int64 `json:"id" example:"1"`
|
ID int64 `json:"id" example:"1"`
|
||||||
TicketID int64 `json:"ticket_id" example:"1"`
|
TicketID int64 `json:"ticket_id" example:"1"`
|
||||||
EventID int64 `json:"event_id" example:"1"`
|
EventID int64 `json:"event_id" example:"1"`
|
||||||
OddID int64 `json:"odd_id" example:"1"`
|
|
||||||
HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||||
AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||||
MarketID int64 `json:"market_id" example:"1"`
|
MarketID int64 `json:"market_id" example:"1"`
|
||||||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||||
|
OddID int64 `json:"odd_id" example:"1"`
|
||||||
Odd float32 `json:"odd" example:"1.5"`
|
Odd float32 `json:"odd" example:"1.5"`
|
||||||
OddName string `json:"odd_name" example:"1"`
|
OddName string `json:"odd_name" example:"1"`
|
||||||
|
OddHeader string `json:"odd_header" example:"1"`
|
||||||
|
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,6 +28,8 @@ type CreateTicketOutcome struct {
|
||||||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||||
Odd float32 `json:"odd" example:"1.5"`
|
Odd float32 `json:"odd" example:"1.5"`
|
||||||
OddName string `json:"odd_name" example:"1"`
|
OddName string `json:"odd_name" example:"1"`
|
||||||
|
OddHeader string `json:"odd_header" example:"1"`
|
||||||
|
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ func convertDBBetOutcomes(bet dbgen.BetWithOutcome) domain.GetBet {
|
||||||
MarketName: outcome.MarketName,
|
MarketName: outcome.MarketName,
|
||||||
Odd: outcome.Odd,
|
Odd: outcome.Odd,
|
||||||
OddName: outcome.OddName,
|
OddName: outcome.OddName,
|
||||||
|
OddHeader: outcome.OddHeader,
|
||||||
|
OddHandicap: outcome.OddHandicap,
|
||||||
Expires: outcome.Expires.Time,
|
Expires: outcome.Expires.Time,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -82,6 +84,8 @@ func convertDBCreateBetOutcome(betOutcome domain.CreateBetOutcome) dbgen.CreateB
|
||||||
MarketName: betOutcome.MarketName,
|
MarketName: betOutcome.MarketName,
|
||||||
Odd: betOutcome.Odd,
|
Odd: betOutcome.Odd,
|
||||||
OddName: betOutcome.OddName,
|
OddName: betOutcome.OddName,
|
||||||
|
OddHeader: betOutcome.OddHeader,
|
||||||
|
OddHandicap: betOutcome.OddHandicap,
|
||||||
Expires: pgtype.Timestamp{
|
Expires: pgtype.Timestamp{
|
||||||
Time: betOutcome.Expires,
|
Time: betOutcome.Expires,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
|
|
@ -193,6 +197,14 @@ func (s *Store) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateStatus(ctx context.Context, id int64, status domain.BetStatus) error {
|
||||||
|
err := s.queries.UpdateStatus(ctx, dbgen.UpdateStatusParams{
|
||||||
|
ID: id,
|
||||||
|
Status: int32(status),
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) DeleteBet(ctx context.Context, id int64) error {
|
func (s *Store) DeleteBet(ctx context.Context, id int64) error {
|
||||||
return s.queries.DeleteBet(ctx, id)
|
return s.queries.DeleteBet(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
|
||||||
// "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
// "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
@ -86,6 +87,42 @@ func (s *Store) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEven
|
||||||
}
|
}
|
||||||
return upcomingEvents, nil
|
return upcomingEvents, nil
|
||||||
}
|
}
|
||||||
|
func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32) ([]domain.UpcomingEvent, int64, error) {
|
||||||
|
events, err := s.queries.GetPaginatedUpcomingEvents(ctx, dbgen.GetPaginatedUpcomingEventsParams{
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset * limit,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
upcomingEvents := make([]domain.UpcomingEvent, len(events))
|
||||||
|
for i, e := range events {
|
||||||
|
upcomingEvents[i] = domain.UpcomingEvent{
|
||||||
|
ID: e.ID,
|
||||||
|
SportID: e.SportID.String,
|
||||||
|
MatchName: e.MatchName.String,
|
||||||
|
HomeTeam: e.HomeTeam.String,
|
||||||
|
AwayTeam: e.AwayTeam.String,
|
||||||
|
HomeTeamID: e.HomeTeamID.String,
|
||||||
|
AwayTeamID: e.AwayTeamID.String,
|
||||||
|
HomeKitImage: e.HomeKitImage.String,
|
||||||
|
AwayKitImage: e.AwayKitImage.String,
|
||||||
|
LeagueID: e.LeagueID.String,
|
||||||
|
LeagueName: e.LeagueName.String,
|
||||||
|
LeagueCC: e.LeagueCc.String,
|
||||||
|
StartTime: e.StartTime.Time.UTC(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalCount, err := s.queries.GetTotalEvents(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
numberOfPages := (totalCount) / int64(limit)
|
||||||
|
return upcomingEvents, numberOfPages, nil
|
||||||
|
}
|
||||||
func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
||||||
event, err := s.queries.GetUpcomingByID(ctx, ID)
|
event, err := s.queries.GetUpcomingByID(ctx, ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -108,4 +145,3 @@ func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.Upc
|
||||||
StartTime: event.StartTime.Time.UTC(),
|
StartTime: event.StartTime.Time.UTC(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package repository
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -180,28 +179,22 @@ func (s *Store) GetRawOddsByMarketID(ctx context.Context, rawOddsID string, upco
|
||||||
params := dbgen.GetRawOddsByMarketIDParams{
|
params := dbgen.GetRawOddsByMarketIDParams{
|
||||||
MarketID: pgtype.Text{String: rawOddsID, Valid: true},
|
MarketID: pgtype.Text{String: rawOddsID, Valid: true},
|
||||||
Fi: pgtype.Text{String: upcomingID, Valid: true},
|
Fi: pgtype.Text{String: upcomingID, Valid: true},
|
||||||
Limit: 1,
|
|
||||||
Offset: 0,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := s.queries.GetRawOddsByMarketID(ctx, params)
|
odds, err := s.queries.GetRawOddsByMarketID(ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.RawOddsByMarketID{}, err
|
return domain.RawOddsByMarketID{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rows) == 0 {
|
|
||||||
return domain.RawOddsByMarketID{}, fmt.Errorf("no raw odds found for market_id: %s", rawOddsID)
|
|
||||||
}
|
|
||||||
|
|
||||||
row := rows[0]
|
|
||||||
|
|
||||||
var rawOdds []json.RawMessage
|
var rawOdds []json.RawMessage
|
||||||
if err := json.Unmarshal(row.RawOdds, &rawOdds); err != nil {
|
if err := json.Unmarshal(odds.RawOdds, &rawOdds); err != nil {
|
||||||
return domain.RawOddsByMarketID{}, err
|
return domain.RawOddsByMarketID{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return domain.RawOddsByMarketID{
|
return domain.RawOddsByMarketID{
|
||||||
ID: int64(row.ID),
|
ID: int64(odds.ID),
|
||||||
|
MarketName: odds.MarketName.String,
|
||||||
|
Handicap: odds.Handicap.String,
|
||||||
RawOdds: func() []domain.RawMessage {
|
RawOdds: func() []domain.RawMessage {
|
||||||
converted := make([]domain.RawMessage, len(rawOdds))
|
converted := make([]domain.RawMessage, len(rawOdds))
|
||||||
for i, r := range rawOdds {
|
for i, r := range rawOdds {
|
||||||
|
|
@ -209,7 +202,7 @@ func (s *Store) GetRawOddsByMarketID(ctx context.Context, rawOddsID string, upco
|
||||||
}
|
}
|
||||||
return converted
|
return converted
|
||||||
}(),
|
}(),
|
||||||
FetchedAt: row.FetchedAt.Time,
|
FetchedAt: odds.FetchedAt.Time,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ func convertDBTicketOutcomes(ticket dbgen.TicketWithOutcome) domain.GetTicket {
|
||||||
MarketName: outcome.MarketName,
|
MarketName: outcome.MarketName,
|
||||||
Odd: outcome.Odd,
|
Odd: outcome.Odd,
|
||||||
OddName: outcome.OddName,
|
OddName: outcome.OddName,
|
||||||
|
OddHeader: outcome.OddHeader,
|
||||||
|
OddHandicap: outcome.OddHandicap,
|
||||||
Expires: outcome.Expires.Time,
|
Expires: outcome.Expires.Time,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -54,6 +56,8 @@ func convertDBCreateTicketOutcome(ticketOutcome domain.CreateTicketOutcome) dbge
|
||||||
MarketName: ticketOutcome.MarketName,
|
MarketName: ticketOutcome.MarketName,
|
||||||
Odd: ticketOutcome.Odd,
|
Odd: ticketOutcome.Odd,
|
||||||
OddName: ticketOutcome.OddName,
|
OddName: ticketOutcome.OddName,
|
||||||
|
OddHeader: ticketOutcome.OddHeader,
|
||||||
|
OddHandicap: ticketOutcome.OddHandicap,
|
||||||
Expires: pgtype.Timestamp{
|
Expires: pgtype.Timestamp{
|
||||||
Time: ticketOutcome.Expires,
|
Time: ticketOutcome.Expires,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,6 @@ type BetStore interface {
|
||||||
GetAllBets(ctx context.Context) ([]domain.GetBet, error)
|
GetAllBets(ctx context.Context) ([]domain.GetBet, error)
|
||||||
GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.GetBet, error)
|
GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.GetBet, error)
|
||||||
UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error
|
UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error
|
||||||
|
UpdateStatus(ctx context.Context, id int64, status domain.BetStatus) error
|
||||||
DeleteBet(ctx context.Context, id int64) error
|
DeleteBet(ctx context.Context, id int64) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,10 @@ func (s *Service) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) e
|
||||||
return s.betStore.UpdateCashOut(ctx, id, cashedOut)
|
return s.betStore.UpdateCashOut(ctx, id, cashedOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.BetStatus) error {
|
||||||
|
return s.betStore.UpdateStatus(ctx, id, status)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) DeleteBet(ctx context.Context, id int64) error {
|
func (s *Service) DeleteBet(ctx context.Context, id int64) error {
|
||||||
return s.betStore.DeleteBet(ctx, id)
|
return s.betStore.DeleteBet(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,6 @@ type Service interface {
|
||||||
FetchLiveEvents(ctx context.Context) error
|
FetchLiveEvents(ctx context.Context) error
|
||||||
FetchUpcomingEvents(ctx context.Context) error
|
FetchUpcomingEvents(ctx context.Context) error
|
||||||
GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
|
GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
|
||||||
|
GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32) ([]domain.UpcomingEvent, int64, error)
|
||||||
GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error)
|
GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,10 @@ func (s *service) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEv
|
||||||
return s.store.GetAllUpcomingEvents(ctx)
|
return s.store.GetAllUpcomingEvents(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *service) GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32) ([]domain.UpcomingEvent, int64, error) {
|
||||||
|
return s.store.GetPaginatedUpcomingEvents(ctx, limit, offset)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *service) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
func (s *service) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
||||||
return s.store.GetUpcomingEventByID(ctx, ID)
|
return s.store.GetUpcomingEventByID(ctx, ID)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,5 @@ type Service interface {
|
||||||
FetchNonLiveOdds(ctx context.Context) error
|
FetchNonLiveOdds(ctx context.Context) error
|
||||||
GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error)
|
GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error)
|
||||||
GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error)
|
GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error)
|
||||||
GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) ([]domain.RawOddsByMarketID, error)
|
GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.RawOddsByMarketID, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,13 +119,13 @@ func (s *ServiceImpl) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, err
|
||||||
return s.store.GetALLPrematchOdds(ctx)
|
return s.store.GetALLPrematchOdds(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceImpl) GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) ([]domain.RawOddsByMarketID, error) {
|
func (s *ServiceImpl) GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.RawOddsByMarketID, error) {
|
||||||
rows, err := s.store.GetRawOddsByMarketID(ctx, marketID, upcomingID)
|
rows, err := s.store.GetRawOddsByMarketID(ctx, marketID, upcomingID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return domain.RawOddsByMarketID{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return []domain.RawOddsByMarketID{rows}, nil
|
return rows, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceImpl) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset int32) ([]domain.Odd, error) {
|
func (s *ServiceImpl) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset int32) ([]domain.Odd, error) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
package httpserver
|
package httpserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
// "context"
|
"fmt"
|
||||||
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
|
|
@ -19,7 +18,6 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
}{
|
}{
|
||||||
|
|
||||||
// {
|
// {
|
||||||
|
|
||||||
// spec: "0 0 * * * *", // Every hour
|
// spec: "0 0 * * * *", // Every hour
|
||||||
// task: func() {
|
// task: func() {
|
||||||
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||||
|
|
@ -48,6 +46,8 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, job := range schedule {
|
for _, job := range schedule {
|
||||||
|
job.task()
|
||||||
|
fmt.Printf("here at")
|
||||||
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
||||||
log.Fatalf("Failed to schedule cron job: %v", err)
|
log.Fatalf("Failed to schedule cron job: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -9,6 +10,8 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
|
@ -18,16 +21,16 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreateBetOutcomeReq struct {
|
type CreateBetOutcomeReq struct {
|
||||||
BetID int64 `json:"bet_id" example:"1"`
|
// BetID int64 `json:"bet_id" example:"1"`
|
||||||
EventID int64 `json:"event_id" example:"1"`
|
EventID int64 `json:"event_id" example:"1"`
|
||||||
OddID int64 `json:"odd_id" example:"1"`
|
OddID int64 `json:"odd_id" example:"1"`
|
||||||
HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
|
||||||
AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
|
||||||
MarketID int64 `json:"market_id" example:"1"`
|
MarketID int64 `json:"market_id" example:"1"`
|
||||||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
// HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||||
Odd float32 `json:"odd" example:"1.5"`
|
// AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||||
OddName string `json:"odd_name" example:"1"`
|
// MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
// Odd float32 `json:"odd" example:"1.5"`
|
||||||
|
// OddName string `json:"odd_name" example:"1"`
|
||||||
|
// Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NullableInt64 struct {
|
type NullableInt64 struct {
|
||||||
|
|
@ -139,7 +142,7 @@ func convertBet(bet domain.GetBet) BetRes {
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /bet [post]
|
// @Router /bet [post]
|
||||||
func CreateBet(logger *slog.Logger, betSvc *bet.Service, userSvc *user.Service, branchSvc *branch.Service, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
func CreateBet(logger *slog.Logger, betSvc *bet.Service, userSvc *user.Service, branchSvc *branch.Service, walletSvc *wallet.Service, eventSvc event.Service, oddSvc odds.ServiceImpl, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
|
|
||||||
// Get user_id from middleware
|
// Get user_id from middleware
|
||||||
|
|
@ -160,6 +163,8 @@ func CreateBet(logger *slog.Logger, betSvc *bet.Service, userSvc *user.Service,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validating user by role
|
||||||
|
// Differentiating between offline and online bets
|
||||||
user, err := userSvc.GetUserByID(c.Context(), userID)
|
user, err := userSvc.GetUserByID(c.Context(), userID)
|
||||||
cashoutUUID := uuid.New()
|
cashoutUUID := uuid.New()
|
||||||
var bet domain.Bet
|
var bet domain.Bet
|
||||||
|
|
@ -226,28 +231,88 @@ func CreateBet(logger *slog.Logger, betSvc *bet.Service, userSvc *user.Service,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Validate Outcomes Here and make sure they didn't expire
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("CreateBetReq failed", "error", err)
|
logger.Error("CreateBetReq failed", "error", err)
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil)
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil)
|
||||||
}
|
}
|
||||||
var outcomes []domain.CreateBetOutcome = make([]domain.CreateBetOutcome, 0, len(req.Outcomes))
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// TODO Validate Outcomes Here and make sure they didn't expire
|
||||||
|
// Validation for creating tickets
|
||||||
|
if len(req.Outcomes) > 30 {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "Too many odds/outcomes selected", nil, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var outcomes []domain.CreateBetOutcome = make([]domain.CreateBetOutcome, 0, len(req.Outcomes))
|
||||||
for _, outcome := range req.Outcomes {
|
for _, outcome := range req.Outcomes {
|
||||||
|
eventIDStr := strconv.FormatInt(outcome.EventID, 10)
|
||||||
|
marketIDStr := strconv.FormatInt(outcome.MarketID, 10)
|
||||||
|
oddIDStr := strconv.FormatInt(outcome.OddID, 10)
|
||||||
|
event, err := eventSvc.GetUpcomingEventByID(c.Context(), eventIDStr)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid event id", err, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking to make sure the event hasn't already started
|
||||||
|
currentTime := time.Now()
|
||||||
|
if event.StartTime.Before(currentTime) {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "The event has already expired", nil, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
odds, err := oddSvc.GetRawOddsByMarketID(c.Context(), marketIDStr, eventIDStr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid market id", err, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
type rawOddType struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Odds string
|
||||||
|
Header string
|
||||||
|
Handicap string
|
||||||
|
}
|
||||||
|
var selectedOdd rawOddType
|
||||||
|
var isOddFound bool = false
|
||||||
|
for _, raw := range odds.RawOdds {
|
||||||
|
var rawOdd rawOddType
|
||||||
|
rawBytes, err := json.Marshal(raw)
|
||||||
|
err = json.Unmarshal(rawBytes, &rawOdd)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to unmarshal raw odd:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if rawOdd.ID == oddIDStr {
|
||||||
|
selectedOdd = rawOdd
|
||||||
|
isOddFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isOddFound {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid odd id", nil, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
||||||
|
|
||||||
outcomes = append(outcomes, domain.CreateBetOutcome{
|
outcomes = append(outcomes, domain.CreateBetOutcome{
|
||||||
BetID: bet.ID,
|
BetID: bet.ID,
|
||||||
EventID: outcome.EventID,
|
EventID: outcome.EventID,
|
||||||
OddID: outcome.OddID,
|
OddID: outcome.OddID,
|
||||||
HomeTeamName: outcome.HomeTeamName,
|
|
||||||
AwayTeamName: outcome.AwayTeamName,
|
|
||||||
MarketID: outcome.MarketID,
|
MarketID: outcome.MarketID,
|
||||||
MarketName: outcome.MarketName,
|
HomeTeamName: event.HomeTeam,
|
||||||
Odd: outcome.Odd,
|
AwayTeamName: event.AwayTeam,
|
||||||
OddName: outcome.OddName,
|
MarketName: odds.MarketName,
|
||||||
Expires: outcome.Expires,
|
Odd: float32(parsedOdd),
|
||||||
|
OddName: selectedOdd.Name,
|
||||||
|
OddHeader: selectedOdd.Header,
|
||||||
|
OddHandicap: selectedOdd.Handicap,
|
||||||
|
Expires: event.StartTime,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := betSvc.CreateBetOutcome(c.Context(), outcomes)
|
rows, err := betSvc.CreateBetOutcome(c.Context(), outcomes)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -96,17 +96,22 @@ func GetRawOddsByMarketID(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fi
|
||||||
// @Tags prematch
|
// @Tags prematch
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
|
// @Param page query int false "Page number"
|
||||||
|
// @Param page_size query int false "Page size"
|
||||||
// @Success 200 {array} domain.UpcomingEvent
|
// @Success 200 {array} domain.UpcomingEvent
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /prematch/events [get]
|
// @Router /prematch/events [get]
|
||||||
func GetAllUpcomingEvents(logger *slog.Logger, eventSvc event.Service) fiber.Handler {
|
func GetAllUpcomingEvents(logger *slog.Logger, eventSvc event.Service) fiber.Handler {
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
events, err := eventSvc.GetAllUpcomingEvents(c.Context())
|
page := c.QueryInt("page", 1)
|
||||||
|
pageSize := c.QueryInt("page_size", 10)
|
||||||
|
|
||||||
|
events, total, err := eventSvc.GetPaginatedUpcomingEvents(c.Context(), int32(pageSize), int32(page) - 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve all upcoming events", nil, nil)
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve all upcoming events", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", events, nil)
|
return response.WritePaginatedJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", events, nil, page, int(total))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
||||||
|
|
@ -13,16 +17,16 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreateTicketOutcomeReq struct {
|
type CreateTicketOutcomeReq struct {
|
||||||
TicketID int64 `json:"ticket_id" example:"1"`
|
// TicketID int64 `json:"ticket_id" example:"1"`
|
||||||
EventID int64 `json:"event_id" example:"1"`
|
EventID int64 `json:"event_id" example:"1"`
|
||||||
OddID int64 `json:"odd_id" example:"1"`
|
OddID int64 `json:"odd_id" example:"1"`
|
||||||
HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
|
||||||
AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
|
||||||
MarketID int64 `json:"market_id" example:"1"`
|
MarketID int64 `json:"market_id" example:"1"`
|
||||||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
// HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||||
Odd float32 `json:"odd" example:"1.5"`
|
// AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||||
OddName string `json:"odd_name" example:"1"`
|
// MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
// Odd float32 `json:"odd" example:"1.5"`
|
||||||
|
// OddName string `json:"odd_name" example:"1"`
|
||||||
|
// Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateTicketReq struct {
|
type CreateTicketReq struct {
|
||||||
|
|
@ -46,8 +50,7 @@ type CreateTicketRes struct {
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /ticket [post]
|
// @Router /ticket [post]
|
||||||
func CreateTicket(logger *slog.Logger, ticketSvc *ticket.Service,
|
func CreateTicket(logger *slog.Logger, ticketSvc *ticket.Service, eventSvc event.Service, oddSvc odds.ServiceImpl, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
validator *customvalidator.CustomValidator) fiber.Handler {
|
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
var req CreateTicketReq
|
var req CreateTicketReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
|
@ -64,6 +67,79 @@ func CreateTicket(logger *slog.Logger, ticketSvc *ticket.Service,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Validate Outcomes Here and make sure they didn't expire
|
// TODO Validate Outcomes Here and make sure they didn't expire
|
||||||
|
// Validation for creating tickets
|
||||||
|
if len(req.Outcomes) > 30 {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "Too many odds/outcomes selected", nil, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var outcomes []domain.CreateTicketOutcome = make([]domain.CreateTicketOutcome, 0, len(req.Outcomes))
|
||||||
|
for _, outcome := range req.Outcomes {
|
||||||
|
eventIDStr := strconv.FormatInt(outcome.EventID, 10)
|
||||||
|
marketIDStr := strconv.FormatInt(outcome.MarketID, 10)
|
||||||
|
oddIDStr := strconv.FormatInt(outcome.OddID, 10)
|
||||||
|
event, err := eventSvc.GetUpcomingEventByID(c.Context(), eventIDStr)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid event id", err, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking to make sure the event hasn't already started
|
||||||
|
currentTime := time.Now()
|
||||||
|
if event.StartTime.Before(currentTime) {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "The event has already expired", nil, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
odds, err := oddSvc.GetRawOddsByMarketID(c.Context(), marketIDStr, eventIDStr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid market id", err, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
type rawOddType struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Odds string
|
||||||
|
Header string
|
||||||
|
Handicap string
|
||||||
|
}
|
||||||
|
var selectedOdd rawOddType
|
||||||
|
var isOddFound bool = false
|
||||||
|
for _, raw := range odds.RawOdds {
|
||||||
|
var rawOdd rawOddType
|
||||||
|
rawBytes, err := json.Marshal(raw)
|
||||||
|
err = json.Unmarshal(rawBytes, &rawOdd)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to unmarshal raw odd:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if rawOdd.ID == oddIDStr {
|
||||||
|
selectedOdd = rawOdd
|
||||||
|
isOddFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isOddFound {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid odd id", nil, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
||||||
|
|
||||||
|
outcomes = append(outcomes, domain.CreateTicketOutcome{
|
||||||
|
EventID: outcome.EventID,
|
||||||
|
OddID: outcome.OddID,
|
||||||
|
MarketID: outcome.MarketID,
|
||||||
|
HomeTeamName: event.HomeTeam,
|
||||||
|
AwayTeamName: event.AwayTeam,
|
||||||
|
MarketName: odds.MarketName,
|
||||||
|
Odd: float32(parsedOdd),
|
||||||
|
OddName: selectedOdd.Name,
|
||||||
|
OddHeader: selectedOdd.Header,
|
||||||
|
OddHandicap: selectedOdd.Handicap,
|
||||||
|
Expires: event.StartTime,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
ticket, err := ticketSvc.CreateTicket(c.Context(), domain.CreateTicket{
|
ticket, err := ticketSvc.CreateTicket(c.Context(), domain.CreateTicket{
|
||||||
Amount: domain.ToCurrency(req.Amount),
|
Amount: domain.ToCurrency(req.Amount),
|
||||||
|
|
@ -76,22 +152,11 @@ func CreateTicket(logger *slog.Logger, ticketSvc *ticket.Service,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var outcomes []domain.CreateTicketOutcome = make([]domain.CreateTicketOutcome, 0, len(req.Outcomes))
|
// Add the ticket id now that it has fetched from the database
|
||||||
|
for index := range outcomes {
|
||||||
for _, outcome := range req.Outcomes {
|
outcomes[index].TicketID = ticket.ID
|
||||||
outcomes = append(outcomes, domain.CreateTicketOutcome{
|
|
||||||
TicketID: ticket.ID,
|
|
||||||
EventID: outcome.EventID,
|
|
||||||
OddID: outcome.OddID,
|
|
||||||
HomeTeamName: outcome.HomeTeamName,
|
|
||||||
AwayTeamName: outcome.AwayTeamName,
|
|
||||||
MarketID: outcome.MarketID,
|
|
||||||
MarketName: outcome.MarketName,
|
|
||||||
Odd: outcome.Odd,
|
|
||||||
OddName: outcome.OddName,
|
|
||||||
Expires: outcome.Expires,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := ticketSvc.CreateTicketOutcome(c.Context(), outcomes)
|
rows, err := ticketSvc.CreateTicketOutcome(c.Context(), outcomes)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,15 @@ type APIResponse struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Data interface{} `json:"data,omitempty"`
|
Data interface{} `json:"data,omitempty"`
|
||||||
Metadata interface{} `json:"metadata,omitempty"`
|
Metadata interface{} `json:"metadata,omitempty"`
|
||||||
|
Page *int `json:"page,omitempty"`
|
||||||
|
Total *int `json:"total,omitempty"`
|
||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAPIResponse(
|
func NewAPIResponse(
|
||||||
status Status, message string,
|
status Status, message string,
|
||||||
data interface{}, metadata interface{},
|
data interface{}, metadata interface{},
|
||||||
|
page *int, total *int,
|
||||||
) APIResponse {
|
) APIResponse {
|
||||||
|
|
||||||
return APIResponse{
|
return APIResponse{
|
||||||
|
|
@ -32,6 +35,8 @@ func NewAPIResponse(
|
||||||
Data: data,
|
Data: data,
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
Timestamp: time.Now(),
|
Timestamp: time.Now(),
|
||||||
|
Page: page,
|
||||||
|
Total: total,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func WriteJSON(c *fiber.Ctx, status int, message string, data, metadata interface{}) error {
|
func WriteJSON(c *fiber.Ctx, status int, message string, data, metadata interface{}) error {
|
||||||
|
|
@ -41,7 +46,18 @@ func WriteJSON(c *fiber.Ctx, status int, message string, data, metadata interfac
|
||||||
} else {
|
} else {
|
||||||
apiStatus = Error
|
apiStatus = Error
|
||||||
}
|
}
|
||||||
apiRes := NewAPIResponse(apiStatus, message, data, metadata)
|
apiRes := NewAPIResponse(apiStatus, message, data, metadata, nil, nil)
|
||||||
|
|
||||||
|
return c.Status(status).JSON(apiRes)
|
||||||
|
}
|
||||||
|
func WritePaginatedJSON(c *fiber.Ctx, status int, message string, data, metadata interface{}, page int, total int) error {
|
||||||
|
var apiStatus Status
|
||||||
|
if status >= 200 && status <= 299 {
|
||||||
|
apiStatus = Success
|
||||||
|
} else {
|
||||||
|
apiStatus = Error
|
||||||
|
}
|
||||||
|
apiRes := NewAPIResponse(apiStatus, message, data, metadata, &page, &total)
|
||||||
|
|
||||||
return c.Status(status).JSON(apiRes)
|
return c.Status(status).JSON(apiRes)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,12 +86,12 @@ func (a *App) initAppRoutes() {
|
||||||
a.fiber.Delete("/branch/:id/operation/:opID", a.authMiddleware, handlers.DeleteBranchOperation(a.logger, a.branchSvc, a.validator))
|
a.fiber.Delete("/branch/:id/operation/:opID", a.authMiddleware, handlers.DeleteBranchOperation(a.logger, a.branchSvc, a.validator))
|
||||||
|
|
||||||
// Ticket
|
// Ticket
|
||||||
a.fiber.Post("/ticket", handlers.CreateTicket(a.logger, a.ticketSvc, a.validator))
|
a.fiber.Post("/ticket", handlers.CreateTicket(a.logger, a.ticketSvc, a.eventSvc, *a.prematchSvc, a.validator))
|
||||||
a.fiber.Get("/ticket", handlers.GetAllTickets(a.logger, a.ticketSvc, a.validator))
|
a.fiber.Get("/ticket", handlers.GetAllTickets(a.logger, a.ticketSvc, a.validator))
|
||||||
a.fiber.Get("/ticket/:id", handlers.GetTicketByID(a.logger, a.ticketSvc, a.validator))
|
a.fiber.Get("/ticket/:id", handlers.GetTicketByID(a.logger, a.ticketSvc, a.validator))
|
||||||
|
|
||||||
// Bet
|
// Bet
|
||||||
a.fiber.Post("/bet", a.authMiddleware, handlers.CreateBet(a.logger, a.betSvc, a.userSvc, a.branchSvc, a.walletSvc, a.validator))
|
a.fiber.Post("/bet", a.authMiddleware, handlers.CreateBet(a.logger, a.betSvc, a.userSvc, a.branchSvc, a.walletSvc, a.eventSvc, *a.prematchSvc, a.validator))
|
||||||
a.fiber.Get("/bet", a.authMiddleware, handlers.GetAllBet(a.logger, a.betSvc, a.validator))
|
a.fiber.Get("/bet", a.authMiddleware, handlers.GetAllBet(a.logger, a.betSvc, a.validator))
|
||||||
a.fiber.Get("/bet/:id", a.authMiddleware, handlers.GetBetByID(a.logger, a.betSvc, a.validator))
|
a.fiber.Get("/bet/:id", a.authMiddleware, handlers.GetBetByID(a.logger, a.betSvc, a.validator))
|
||||||
a.fiber.Get("/bet/cashout/:id", a.authMiddleware, handlers.GetBetByCashoutID(a.logger, a.betSvc, a.validator))
|
a.fiber.Get("/bet/cashout/:id", a.authMiddleware, handlers.GetBetByCashoutID(a.logger, a.betSvc, a.validator))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user