adding fi
This commit is contained in:
parent
6c478df2b4
commit
b8d15695a4
|
|
@ -90,12 +90,10 @@ CREATE TABLE odds (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
event_id TEXT,
|
event_id TEXT,
|
||||||
fi TEXT,
|
fi TEXT,
|
||||||
raw_event_id TEXT,
|
|
||||||
market_type TEXT NOT NULL,
|
market_type TEXT NOT NULL,
|
||||||
market_name TEXT,
|
market_name TEXT,
|
||||||
market_category TEXT,
|
market_category TEXT,
|
||||||
market_id TEXT,
|
market_id TEXT,
|
||||||
header TEXT,
|
|
||||||
name TEXT,
|
name TEXT,
|
||||||
handicap TEXT,
|
handicap TEXT,
|
||||||
odds_value DOUBLE PRECISION,
|
odds_value DOUBLE PRECISION,
|
||||||
|
|
@ -105,7 +103,7 @@ CREATE TABLE odds (
|
||||||
fetched_at TIMESTAMP DEFAULT now(),
|
fetched_at TIMESTAMP DEFAULT now(),
|
||||||
source TEXT DEFAULT 'b365api',
|
source TEXT DEFAULT 'b365api',
|
||||||
is_active BOOLEAN DEFAULT true,
|
is_active BOOLEAN DEFAULT true,
|
||||||
UNIQUE (event_id, market_id, header, name, handicap)
|
UNIQUE (event_id, market_id, name, handicap)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,10 @@
|
||||||
INSERT INTO odds (
|
INSERT INTO odds (
|
||||||
event_id,
|
event_id,
|
||||||
fi,
|
fi,
|
||||||
raw_event_id,
|
|
||||||
market_type,
|
market_type,
|
||||||
market_name,
|
market_name,
|
||||||
market_category,
|
market_category,
|
||||||
market_id,
|
market_id,
|
||||||
header,
|
|
||||||
name,
|
name,
|
||||||
handicap,
|
handicap,
|
||||||
odds_value,
|
odds_value,
|
||||||
|
|
@ -19,48 +17,21 @@ INSERT INTO odds (
|
||||||
fetched_at
|
fetched_at
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2, $3, $4, $5, $6, $7,
|
$1, $2, $3, $4, $5, $6, $7,
|
||||||
$8, $9, $10, $11, $12, $13, $14,
|
$8, $9, $10, $11, $12, $13, $14, $15
|
||||||
true, 'b365api', now()
|
|
||||||
)
|
)
|
||||||
ON CONFLICT (event_id, market_id, header, name, handicap) DO UPDATE SET
|
ON CONFLICT (market_id, name, handicap) DO UPDATE SET
|
||||||
odds_value = EXCLUDED.odds_value,
|
odds_value = EXCLUDED.odds_value,
|
||||||
raw_odds = EXCLUDED.raw_odds,
|
raw_odds = EXCLUDED.raw_odds,
|
||||||
market_type = EXCLUDED.market_type,
|
market_type = EXCLUDED.market_type,
|
||||||
market_name = EXCLUDED.market_name,
|
market_name = EXCLUDED.market_name,
|
||||||
market_category = EXCLUDED.market_category,
|
market_category = EXCLUDED.market_category,
|
||||||
fetched_at = now(),
|
fetched_at = EXCLUDED.fetched_at,
|
||||||
is_active = true,
|
is_active = EXCLUDED.is_active,
|
||||||
source = 'b365api',
|
source = EXCLUDED.source,
|
||||||
fi = EXCLUDED.fi,
|
fi = EXCLUDED.fi;
|
||||||
raw_event_id = EXCLUDED.raw_event_id;
|
|
||||||
|
|
||||||
|
|
||||||
-- name: GetPrematchOdds :many
|
-- name: GetPrematchOdds :many
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
|
||||||
event_id,
|
|
||||||
fi,
|
|
||||||
raw_event_id,
|
|
||||||
market_type,
|
|
||||||
market_name,
|
|
||||||
market_category,
|
|
||||||
market_id,
|
|
||||||
header,
|
|
||||||
name,
|
|
||||||
handicap,
|
|
||||||
odds_value,
|
|
||||||
section,
|
|
||||||
category,
|
|
||||||
raw_odds,
|
|
||||||
fetched_at,
|
|
||||||
source,
|
|
||||||
is_active
|
|
||||||
FROM odds
|
|
||||||
WHERE event_id = $1 AND is_active = true AND source = 'b365api';
|
|
||||||
|
|
||||||
-- name: GetALLPrematchOdds :many
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
event_id,
|
event_id,
|
||||||
fi,
|
fi,
|
||||||
market_type,
|
market_type,
|
||||||
|
|
@ -78,10 +49,30 @@ SELECT
|
||||||
is_active
|
is_active
|
||||||
FROM odds
|
FROM odds
|
||||||
WHERE is_active = true AND source = 'b365api';
|
WHERE is_active = true AND source = 'b365api';
|
||||||
|
|
||||||
|
-- name: GetALLPrematchOdds :many
|
||||||
|
SELECT
|
||||||
|
event_id,
|
||||||
|
fi,
|
||||||
|
market_type,
|
||||||
|
market_name,
|
||||||
|
market_category,
|
||||||
|
market_id,
|
||||||
|
name,
|
||||||
|
handicap,
|
||||||
|
odds_value,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
raw_odds,
|
||||||
|
fetched_at,
|
||||||
|
source,
|
||||||
|
is_active
|
||||||
|
FROM odds
|
||||||
|
WHERE is_active = true AND source = 'b365api';
|
||||||
|
|
||||||
-- name: GetRawOddsByID :one
|
-- name: GetRawOddsByID :one
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
event_id,
|
|
||||||
raw_odds,
|
raw_odds,
|
||||||
fetched_at
|
fetched_at
|
||||||
FROM odds
|
FROM odds
|
||||||
|
|
@ -89,4 +80,30 @@ WHERE
|
||||||
raw_odds @> $1::jsonb AND
|
raw_odds @> $1::jsonb AND
|
||||||
is_active = true AND
|
is_active = true AND
|
||||||
source = 'b365api'
|
source = 'b365api'
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetPrematchOddsByUpcomingID :many
|
||||||
|
SELECT
|
||||||
|
o.event_id,
|
||||||
|
o.fi,
|
||||||
|
o.market_type,
|
||||||
|
o.market_name,
|
||||||
|
o.market_category,
|
||||||
|
o.market_id,
|
||||||
|
o.name,
|
||||||
|
o.handicap,
|
||||||
|
o.odds_value,
|
||||||
|
o.section,
|
||||||
|
o.category,
|
||||||
|
o.raw_odds,
|
||||||
|
o.fetched_at,
|
||||||
|
o.source,
|
||||||
|
o.is_active
|
||||||
|
FROM odds o
|
||||||
|
JOIN events e ON o.fi = e.id
|
||||||
|
WHERE e.id = $1
|
||||||
|
AND e.is_live = false
|
||||||
|
AND e.status = 'upcoming'
|
||||||
|
AND o.is_active = true
|
||||||
|
AND o.source = 'b365api'
|
||||||
|
LIMIT $2 OFFSET $3;
|
||||||
64
docs/docs.go
64
docs/docs.go
|
|
@ -332,6 +332,65 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/prematch/odds/upcoming/{upcoming_id}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"prematch"
|
||||||
|
],
|
||||||
|
"summary": "Retrieve prematch odds by upcoming ID (FI)",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Upcoming Event ID (FI)",
|
||||||
|
"name": "upcoming_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Number of results to return (default: 10)",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Number of results to skip (default: 0)",
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.Odd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/prematch/odds/{event_id}": {
|
"/prematch/odds/{event_id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Retrieve prematch odds for a specific event by event ID",
|
"description": "Retrieve prematch odds for a specific event by event ID",
|
||||||
|
|
@ -669,9 +728,6 @@ const docTemplate = `{
|
||||||
"handicap": {
|
"handicap": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"id": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"is_active": {
|
"is_active": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|
@ -685,11 +741,9 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"market_type": {
|
"market_type": {
|
||||||
"description": "RawEventID string ` + "`" + `json:\"raw_event_id\"` + "`" + `",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"description": "Header string ` + "`" + `json:\"header\"` + "`" + `",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"odds_value": {
|
"odds_value": {
|
||||||
|
|
|
||||||
|
|
@ -324,6 +324,65 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/prematch/odds/upcoming/{upcoming_id}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"prematch"
|
||||||
|
],
|
||||||
|
"summary": "Retrieve prematch odds by upcoming ID (FI)",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Upcoming Event ID (FI)",
|
||||||
|
"name": "upcoming_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Number of results to return (default: 10)",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Number of results to skip (default: 0)",
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.Odd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/prematch/odds/{event_id}": {
|
"/prematch/odds/{event_id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Retrieve prematch odds for a specific event by event ID",
|
"description": "Retrieve prematch odds for a specific event by event ID",
|
||||||
|
|
@ -661,9 +720,6 @@
|
||||||
"handicap": {
|
"handicap": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"id": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"is_active": {
|
"is_active": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|
@ -677,11 +733,9 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"market_type": {
|
"market_type": {
|
||||||
"description": "RawEventID string `json:\"raw_event_id\"`",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"description": "Header string `json:\"header\"`",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"odds_value": {
|
"odds_value": {
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,6 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
handicap:
|
handicap:
|
||||||
type: string
|
type: string
|
||||||
id:
|
|
||||||
type: integer
|
|
||||||
is_active:
|
is_active:
|
||||||
type: boolean
|
type: boolean
|
||||||
market_category:
|
market_category:
|
||||||
|
|
@ -22,10 +20,8 @@ definitions:
|
||||||
market_name:
|
market_name:
|
||||||
type: string
|
type: string
|
||||||
market_type:
|
market_type:
|
||||||
description: RawEventID string `json:"raw_event_id"`
|
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
description: Header string `json:"header"`
|
|
||||||
type: string
|
type: string
|
||||||
odds_value:
|
odds_value:
|
||||||
type: number
|
type: number
|
||||||
|
|
@ -498,6 +494,46 @@ paths:
|
||||||
summary: Retrieve raw odds by ID
|
summary: Retrieve raw odds by ID
|
||||||
tags:
|
tags:
|
||||||
- prematch
|
- prematch
|
||||||
|
/prematch/odds/upcoming/{upcoming_id}:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Retrieve prematch odds by upcoming event ID (FI from Bet365) with
|
||||||
|
optional pagination
|
||||||
|
parameters:
|
||||||
|
- description: Upcoming Event ID (FI)
|
||||||
|
in: path
|
||||||
|
name: upcoming_id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: 'Number of results to return (default: 10)'
|
||||||
|
in: query
|
||||||
|
name: limit
|
||||||
|
type: integer
|
||||||
|
- description: 'Number of results to skip (default: 0)'
|
||||||
|
in: query
|
||||||
|
name: offset
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/domain.Odd'
|
||||||
|
type: array
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
summary: Retrieve prematch odds by upcoming ID (FI)
|
||||||
|
tags:
|
||||||
|
- prematch
|
||||||
/user/checkPhoneEmailExist:
|
/user/checkPhoneEmailExist:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,10 @@ type Odd struct {
|
||||||
ID int32
|
ID int32
|
||||||
EventID pgtype.Text
|
EventID pgtype.Text
|
||||||
Fi pgtype.Text
|
Fi pgtype.Text
|
||||||
RawEventID pgtype.Text
|
|
||||||
MarketType string
|
MarketType string
|
||||||
MarketName pgtype.Text
|
MarketName pgtype.Text
|
||||||
MarketCategory pgtype.Text
|
MarketCategory pgtype.Text
|
||||||
MarketID pgtype.Text
|
MarketID pgtype.Text
|
||||||
Header pgtype.Text
|
|
||||||
Name pgtype.Text
|
Name pgtype.Text
|
||||||
Handicap pgtype.Text
|
Handicap pgtype.Text
|
||||||
OddsValue pgtype.Float8
|
OddsValue pgtype.Float8
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import (
|
||||||
|
|
||||||
const GetALLPrematchOdds = `-- name: GetALLPrematchOdds :many
|
const GetALLPrematchOdds = `-- name: GetALLPrematchOdds :many
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
|
||||||
event_id,
|
event_id,
|
||||||
fi,
|
fi,
|
||||||
market_type,
|
market_type,
|
||||||
|
|
@ -34,7 +33,6 @@ WHERE is_active = true AND source = 'b365api'
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetALLPrematchOddsRow struct {
|
type GetALLPrematchOddsRow struct {
|
||||||
ID int32
|
|
||||||
EventID pgtype.Text
|
EventID pgtype.Text
|
||||||
Fi pgtype.Text
|
Fi pgtype.Text
|
||||||
MarketType string
|
MarketType string
|
||||||
|
|
@ -62,7 +60,6 @@ func (q *Queries) GetALLPrematchOdds(ctx context.Context) ([]GetALLPrematchOddsR
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i GetALLPrematchOddsRow
|
var i GetALLPrematchOddsRow
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.ID,
|
|
||||||
&i.EventID,
|
&i.EventID,
|
||||||
&i.Fi,
|
&i.Fi,
|
||||||
&i.MarketType,
|
&i.MarketType,
|
||||||
|
|
@ -91,15 +88,12 @@ func (q *Queries) GetALLPrematchOdds(ctx context.Context) ([]GetALLPrematchOddsR
|
||||||
|
|
||||||
const GetPrematchOdds = `-- name: GetPrematchOdds :many
|
const GetPrematchOdds = `-- name: GetPrematchOdds :many
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
|
||||||
event_id,
|
event_id,
|
||||||
fi,
|
fi,
|
||||||
raw_event_id,
|
|
||||||
market_type,
|
market_type,
|
||||||
market_name,
|
market_name,
|
||||||
market_category,
|
market_category,
|
||||||
market_id,
|
market_id,
|
||||||
header,
|
|
||||||
name,
|
name,
|
||||||
handicap,
|
handicap,
|
||||||
odds_value,
|
odds_value,
|
||||||
|
|
@ -110,28 +104,130 @@ SELECT
|
||||||
source,
|
source,
|
||||||
is_active
|
is_active
|
||||||
FROM odds
|
FROM odds
|
||||||
WHERE event_id = $1 AND is_active = true AND source = 'b365api'
|
WHERE is_active = true AND source = 'b365api'
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetPrematchOdds(ctx context.Context, eventID pgtype.Text) ([]Odd, error) {
|
type GetPrematchOddsRow struct {
|
||||||
rows, err := q.db.Query(ctx, GetPrematchOdds, eventID)
|
EventID pgtype.Text
|
||||||
|
Fi pgtype.Text
|
||||||
|
MarketType string
|
||||||
|
MarketName pgtype.Text
|
||||||
|
MarketCategory pgtype.Text
|
||||||
|
MarketID pgtype.Text
|
||||||
|
Name pgtype.Text
|
||||||
|
Handicap pgtype.Text
|
||||||
|
OddsValue pgtype.Float8
|
||||||
|
Section string
|
||||||
|
Category pgtype.Text
|
||||||
|
RawOdds []byte
|
||||||
|
FetchedAt pgtype.Timestamp
|
||||||
|
Source pgtype.Text
|
||||||
|
IsActive pgtype.Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetPrematchOdds(ctx context.Context) ([]GetPrematchOddsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetPrematchOdds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []Odd
|
var items []GetPrematchOddsRow
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i Odd
|
var i GetPrematchOddsRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.EventID,
|
||||||
|
&i.Fi,
|
||||||
|
&i.MarketType,
|
||||||
|
&i.MarketName,
|
||||||
|
&i.MarketCategory,
|
||||||
|
&i.MarketID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Handicap,
|
||||||
|
&i.OddsValue,
|
||||||
|
&i.Section,
|
||||||
|
&i.Category,
|
||||||
|
&i.RawOdds,
|
||||||
|
&i.FetchedAt,
|
||||||
|
&i.Source,
|
||||||
|
&i.IsActive,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetPrematchOddsByUpcomingID = `-- name: GetPrematchOddsByUpcomingID :many
|
||||||
|
SELECT
|
||||||
|
o.event_id,
|
||||||
|
o.fi,
|
||||||
|
o.market_type,
|
||||||
|
o.market_name,
|
||||||
|
o.market_category,
|
||||||
|
o.market_id,
|
||||||
|
o.name,
|
||||||
|
o.handicap,
|
||||||
|
o.odds_value,
|
||||||
|
o.section,
|
||||||
|
o.category,
|
||||||
|
o.raw_odds,
|
||||||
|
o.fetched_at,
|
||||||
|
o.source,
|
||||||
|
o.is_active
|
||||||
|
FROM odds o
|
||||||
|
JOIN events e ON o.fi = e.id
|
||||||
|
WHERE e.id = $1
|
||||||
|
AND e.is_live = false
|
||||||
|
AND e.status = 'upcoming'
|
||||||
|
AND o.is_active = true
|
||||||
|
AND o.source = 'b365api'
|
||||||
|
LIMIT $2 OFFSET $3
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetPrematchOddsByUpcomingIDParams struct {
|
||||||
|
ID string
|
||||||
|
Limit int32
|
||||||
|
Offset int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetPrematchOddsByUpcomingIDRow struct {
|
||||||
|
EventID pgtype.Text
|
||||||
|
Fi pgtype.Text
|
||||||
|
MarketType string
|
||||||
|
MarketName pgtype.Text
|
||||||
|
MarketCategory pgtype.Text
|
||||||
|
MarketID pgtype.Text
|
||||||
|
Name pgtype.Text
|
||||||
|
Handicap pgtype.Text
|
||||||
|
OddsValue pgtype.Float8
|
||||||
|
Section string
|
||||||
|
Category pgtype.Text
|
||||||
|
RawOdds []byte
|
||||||
|
FetchedAt pgtype.Timestamp
|
||||||
|
Source pgtype.Text
|
||||||
|
IsActive pgtype.Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetPrematchOddsByUpcomingID(ctx context.Context, arg GetPrematchOddsByUpcomingIDParams) ([]GetPrematchOddsByUpcomingIDRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetPrematchOddsByUpcomingID, arg.ID, arg.Limit, arg.Offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetPrematchOddsByUpcomingIDRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetPrematchOddsByUpcomingIDRow
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.ID,
|
|
||||||
&i.EventID,
|
&i.EventID,
|
||||||
&i.Fi,
|
&i.Fi,
|
||||||
&i.RawEventID,
|
|
||||||
&i.MarketType,
|
&i.MarketType,
|
||||||
&i.MarketName,
|
&i.MarketName,
|
||||||
&i.MarketCategory,
|
&i.MarketCategory,
|
||||||
&i.MarketID,
|
&i.MarketID,
|
||||||
&i.Header,
|
|
||||||
&i.Name,
|
&i.Name,
|
||||||
&i.Handicap,
|
&i.Handicap,
|
||||||
&i.OddsValue,
|
&i.OddsValue,
|
||||||
|
|
@ -155,7 +251,6 @@ func (q *Queries) GetPrematchOdds(ctx context.Context, eventID pgtype.Text) ([]O
|
||||||
const GetRawOddsByID = `-- name: GetRawOddsByID :one
|
const GetRawOddsByID = `-- name: GetRawOddsByID :one
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
event_id,
|
|
||||||
raw_odds,
|
raw_odds,
|
||||||
fetched_at
|
fetched_at
|
||||||
FROM odds
|
FROM odds
|
||||||
|
|
@ -168,7 +263,6 @@ LIMIT 1
|
||||||
|
|
||||||
type GetRawOddsByIDRow struct {
|
type GetRawOddsByIDRow struct {
|
||||||
ID int32
|
ID int32
|
||||||
EventID pgtype.Text
|
|
||||||
RawOdds []byte
|
RawOdds []byte
|
||||||
FetchedAt pgtype.Timestamp
|
FetchedAt pgtype.Timestamp
|
||||||
}
|
}
|
||||||
|
|
@ -176,12 +270,7 @@ type GetRawOddsByIDRow struct {
|
||||||
func (q *Queries) GetRawOddsByID(ctx context.Context, dollar_1 []byte) (GetRawOddsByIDRow, error) {
|
func (q *Queries) GetRawOddsByID(ctx context.Context, dollar_1 []byte) (GetRawOddsByIDRow, error) {
|
||||||
row := q.db.QueryRow(ctx, GetRawOddsByID, dollar_1)
|
row := q.db.QueryRow(ctx, GetRawOddsByID, dollar_1)
|
||||||
var i GetRawOddsByIDRow
|
var i GetRawOddsByIDRow
|
||||||
err := row.Scan(
|
err := row.Scan(&i.ID, &i.RawOdds, &i.FetchedAt)
|
||||||
&i.ID,
|
|
||||||
&i.EventID,
|
|
||||||
&i.RawOdds,
|
|
||||||
&i.FetchedAt,
|
|
||||||
)
|
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,12 +278,10 @@ const InsertNonLiveOdd = `-- name: InsertNonLiveOdd :exec
|
||||||
INSERT INTO odds (
|
INSERT INTO odds (
|
||||||
event_id,
|
event_id,
|
||||||
fi,
|
fi,
|
||||||
raw_event_id,
|
|
||||||
market_type,
|
market_type,
|
||||||
market_name,
|
market_name,
|
||||||
market_category,
|
market_category,
|
||||||
market_id,
|
market_id,
|
||||||
header,
|
|
||||||
name,
|
name,
|
||||||
handicap,
|
handicap,
|
||||||
odds_value,
|
odds_value,
|
||||||
|
|
@ -206,55 +293,55 @@ INSERT INTO odds (
|
||||||
fetched_at
|
fetched_at
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2, $3, $4, $5, $6, $7,
|
$1, $2, $3, $4, $5, $6, $7,
|
||||||
$8, $9, $10, $11, $12, $13, $14,
|
$8, $9, $10, $11, $12, $13, $14, $15
|
||||||
true, 'b365api', now()
|
|
||||||
)
|
)
|
||||||
ON CONFLICT (event_id, market_id, header, name, handicap) DO UPDATE SET
|
ON CONFLICT (market_id, name, handicap) DO UPDATE SET
|
||||||
odds_value = EXCLUDED.odds_value,
|
odds_value = EXCLUDED.odds_value,
|
||||||
raw_odds = EXCLUDED.raw_odds,
|
raw_odds = EXCLUDED.raw_odds,
|
||||||
market_type = EXCLUDED.market_type,
|
market_type = EXCLUDED.market_type,
|
||||||
market_name = EXCLUDED.market_name,
|
market_name = EXCLUDED.market_name,
|
||||||
market_category = EXCLUDED.market_category,
|
market_category = EXCLUDED.market_category,
|
||||||
fetched_at = now(),
|
fetched_at = EXCLUDED.fetched_at,
|
||||||
is_active = true,
|
is_active = EXCLUDED.is_active,
|
||||||
source = 'b365api',
|
source = EXCLUDED.source,
|
||||||
fi = EXCLUDED.fi,
|
fi = EXCLUDED.fi
|
||||||
raw_event_id = EXCLUDED.raw_event_id
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type InsertNonLiveOddParams struct {
|
type InsertNonLiveOddParams struct {
|
||||||
EventID pgtype.Text
|
EventID pgtype.Text
|
||||||
Fi pgtype.Text
|
Fi pgtype.Text
|
||||||
RawEventID pgtype.Text
|
|
||||||
MarketType string
|
MarketType string
|
||||||
MarketName pgtype.Text
|
MarketName pgtype.Text
|
||||||
MarketCategory pgtype.Text
|
MarketCategory pgtype.Text
|
||||||
MarketID pgtype.Text
|
MarketID pgtype.Text
|
||||||
Header pgtype.Text
|
|
||||||
Name pgtype.Text
|
Name pgtype.Text
|
||||||
Handicap pgtype.Text
|
Handicap pgtype.Text
|
||||||
OddsValue pgtype.Float8
|
OddsValue pgtype.Float8
|
||||||
Section string
|
Section string
|
||||||
Category pgtype.Text
|
Category pgtype.Text
|
||||||
RawOdds []byte
|
RawOdds []byte
|
||||||
|
IsActive pgtype.Bool
|
||||||
|
Source pgtype.Text
|
||||||
|
FetchedAt pgtype.Timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) InsertNonLiveOdd(ctx context.Context, arg InsertNonLiveOddParams) error {
|
func (q *Queries) InsertNonLiveOdd(ctx context.Context, arg InsertNonLiveOddParams) error {
|
||||||
_, err := q.db.Exec(ctx, InsertNonLiveOdd,
|
_, err := q.db.Exec(ctx, InsertNonLiveOdd,
|
||||||
arg.EventID,
|
arg.EventID,
|
||||||
arg.Fi,
|
arg.Fi,
|
||||||
arg.RawEventID,
|
|
||||||
arg.MarketType,
|
arg.MarketType,
|
||||||
arg.MarketName,
|
arg.MarketName,
|
||||||
arg.MarketCategory,
|
arg.MarketCategory,
|
||||||
arg.MarketID,
|
arg.MarketID,
|
||||||
arg.Header,
|
|
||||||
arg.Name,
|
arg.Name,
|
||||||
arg.Handicap,
|
arg.Handicap,
|
||||||
arg.OddsValue,
|
arg.OddsValue,
|
||||||
arg.Section,
|
arg.Section,
|
||||||
arg.Category,
|
arg.Category,
|
||||||
arg.RawOdds,
|
arg.RawOdds,
|
||||||
|
arg.IsActive,
|
||||||
|
arg.Source,
|
||||||
|
arg.FetchedAt,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,23 +16,18 @@ type Market struct {
|
||||||
MarketID string
|
MarketID string
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
Odds []json.RawMessage
|
Odds []json.RawMessage
|
||||||
|
|
||||||
Header string
|
|
||||||
Name string
|
Name string
|
||||||
Handicap string
|
Handicap string
|
||||||
OddsVal float64
|
OddsVal float64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Odd struct {
|
type Odd struct {
|
||||||
ID int64 `json:"id"`
|
|
||||||
EventID string `json:"event_id"`
|
EventID string `json:"event_id"`
|
||||||
Fi string `json:"fi"`
|
Fi string `json:"fi"`
|
||||||
// RawEventID string `json:"raw_event_id"`
|
|
||||||
MarketType string `json:"market_type"`
|
MarketType string `json:"market_type"`
|
||||||
MarketName string `json:"market_name"`
|
MarketName string `json:"market_name"`
|
||||||
MarketCategory string `json:"market_category"`
|
MarketCategory string `json:"market_category"`
|
||||||
MarketID string `json:"market_id"`
|
MarketID string `json:"market_id"`
|
||||||
// Header string `json:"header"`
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Handicap string `json:"handicap"`
|
Handicap string `json:"handicap"`
|
||||||
OddsValue float64 `json:"odds_value"`
|
OddsValue float64 `json:"odds_value"`
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ func (s *Store) SaveNonLiveMarket(ctx context.Context, m domain.Market) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
header := getString(item["header"])
|
|
||||||
name := getString(item["name"])
|
name := getString(item["name"])
|
||||||
handicap := getString(item["handicap"])
|
handicap := getString(item["handicap"])
|
||||||
oddsVal := getFloat(item["odds"])
|
oddsVal := getFloat(item["odds"])
|
||||||
|
|
@ -33,23 +32,24 @@ func (s *Store) SaveNonLiveMarket(ctx context.Context, m domain.Market) error {
|
||||||
params := dbgen.InsertNonLiveOddParams{
|
params := dbgen.InsertNonLiveOddParams{
|
||||||
EventID: pgtype.Text{String: m.EventID, Valid: m.EventID != ""},
|
EventID: pgtype.Text{String: m.EventID, Valid: m.EventID != ""},
|
||||||
Fi: pgtype.Text{String: m.FI, Valid: m.FI != ""},
|
Fi: pgtype.Text{String: m.FI, Valid: m.FI != ""},
|
||||||
RawEventID: pgtype.Text{String: m.EventID, Valid: m.EventID != ""},
|
|
||||||
MarketType: m.MarketType,
|
MarketType: m.MarketType,
|
||||||
MarketName: pgtype.Text{String: m.MarketName, Valid: m.MarketName != ""},
|
MarketName: pgtype.Text{String: m.MarketName, Valid: m.MarketName != ""},
|
||||||
MarketCategory: pgtype.Text{String: m.MarketCategory, Valid: m.MarketCategory != ""},
|
MarketCategory: pgtype.Text{String: m.MarketCategory, Valid: m.MarketCategory != ""},
|
||||||
MarketID: pgtype.Text{String: m.MarketID, Valid: m.MarketID != ""},
|
MarketID: pgtype.Text{String: m.MarketID, Valid: m.MarketID != ""},
|
||||||
Header: pgtype.Text{String: header, Valid: header != ""},
|
|
||||||
Name: pgtype.Text{String: name, Valid: name != ""},
|
Name: pgtype.Text{String: name, Valid: name != ""},
|
||||||
Handicap: pgtype.Text{String: handicap, Valid: handicap != ""},
|
Handicap: pgtype.Text{String: handicap, Valid: handicap != ""},
|
||||||
OddsValue: pgtype.Float8{Float64: oddsVal, Valid: oddsVal != 0},
|
OddsValue: pgtype.Float8{Float64: oddsVal, Valid: oddsVal != 0},
|
||||||
Section: m.MarketCategory,
|
Section: m.MarketCategory,
|
||||||
Category: pgtype.Text{Valid: false},
|
Category: pgtype.Text{Valid: false},
|
||||||
RawOdds: rawOddsBytes,
|
RawOdds: rawOddsBytes,
|
||||||
|
IsActive: pgtype.Bool{Bool: true, Valid: true},
|
||||||
|
Source: pgtype.Text{String: "b365api", Valid: true},
|
||||||
|
FetchedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.queries.InsertNonLiveOdd(ctx, params)
|
err := s.queries.InsertNonLiveOdd(ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = writeFailedMarketLog(m, err)
|
_ = writeFailedMarketLog(m, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -103,9 +103,7 @@ func getFloat(v interface{}) float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
|
func (s *Store) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
|
||||||
eventIDParam := pgtype.Text{String: eventID, Valid: eventID != ""}
|
odds, err := s.queries.GetPrematchOdds(ctx)
|
||||||
|
|
||||||
odds, err := s.queries.GetPrematchOdds(ctx, eventIDParam)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -113,15 +111,12 @@ func (s *Store) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.O
|
||||||
domainOdds := make([]domain.Odd, len(odds))
|
domainOdds := make([]domain.Odd, len(odds))
|
||||||
for i, odd := range odds {
|
for i, odd := range odds {
|
||||||
domainOdds[i] = domain.Odd{
|
domainOdds[i] = domain.Odd{
|
||||||
ID: int64(odd.ID),
|
|
||||||
EventID: odd.EventID.String,
|
EventID: odd.EventID.String,
|
||||||
Fi: odd.Fi.String,
|
Fi: odd.Fi.String,
|
||||||
// RawEventID: odd.RawEventID.String,
|
|
||||||
MarketType: odd.MarketType,
|
MarketType: odd.MarketType,
|
||||||
MarketName: odd.MarketName.String,
|
MarketName: odd.MarketName.String,
|
||||||
MarketCategory: odd.MarketCategory.String,
|
MarketCategory: odd.MarketCategory.String,
|
||||||
MarketID: odd.MarketID.String,
|
MarketID: odd.MarketID.String,
|
||||||
// Header: odd.Header.String,
|
|
||||||
Name: odd.Name.String,
|
Name: odd.Name.String,
|
||||||
Handicap: odd.Handicap.String,
|
Handicap: odd.Handicap.String,
|
||||||
OddsValue: odd.OddsValue.Float64,
|
OddsValue: odd.OddsValue.Float64,
|
||||||
|
|
@ -152,7 +147,7 @@ func (s *Store) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) {
|
||||||
domainOdds := make([]domain.Odd, len(rows))
|
domainOdds := make([]domain.Odd, len(rows))
|
||||||
for i, row := range rows {
|
for i, row := range rows {
|
||||||
domainOdds[i] = domain.Odd{
|
domainOdds[i] = domain.Odd{
|
||||||
ID: int64(row.ID),
|
// ID: int64(row.ID),
|
||||||
EventID: row.EventID.String,
|
EventID: row.EventID.String,
|
||||||
Fi: row.Fi.String,
|
Fi: row.Fi.String,
|
||||||
MarketType: row.MarketType,
|
MarketType: row.MarketType,
|
||||||
|
|
@ -195,7 +190,6 @@ func (s *Store) GetRawOddsByID(ctx context.Context, rawOddsID string) (domain.Ra
|
||||||
|
|
||||||
return domain.RawOddsByID{
|
return domain.RawOddsByID{
|
||||||
ID: int64(odd.ID),
|
ID: int64(odd.ID),
|
||||||
EventID: odd.EventID.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 {
|
||||||
|
|
@ -205,4 +199,48 @@ func (s *Store) GetRawOddsByID(ctx context.Context, rawOddsID string) (domain.Ra
|
||||||
}(),
|
}(),
|
||||||
FetchedAt: odd.FetchedAt.Time,
|
FetchedAt: odd.FetchedAt.Time,
|
||||||
}, nil
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset int32) ([]domain.Odd, error) {
|
||||||
|
// Prepare query parameters
|
||||||
|
params := dbgen.GetPrematchOddsByUpcomingIDParams{
|
||||||
|
ID: upcomingID,
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the query
|
||||||
|
odds, err := s.queries.GetPrematchOddsByUpcomingID(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the results to domain.Odd
|
||||||
|
domainOdds := make([]domain.Odd, len(odds))
|
||||||
|
for i, odd := range odds {
|
||||||
|
var rawOdds []domain.RawMessage
|
||||||
|
if err := json.Unmarshal(odd.RawOdds, &rawOdds); err != nil {
|
||||||
|
rawOdds = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
domainOdds[i] = domain.Odd{
|
||||||
|
EventID: odd.EventID.String,
|
||||||
|
Fi: odd.Fi.String,
|
||||||
|
MarketType: odd.MarketType,
|
||||||
|
MarketName: odd.MarketName.String,
|
||||||
|
MarketCategory: odd.MarketCategory.String,
|
||||||
|
MarketID: odd.MarketID.String,
|
||||||
|
Name: odd.Name.String,
|
||||||
|
Handicap: odd.Handicap.String,
|
||||||
|
OddsValue: odd.OddsValue.Float64,
|
||||||
|
Section: odd.Section,
|
||||||
|
Category: odd.Category.String,
|
||||||
|
RawOdds: rawOdds,
|
||||||
|
FetchedAt: odd.FetchedAt.Time,
|
||||||
|
Source: odd.Source.String,
|
||||||
|
IsActive: odd.IsActive.Bool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainOdds, nil
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +97,7 @@ func (s *service) FetchLiveEvents(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
||||||
sportIDs := []int{1, 13, 78, 18, 91, 16, 17, 14, 12, 3, 2, 4, 83, 15, 92, 94, 8, 19, 36, 66, 9, 75, 90, 95, 110, 107, 151, 162, 148}
|
sportIDs := []int{1}
|
||||||
for _, sportID := range sportIDs {
|
for _, sportID := range sportIDs {
|
||||||
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s", sportID, s.token)
|
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s", sportID, s.token)
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
|
|
|
||||||
|
|
@ -24,76 +24,51 @@ func New(token string, store *repository.Store) *ServiceImpl {
|
||||||
|
|
||||||
|
|
||||||
func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
||||||
sportIDs := []int{
|
eventIDs, err := s.store.GetAllUpcomingEvents(ctx)
|
||||||
1, 13, 78, 18, 91, 16, 17, 14, 12, 3, 2, 4,
|
if err != nil {
|
||||||
83, 15, 92, 94, 8, 19, 36, 66, 9, 75, 90,
|
log.Printf("❌ Failed to fetch upcoming event IDs: %v", err)
|
||||||
95, 110, 107, 151, 162, 148,
|
return err
|
||||||
}
|
}
|
||||||
for _, sportID := range sportIDs {
|
|
||||||
upcomingURL := "https://api.b365api.com/v1/bet365/upcoming?sport_id=" + strconv.Itoa(sportID) + "&token=" + s.token
|
for _, event := range eventIDs {
|
||||||
log.Printf("Fetching upcoming odds for sport ID: %d from URL: %s", sportID, upcomingURL)
|
eventID := event.ID
|
||||||
resp, err := http.Get(upcomingURL)
|
prematchURL := "https://api.b365api.com/v3/bet365/prematch?token=" + s.token + "&FI=" + eventID
|
||||||
|
log.Printf("📡 Fetching prematch odds for event ID: %s", eventID)
|
||||||
|
resp, err := http.Get(prematchURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error fetching upcoming odds for sport ID: %d, error: %v", sportID, err)
|
log.Printf("❌ Failed to fetch prematch odds for event %s: %v", eventID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
var upcomingData struct {
|
var oddsData struct {
|
||||||
Success int `json:"success"`
|
Success int `json:"success"`
|
||||||
Results []struct {
|
Results []struct {
|
||||||
ID string `json:"id"`
|
EventID string `json:"event_id"`
|
||||||
|
FI string `json:"FI"`
|
||||||
|
Main OddsSection `json:"main"`
|
||||||
} `json:"results"`
|
} `json:"results"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(body, &upcomingData); err != nil || upcomingData.Success != 1 {
|
if err := json.Unmarshal(body, &oddsData); err != nil || oddsData.Success != 1 || len(oddsData.Results) == 0 {
|
||||||
log.Printf("Failed to parse upcoming odds for sport ID: %d, error: %v", sportID, err)
|
log.Printf("❌ Invalid prematch data for event %s", eventID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Successfully fetched upcoming odds for sport ID: %d", sportID)
|
result := oddsData.Results[0]
|
||||||
|
finalID := result.EventID
|
||||||
for _, ev := range upcomingData.Results {
|
if finalID == "" {
|
||||||
eventID := ev.ID
|
finalID = result.FI
|
||||||
prematchURL := "https://api.b365api.com/v3/bet365/prematch?token=" + s.token + "&FI=" + eventID
|
|
||||||
log.Printf("Fetching prematch odds for event ID: %s from URL: %s", eventID, prematchURL)
|
|
||||||
oddsResp, err := http.Get(prematchURL)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error fetching prematch odds for event ID: %s, error: %v", eventID, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
defer oddsResp.Body.Close()
|
|
||||||
|
|
||||||
oddsBody, _ := io.ReadAll(oddsResp.Body)
|
|
||||||
var oddsData struct {
|
|
||||||
Success int `json:"success"`
|
|
||||||
Results []struct {
|
|
||||||
EventID string `json:"event_id"`
|
|
||||||
FI string `json:"FI"`
|
|
||||||
Main OddsSection `json:"main"`
|
|
||||||
} `json:"results"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(oddsBody, &oddsData); err != nil || oddsData.Success != 1 || len(oddsData.Results) == 0 {
|
|
||||||
log.Printf("Failed to parse prematch odds for event ID: %s, error: %v", eventID, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
result := oddsData.Results[0]
|
|
||||||
finalID := result.EventID
|
|
||||||
if finalID == "" {
|
|
||||||
finalID = result.FI
|
|
||||||
}
|
|
||||||
if finalID == "" {
|
|
||||||
log.Printf("Skipping event with missing final ID for event ID: %s", eventID)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Storing odds for event ID: %s, final ID: %s", eventID, finalID)
|
|
||||||
s.storeSection(ctx, finalID, result.FI, "main", result.Main)
|
|
||||||
}
|
}
|
||||||
|
if finalID == "" {
|
||||||
|
log.Printf("⚠️ Skipping event %s with no valid ID", eventID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.storeSection(ctx, finalID, result.FI, "main", result.Main)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section OddsSection) {
|
func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section OddsSection) {
|
||||||
|
|
@ -153,4 +128,7 @@ func (s *ServiceImpl) GetRawOddsByID(ctx context.Context, rawOddsID string) ([]d
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return []domain.RawOddsByID{rawOdds}, nil
|
return []domain.RawOddsByID{rawOdds}, nil
|
||||||
}
|
}
|
||||||
|
func (s *ServiceImpl) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset int32) ([]domain.Odd, error) {
|
||||||
|
return s.store.GetPrematchOddsByUpcomingID(ctx, upcomingID, limit, offset)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package httpserver
|
package httpserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
// "context"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
|
|
@ -17,33 +17,35 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
task func()
|
task func()
|
||||||
}{
|
}{
|
||||||
|
|
||||||
{
|
// {
|
||||||
spec: "0 0 * * * *", // Every hour at minute 0 and second 0
|
// spec: "*/30 * * * * *", // Every 30 seconds
|
||||||
task: func() {
|
// task: func() {
|
||||||
if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||||
log.Printf("FetchUpcomingEvents error: %v", err)
|
// log.Printf("FetchUpcomingEvents error: %v", err)
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
|
|
||||||
|
|
||||||
{
|
// {
|
||||||
spec: "*/5 * * * * *", // Every 5 seconds
|
// spec: "*/5 * * * * *", // Every 5 seconds
|
||||||
task: func() {
|
// task: func() {
|
||||||
if err := eventService.FetchLiveEvents(context.Background()); err != nil {
|
// if err := eventService.FetchLiveEvents(context.Background()); err != nil {
|
||||||
log.Printf("FetchLiveEvents error: %v", err)
|
// log.Printf("FetchLiveEvents error: %v", err)
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
|
|
||||||
|
|
||||||
{
|
// {
|
||||||
spec: "0 0 * * * *", // Every hour at minute 0 and second 0
|
// spec: "*/30 * * * * *", // Every 30 seconds
|
||||||
task: func() {
|
// task: func() {
|
||||||
if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||||
log.Printf("FetchNonLiveOdds error: %v", err)
|
// log.Printf("FetchNonLiveOdds error: %v", err)
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"log/slog"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
"strconv"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
"log/slog"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetPrematchOdds godoc
|
// GetPrematchOdds godoc
|
||||||
|
|
@ -123,3 +125,41 @@ func GetUpcomingEventByID(logger *slog.Logger, eventSvc event.Service) fiber.Han
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Upcoming event retrieved successfully", event, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Upcoming event retrieved successfully", event, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @Summary Retrieve prematch odds by upcoming ID (FI)
|
||||||
|
// @Description Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination
|
||||||
|
// @Tags prematch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param upcoming_id path string true "Upcoming Event ID (FI)"
|
||||||
|
// @Param limit query int false "Number of results to return (default: 10)"
|
||||||
|
// @Param offset query int false "Number of results to skip (default: 0)"
|
||||||
|
// @Success 200 {array} domain.Odd
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /prematch/odds/upcoming/{upcoming_id} [get]
|
||||||
|
func GetPrematchOddsByUpcomingID(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
upcomingID := c.Params("upcoming_id")
|
||||||
|
if upcomingID == "" {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Missing upcoming_id", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
limit, err := strconv.Atoi(c.Query("limit", "10")) // Default limit is 10
|
||||||
|
if err != nil || limit <= 0 {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid limit value", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
offset, err := strconv.Atoi(c.Query("offset", "0")) // Default offset is 0
|
||||||
|
if err != nil || offset < 0 {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid offset value", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
odds, err := prematchSvc.GetPrematchOddsByUpcomingID(c.Context(), upcomingID, int32(limit), int32(offset))
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve prematch odds", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ func (a *App) initAppRoutes() {
|
||||||
|
|
||||||
a.fiber.Get("/prematch/events/:id", handlers.GetUpcomingEventByID(a.logger, a.eventSvc))
|
a.fiber.Get("/prematch/events/:id", handlers.GetUpcomingEventByID(a.logger, a.eventSvc))
|
||||||
a.fiber.Get("/prematch/events", handlers.GetAllUpcomingEvents(a.logger, a.eventSvc))
|
a.fiber.Get("/prematch/events", handlers.GetAllUpcomingEvents(a.logger, a.eventSvc))
|
||||||
|
a.fiber.Get("/prematch/odds/upcoming/:upcoming_id", handlers.GetPrematchOddsByUpcomingID(a.logger, a.prematchSvc))
|
||||||
// Swagger
|
// Swagger
|
||||||
a.fiber.Get("/swagger/*", fiberSwagger.WrapHandler)
|
a.fiber.Get("/swagger/*", fiberSwagger.WrapHandler)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user