data type and enable/disable provider fixes

This commit is contained in:
Yared Yemane 2025-08-29 15:27:02 +03:00
commit 3624acbacb
127 changed files with 8707 additions and 3805 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ logs/
app_logs/
backup/
reports/
exports/

View File

@ -1,8 +1,11 @@
{
"cSpell.words": [
"Cashout",
"dbgen",
"jackc",
"narg",
"notificationservice",
"pgtype",
"sqlc"
],
"cSpell.enabledFileTypes": {

View File

@ -113,7 +113,7 @@ func main() {
authSvc := authentication.NewService(store, store, cfg.RefreshExpiry)
userSvc := user.NewService(store, store, messengerSvc, cfg)
eventSvc := event.New(cfg.Bet365Token, store, domain.MongoDBLogger)
oddsSvc := odds.New(store, cfg, logger, domain.MongoDBLogger)
oddsSvc := odds.New(store, cfg, eventSvc, logger, domain.MongoDBLogger)
notificationRepo := repository.NewNotificationRepository(store)
virtuaGamesRepo := repository.NewVirtualGameRepository(store)
notificationSvc := notificationservice.New(notificationRepo, domain.MongoDBLogger, logger, cfg, messengerSvc, userSvc)

View File

@ -1,59 +1,222 @@
BEGIN;
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Users
INSERT INTO users (
id, first_name, last_name, email, phone_number, password, role,
email_verified, phone_verified, created_at, updated_at, suspended, company_id
) VALUES
(1, 'John', 'Doe', 'john.doe@example.com', NULL,
crypt('password123', gen_salt('bf'))::bytea, 'customer',
TRUE, FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL),
(2, 'Test', 'Admin', 'test.admin@gmail.com', '0988554466',
crypt('password123', gen_salt('bf'))::bytea, 'admin',
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, 1),
(3, 'Samuel', 'Tariku', 'cybersamt@gmail.com', '0911111111',
crypt('password@123', gen_salt('bf'))::bytea, 'super_admin',
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL),
(4, 'Kirubel', 'Kibru', 'kirubel.jkl679@gmail.com', '0911554486',
crypt('password@123', gen_salt('bf'))::bytea, 'super_admin',
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL);
id,
first_name,
last_name,
email,
phone_number,
password,
role,
email_verified,
phone_verified,
created_at,
updated_at,
suspended,
company_id
)
VALUES (
1,
'John',
'Doe',
'john.doe@example.com',
NULL,
crypt('password@123', gen_salt('bf'))::bytea,
'customer',
TRUE,
FALSE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
),
(
2,
'Test',
'Admin',
'test.admin@gmail.com',
'0988554466',
crypt('password123', gen_salt('bf'))::bytea,
'admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
1
),
(
3,
'Samuel',
'Tariku',
'cybersamt@gmail.com',
'0911111111',
crypt('password@123', gen_salt('bf'))::bytea,
'super_admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
),
(
4,
'Kirubel',
'Kibru',
'kirubel.jkl679@gmail.com',
'0911554486',
crypt('password@123', gen_salt('bf'))::bytea,
'super_admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
),
(
5,
'Test',
'Veli',
'test.veli@example.com',
NULL,
crypt('password@123', gen_salt('bf'))::bytea,
'customer',
TRUE,
FALSE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
);
-- Supported Operations
INSERT INTO supported_operations (id, name, description) VALUES
(1, 'SportBook', 'Sportbook operations'),
(2, 'Virtual', 'Virtual operations');
INSERT INTO supported_operations (id, name, description)
VALUES (1, 'SportBook', 'Sportbook operations'),
(2, 'Virtual', 'Virtual operations');
-- Wallets
INSERT INTO wallets (
id, balance, is_withdraw, is_bettable, is_transferable, user_id,
type, currency, is_active, created_at, updated_at
) VALUES
(1, 10000, TRUE, TRUE, TRUE, 1, 'regular', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
(2, 5000, FALSE, TRUE, TRUE, 1, 'static', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
(3, 20000, TRUE, TRUE, TRUE, 2, 'company_main', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
(4, 15000, TRUE, TRUE, TRUE, 2, 'branch_main', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
id,
balance,
is_withdraw,
is_bettable,
is_transferable,
user_id,
type,
currency,
is_active,
created_at,
updated_at
)
VALUES (
1,
10000,
TRUE,
TRUE,
TRUE,
1,
'regular',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
2,
5000,
FALSE,
TRUE,
TRUE,
1,
'static',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
3,
20000,
TRUE,
TRUE,
TRUE,
2,
'company_main',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
4,
15000,
TRUE,
TRUE,
TRUE,
2,
'branch_main',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);
-- Customer Wallets
INSERT INTO customer_wallets (id, customer_id, regular_wallet_id, static_wallet_id)
INSERT INTO customer_wallets (
id,
customer_id,
regular_wallet_id,
static_wallet_id
)
VALUES (1, 1, 1, 2);
-- Company
INSERT INTO companies (
id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at
) VALUES
(1, 'Test Company', 2, 3, 0.10, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
id,
name,
slug,
admin_id,
wallet_id,
deducted_percentage,
is_active,
created_at,
updated_at
)
VALUES (
1,
'FortuneBets',
'fortunebets',
2,
3,
0.10,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);
-- Branch
INSERT INTO branches (
id, name, location, wallet_id, branch_manager_id, company_id,
is_self_owned, profit_percent, is_active, created_at, updated_at
) VALUES
(1, 'Test Branch', 'addis_ababa', 4, 2, 1, TRUE, 0.10, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
id,
name,
location,
wallet_id,
branch_manager_id,
company_id,
is_self_owned,
profit_percent,
is_active,
created_at,
updated_at
)
VALUES (
1,
'Test Branch',
'addis_ababa',
4,
2,
1,
TRUE,
0.10,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);
COMMIT;

View File

@ -17,7 +17,9 @@ CREATE TABLE IF NOT EXISTS users (
CHECK (
email IS NOT NULL
OR phone_number IS NOT NULL
)
),
UNIQUE(email, company_id),
UNIQUE (phone_number, company_id)
);
CREATE TABLE IF NOT EXISTS virtual_game_providers (
@ -30,10 +32,10 @@ CREATE TABLE IF NOT EXISTS virtual_game_providers (
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS wallets (
id BIGSERIAL PRIMARY KEY,
balance BIGINT NOT NULL DEFAULT 0,
currency VARCHAR(3) NOT NULL DEFAULT 'ETB',
is_withdraw BOOLEAN NOT NULL,
is_bettable BOOLEAN NOT NULL,
is_transferable BOOLEAN NOT NULL,
@ -43,7 +45,6 @@ CREATE TABLE IF NOT EXISTS wallets (
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE refresh_tokens (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
@ -53,26 +54,6 @@ CREATE TABLE refresh_tokens (
revoked BOOLEAN DEFAULT FALSE NOT NULL,
CONSTRAINT unique_token UNIQUE (token)
);
CREATE TABLE direct_deposits (
id BIGSERIAL PRIMARY KEY,
customer_id BIGINT NOT NULL REFERENCES users(id),
wallet_id BIGINT NOT NULL REFERENCES wallets(id),
amount NUMERIC(15, 2) NOT NULL,
bank_reference TEXT NOT NULL,
sender_account TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('pending', 'completed', 'rejected')),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
verified_by BIGINT REFERENCES users(id),
verification_notes TEXT,
verified_at TIMESTAMP
);
CREATE INDEX idx_direct_deposits_status ON direct_deposits(status);
CREATE INDEX idx_direct_deposits_customer ON direct_deposits(customer_id);
CREATE INDEX idx_direct_deposits_reference ON direct_deposits(bank_reference);
-----
CREATE TABLE otps (
id BIGSERIAL PRIMARY KEY,
@ -87,6 +68,7 @@ CREATE TABLE otps (
);
CREATE TABLE IF NOT EXISTS bets (
id BIGSERIAL PRIMARY KEY,
company_id BIGINT NOT NULL,
amount BIGINT NOT NULL,
total_odds REAL NOT NULL,
status INT NOT NULL,
@ -101,6 +83,7 @@ CREATE TABLE IF NOT EXISTS bets (
);
CREATE TABLE IF NOT EXISTS tickets (
id BIGSERIAL PRIMARY KEY,
company_id BIGINT NOT NULL,
amount BIGINT NOT NULL,
total_odds REAL NOT NULL,
IP VARCHAR(255) NOT NULL,
@ -122,14 +105,14 @@ CREATE TABLE IF NOT EXISTS bet_outcomes (
sport_id BIGINT NOT NULL,
event_id BIGINT NOT null,
odd_id BIGINT NOT NULL,
home_team_name VARCHAR(255) NOT NULL,
away_team_name VARCHAR(255) NOT NULL,
home_team_name TEXT NOT NULL,
away_team_name TEXT NOT NULL,
market_id BIGINT NOT NULL,
market_name VARCHAR(255) NOT NULL,
market_name TEXT NOT NULL,
odd REAL NOT NULL,
odd_name VARCHAR(255) NOT NULL,
odd_header VARCHAR(255) NOT NULL,
odd_handicap VARCHAR(255) NOT NULL,
odd_name TEXT NOT NULL,
odd_header TEXT NOT NULL,
odd_handicap TEXT NOT NULL,
status INT NOT NULL DEFAULT 0,
expires TIMESTAMP NOT NULL
);
@ -138,14 +121,14 @@ CREATE TABLE IF NOT EXISTS ticket_outcomes (
ticket_id BIGINT NOT NULL,
event_id BIGINT NOT null,
odd_id BIGINT NOT NULL,
home_team_name VARCHAR(255) NOT NULL,
away_team_name VARCHAR(255) NOT NULL,
home_team_name TEXT NOT NULL,
away_team_name TEXT NOT NULL,
market_id BIGINT NOT NULL,
market_name VARCHAR(255) NOT NULL,
market_name TEXT NOT NULL,
odd REAL NOT NULL,
odd_name VARCHAR(255) NOT NULL,
odd_header VARCHAR(255) NOT NULL,
odd_handicap VARCHAR(255) NOT NULL,
odd_name TEXT NOT NULL,
odd_header TEXT NOT NULL,
odd_handicap TEXT NOT NULL,
status INT NOT NULL DEFAULT 0,
expires TIMESTAMP NOT NULL
);
@ -194,7 +177,7 @@ CREATE TABLE IF NOT EXISTS customer_wallets (
CREATE TABLE IF NOT EXISTS wallet_transfer (
id BIGSERIAL PRIMARY KEY,
amount BIGINT,
message VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
type VARCHAR(255),
receiver_wallet_id BIGINT,
sender_wallet_id BIGINT,
@ -288,54 +271,115 @@ CREATE TABLE IF NOT EXISTS branch_locations (
);
CREATE TABLE events (
id TEXT PRIMARY KEY,
sport_id INT,
match_name TEXT,
home_team TEXT,
away_team TEXT,
home_team_id INT,
away_team_id INT,
home_kit_image TEXT,
away_kit_image TEXT,
league_id INT,
league_name TEXT,
league_cc TEXT,
start_time TIMESTAMP,
sport_id INT NOT NULL,
match_name TEXT NOT NULL,
home_team TEXT NOT NULL,
away_team TEXT NOT NULL,
home_team_id BIGINT NOT NULL,
away_team_id BIGINT NOT NULL,
home_kit_image TEXT NOT NULL,
away_kit_image TEXT NOT NULL,
league_id BIGINT NOT NULL,
league_name TEXT NOT NULL,
start_time TIMESTAMP NOT NULL,
score TEXT,
match_minute INT,
timer_status TEXT,
added_time INT,
match_period INT,
is_live BOOLEAN,
status TEXT,
is_live BOOLEAN NOT NULL DEFAULT false,
status TEXT NOT NULL,
fetched_at TIMESTAMP DEFAULT now(),
source TEXT DEFAULT 'b365api',
is_featured BOOLEAN NOT NULL DEFAULT FALSE,
is_active BOOLEAN NOT NULL DEFAULT TRUE
source TEXT NOT NULL DEFAULT 'b365api' CHECK (
source IN (
'b365api',
'bfair',
'1xbet',
'bwin',
'enetpulse'
)
),
default_is_active BOOLEAN NOT NULL DEFAULT true,
default_is_featured BOOLEAN NOT NULL DEFAULT false,
default_winning_upper_limit INT NOT NULL,
is_monitored BOOLEAN NOT NULL DEFAULT FALSE,
UNIQUE(id, source)
);
CREATE TABLE odds (
id SERIAL PRIMARY KEY,
event_id TEXT,
fi TEXT,
CREATE TABLE event_history (
id BIGSERIAL PRIMARY KEY,
event_id TEXT NOT NULL,
status TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE company_event_settings (
id BIGSERIAL PRIMARY KEY,
company_id BIGINT NOT NULL,
event_id TEXT NOT NULL,
is_active BOOLEAN,
is_featured BOOLEAN,
winning_upper_limit INT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(company_id, event_id)
);
CREATE TABLE odds_market (
id BIGSERIAL PRIMARY KEY,
event_id TEXT NOT NULL,
market_type TEXT NOT NULL,
market_name TEXT,
market_category TEXT,
market_id TEXT,
name TEXT,
handicap TEXT,
odds_value DOUBLE PRECISION,
section TEXT NOT NULL,
category TEXT,
raw_odds JSONB,
market_name TEXT NOT NULL,
market_category TEXT NOT NULL,
market_id TEXT NOT NULL,
raw_odds JSONB NOT NULL,
default_is_active BOOLEAN NOT NULL DEFAULT true,
fetched_at TIMESTAMP DEFAULT now(),
source TEXT DEFAULT 'b365api',
is_active BOOLEAN DEFAULT true,
UNIQUE (market_id, name, handicap),
UNIQUE (event_id, market_id, name, handicap),
expires_at TIMESTAMP NOT NULL,
UNIQUE (event_id, market_id)
);
CREATE TABLE odd_history (
id BIGSERIAL PRIMARY KEY,
odds_market_id BIGINT NOT NULL REFERENCES odds_market(id),
raw_odd_id BIGINT NOT NULL,
market_id TEXT NOT NULL,
event_id TEXT NOT NULL,
odd_value DOUBLE PRECISION NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE disabled_odd (
id BIGSERIAL PRIMARY KEY,
company_id BIGINT NOT NULL,
odds_market_id BIGINT NOT NULL,
raw_odd_id BIGINT NOT NULL,
event_id TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE company_odd_settings (
id BIGSERIAL PRIMARY KEY,
company_id BIGINT NOT NULL,
odds_market_id BIGINT NOT NULL,
is_active BOOLEAN,
custom_raw_odds JSONB,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(company_id, odds_market_id)
);
CREATE TABLE result_log (
id BIGSERIAL PRIMARY KEY,
status_not_finished_count INT NOT NULL,
status_not_finished_bets INT NOT NULL,
status_to_be_fixed_count INT NOT NULL,
status_to_be_fixed_bets INT NOT NULL,
status_postponed_count INT NOT NULL,
status_postponed_bets INT NOT NULL,
status_ended_count INT NOT NULL,
status_ended_bets INT NOT NULL,
status_removed_count INT NOT NULL,
status_removed_bets INT NOT NULL,
removed_count INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE companies (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
admin_id BIGINT NOT NULL,
wallet_id BIGINT NOT NULL,
deducted_percentage REAL NOT NULL,
@ -350,35 +394,53 @@ CREATE TABLE companies (
CREATE TABLE leagues (
id BIGINT PRIMARY KEY,
name TEXT NOT NULL,
img TEXT,
img_url TEXT,
country_code TEXT,
bet365_id INT,
sport_id INT NOT NULL,
is_active BOOLEAN DEFAULT true,
is_featured BOOLEAN DEFAULT false
default_is_active BOOLEAN NOT NULL DEFAULT true,
default_is_featured BOOLEAN NOT NULL DEFAULT false
);
CREATE TABLE company_league_settings (
id BIGSERIAL PRIMARY KEY,
company_id BIGINT NOT NULL,
league_id BIGINT NOT NULL,
is_active BOOLEAN,
is_featured BOOLEAN,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(league_id, company_id)
);
CREATE TABLE teams (
id TEXT PRIMARY KEY,
id BIGSERIAL PRIMARY KEY,
team_name TEXT NOT NULL,
country TEXT,
bet365_id INT,
logo_url TEXT
country_code TEXT NOT NULL,
bet365_id BIGINT,
img_url TEXT
);
CREATE TABLE IF NOT EXISTS settings (
CREATE TABLE IF NOT EXISTS global_settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Tenant/Company-specific overrides
CREATE TABLE IF NOT EXISTS company_settings (
company_id BIGINT NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
key TEXT NOT NULL,
value TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (company_id, key)
);
CREATE TABLE bonus (
id BIGSERIAL PRIMARY KEY,
multiplier REAL NOT NULL,
id BIGSERIAL PRIMARY KEY,
balance_cap BIGINT NOT NULL DEFAULT 0
);
CREATE TABLE flags (
id BIGSERIAL PRIMARY KEY,
bet_id BIGINT REFERENCES bets(id) ON DELETE CASCADE,
odd_id BIGINT REFERENCES odds(id),
odds_market_id BIGINT REFERENCES odds_market(id),
reason TEXT,
flagged_at TIMESTAMP DEFAULT NOW(),
resolved BOOLEAN DEFAULT FALSE,
@ -386,14 +448,30 @@ CREATE TABLE flags (
CHECK (
(
bet_id IS NOT NULL
AND odd_id IS NULL
AND odds_market_id IS NULL
)
OR (
bet_id IS NULL
AND odd_id IS NOT NULL
AND odds_market_id IS NOT NULL
)
)
);
CREATE TABLE direct_deposits (
id BIGSERIAL PRIMARY KEY,
customer_id BIGINT NOT NULL REFERENCES users(id),
wallet_id BIGINT NOT NULL REFERENCES wallets(id),
amount NUMERIC(15, 2) NOT NULL,
bank_reference TEXT NOT NULL,
sender_account TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('pending', 'completed', 'rejected')),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
verified_by BIGINT REFERENCES users(id),
verification_notes TEXT,
verified_at TIMESTAMP
);
CREATE INDEX idx_direct_deposits_status ON direct_deposits(status);
CREATE INDEX idx_direct_deposits_customer ON direct_deposits(customer_id);
CREATE INDEX idx_direct_deposits_reference ON direct_deposits(bank_reference);
-- Views
CREATE VIEW companies_details AS
SELECT companies.*,
@ -512,17 +590,64 @@ SELECT sd.*,
st.verified AS transaction_verified
FROM shop_deposits AS sd
JOIN shop_transactions st ON st.id = sd.shop_transaction_id;
CREATE VIEW league_with_settings AS
SELECT l.*,
cls.company_id,
COALESCE(cls.is_active, l.default_is_active) AS is_active,
COALESCE(cls.is_featured, l.default_is_featured) AS is_featured,
cls.updated_at
FROM leagues l
JOIN company_league_settings cls ON l.id = cls.league_id;
CREATE VIEW event_with_settings AS
SELECT e.*,
ces.company_id,
COALESCE(ces.is_active, e.default_is_active) AS is_active,
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
COALESCE(
ces.winning_upper_limit,
e.default_winning_upper_limit
) AS winning_upper_limit,
ces.updated_at,
l.country_code as league_cc
FROM events e
JOIN company_event_settings ces ON e.id = ces.event_id
JOIN leagues l ON l.id = e.league_id;
CREATE VIEW event_with_country AS
SELECT events.*,
leagues.country_code as league_cc
FROM events
LEFT JOIN leagues ON leagues.id = events.league_id;
CREATE VIEW odds_market_with_settings AS
SELECT o.id,
o.event_id,
o.market_type,
o.market_name,
o.market_category,
o.market_id,
o.default_is_active,
o.fetched_at,
o.expires_at,
cos.company_id,
COALESCE(cos.is_active, o.default_is_active) AS is_active,
COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds,
cos.updated_at
FROM odds_market o
JOIN company_odd_settings cos ON o.id = cos.odds_market_id;
CREATE VIEW odds_market_with_event AS
SELECT o.*,
e.is_monitored,
e.is_live,
e.status,
e.source
FROM odds_market o
JOIN events e ON o.event_id = e.id;
-- Foreign Keys
ALTER TABLE users
ADD CONSTRAINT unique_email UNIQUE (email),
ADD CONSTRAINT unique_phone_number UNIQUE (phone_number);
ALTER TABLE refresh_tokens
ADD CONSTRAINT fk_refresh_tokens_users FOREIGN KEY (user_id) REFERENCES users(id);
ALTER TABLE bets
ADD CONSTRAINT fk_bets_users FOREIGN KEY (user_id) REFERENCES users(id);
ALTER TABLE wallets
ADD CONSTRAINT fk_wallets_users FOREIGN KEY (user_id) REFERENCES users(id),
ADD COLUMN currency VARCHAR(3) NOT NULL DEFAULT 'ETB';
ADD CONSTRAINT fk_wallets_users FOREIGN KEY (user_id) REFERENCES users(id);
ALTER TABLE customer_wallets
ADD CONSTRAINT fk_customer_wallets_customers FOREIGN KEY (customer_id) REFERENCES users(id),
ADD CONSTRAINT fk_customer_wallets_regular_wallet FOREIGN KEY (regular_wallet_id) REFERENCES wallets(id),
@ -553,3 +678,12 @@ ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(i
ALTER TABLE companies
ADD CONSTRAINT fk_companies_admin FOREIGN KEY (admin_id) REFERENCES users(id),
ADD CONSTRAINT fk_companies_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE;
ALTER TABLE company_league_settings
ADD CONSTRAINT fk_league_settings_company FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_league_settings_league FOREIGN KEY (league_id) REFERENCES leagues(id) ON DELETE CASCADE;
ALTER TABLE company_event_settings
ADD CONSTRAINT fk_event_settings_company FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_event_settings_event FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE;
ALTER TABLE company_odd_settings
ADD CONSTRAINT fk_odds_settings_company FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE,
ADD CONSTRAINT fk_odds_settings_odds_market FOREIGN KEY (odds_market_id) REFERENCES odds_market(id) ON DELETE CASCADE;

View File

@ -1,6 +1,6 @@
-- Settings Initial Data
INSERT INTO settings (key, value)
VALUES ('sms_provider', '30'),
INSERT INTO global_settings (key, value)
VALUES ('sms_provider', 'afro_message'),
('max_number_of_outcomes', '30'),
('bet_amount_limit', '10000000'),
('daily_ticket_limit', '50'),

View File

@ -1,58 +1,218 @@
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Users
INSERT INTO users (
id, first_name, last_name, email, phone_number, password, role,
email_verified, phone_verified, created_at, updated_at, suspended, company_id
) VALUES
(1, 'John', 'Doe', 'john.doe@example.com', NULL,
crypt('password123', gen_salt('bf'))::bytea, 'customer',
TRUE, FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL),
(2, 'Test', 'Admin', 'test.admin@gmail.com', '0988554466',
crypt('password123', gen_salt('bf'))::bytea, 'admin',
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, 1),
(3, 'Samuel', 'Tariku', 'cybersamt@gmail.com', '0911111111',
crypt('password@123', gen_salt('bf'))::bytea, 'super_admin',
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL),
(4, 'Kirubel', 'Kibru', 'kirubel.jkl679@gmail.com', '0911554486',
crypt('password@123', gen_salt('bf'))::bytea, 'super_admin',
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL);
id,
first_name,
last_name,
email,
phone_number,
password,
role,
email_verified,
phone_verified,
created_at,
updated_at,
suspended,
company_id
)
VALUES (
1,
'John',
'Doe',
'john.doe@example.com',
NULL,
crypt('password123', gen_salt('bf'))::bytea,
'customer',
TRUE,
FALSE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
),
(
2,
'Test',
'Admin',
'test.admin@gmail.com',
'0988554466',
crypt('password123', gen_salt('bf'))::bytea,
'admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
1
),
(
3,
'Samuel',
'Tariku',
'cybersamt@gmail.com',
'0911111111',
crypt('password@123', gen_salt('bf'))::bytea,
'super_admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
),
(
4,
'Kirubel',
'Kibru',
'kirubel.jkl679@gmail.com',
'0911554486',
crypt('password@123', gen_salt('bf'))::bytea,
'super_admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
),
(
5,
'Test',
'Veli',
'test.veli@example.com',
NULL,
crypt('password@123', gen_salt('bf'))::bytea,
'customer',
TRUE,
FALSE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
);
-- Supported Operations
INSERT INTO supported_operations (id, name, description) VALUES
(1, 'SportBook', 'Sportbook operations'),
(2, 'Virtual', 'Virtual operations');
INSERT INTO supported_operations (id, name, description)
VALUES (1, 'SportBook', 'Sportbook operations'),
(2, 'Virtual', 'Virtual operations');
-- Wallets
INSERT INTO wallets (
id, balance, is_withdraw, is_bettable, is_transferable, user_id,
type, currency, is_active, created_at, updated_at
) VALUES
(1, 10000, TRUE, TRUE, TRUE, 1, 'regular', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
(2, 5000, FALSE, TRUE, TRUE, 1, 'static', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
(3, 20000, TRUE, TRUE, TRUE, 2, 'company_main', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
(4, 15000, TRUE, TRUE, TRUE, 2, 'branch_main', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
id,
balance,
is_withdraw,
is_bettable,
is_transferable,
user_id,
type,
currency,
is_active,
created_at,
updated_at
)
VALUES (
1,
10000,
TRUE,
TRUE,
TRUE,
1,
'regular',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
2,
5000,
FALSE,
TRUE,
TRUE,
1,
'static',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
3,
20000,
TRUE,
TRUE,
TRUE,
2,
'company_main',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
4,
15000,
TRUE,
TRUE,
TRUE,
2,
'branch_main',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);
-- Customer Wallets
INSERT INTO customer_wallets (id, customer_id, regular_wallet_id, static_wallet_id)
INSERT INTO customer_wallets (
id,
customer_id,
regular_wallet_id,
static_wallet_id
)
VALUES (1, 1, 1, 2);
-- Company
INSERT INTO companies (
id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at
) VALUES
(1, 'Test Company', 2, 3, 0.10, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
id,
name,
admin_id,
wallet_id,
deducted_percentage,
is_active,
created_at,
updated_at
)
VALUES (
1,
'Test Company',
2,
3,
0.10,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);
-- Branch
INSERT INTO branches (
id, name, location, wallet_id, branch_manager_id, company_id,
is_self_owned, profit_percent, is_active, created_at, updated_at
) VALUES
(1, 'Test Branch', 'addis_ababa', 4, 2, 1, TRUE, 0.10, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
id,
name,
location,
wallet_id,
branch_manager_id,
company_id,
is_self_owned,
profit_percent,
is_active,
created_at,
updated_at
)
VALUES (
1,
'Test Branch',
'addis_ababa',
4,
2,
1,
TRUE,
0.10,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);

View File

@ -1,12 +1,17 @@
-- name: GetUserByEmailPhone :one
SELECT *
FROM users
WHERE email = $1
OR phone_number = $2;
WHERE (
email = $1
OR phone_number = $2
)
AND (
company_id = sqlc.narg('company_id')
OR sqlc.narg('company_id') IS NULL
);
-- name: CreateRefreshToken :exec
INSERT INTO refresh_tokens (user_id, token, expires_at, created_at, revoked)
VALUES ($1, $2, $3, $4, $5);
-- name: GetRefreshToken :one
SELECT *
FROM refresh_tokens

View File

@ -6,9 +6,10 @@ INSERT INTO bets (
user_id,
is_shop_bet,
outcomes_hash,
fast_code
fast_code,
company_id
)
VALUES ($1, $2, $3, $4, $5, $6, $7)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING *;
-- name: CreateBetOutcome :copyfrom
INSERT INTO bet_outcomes (
@ -52,6 +53,10 @@ wHERE (
is_shop_bet = sqlc.narg('is_shop_bet')
OR sqlc.narg('is_shop_bet') IS NULL
)
AND (
company_id = sqlc.narg('company_id')
OR sqlc.narg('company_id') IS NULL
)
AND (
cashed_out = sqlc.narg('cashed_out')
OR sqlc.narg('cashed_out') IS NULL

View File

@ -1,11 +1,12 @@
-- name: CreateCompany :one
INSERT INTO companies (
name,
slug,
admin_id,
wallet_id,
deducted_percentage
)
VALUES ($1, $2, $3, $4)
VALUES ($1, $2, $3, $4, $5)
RETURNING *;
-- name: GetAllCompanies :many
SELECT *
@ -29,6 +30,10 @@ WHERE (
SELECT *
FROM companies_details
WHERE id = $1;
-- name: GetCompanyIDUsingSlug :one
SELECT id
FROM companies
WHERE slug = $1;
-- name: SearchCompanyByName :many
SELECT *
FROM companies_details

35
db/query/custom_odds.sql Normal file
View File

@ -0,0 +1,35 @@
-- -- name: InsertCustomOddsMarket :one
-- INSERT INTO custom_odds_market (
-- odds_market_id,
-- company_id,
-- event_id,
-- raw_odds
-- )
-- VALUES ($1, $2, $3, $4)
-- RETURNING *;
-- -- name: GetAllCustomOdds :many
-- SELECT *
-- FROM custom_odds_market
-- WHERE (
-- company_id = sqlc.narg('company_id')
-- OR sqlc.narg('company_id') IS NULL
-- );
-- -- name: GetCustomOddByID :one
-- SELECT *
-- FROM custom_odds_market
-- WHERE id = $1;
-- -- name: GetCustomOddByOddID :one
-- SELECT *
-- FROM custom_odds_market
-- WHERE odds_market_id = $1
-- AND company_id = $2;
-- -- name: DeleteCustomOddsByID :exec
-- DELETE FROM custom_odds_market
-- WHERE id = $1;
-- -- name: DeleteCustomOddsByOddID :exec
-- DELETE FROM custom_odds_market
-- WHERE odds_market_id = $1
-- AND company_id = $2;
-- -- name: DeleteCustomOddByEventID :exec
-- DELETE FROM custom_odds_market
-- WHERE event_id = $1;

View File

@ -0,0 +1,26 @@
-- name: InsertDisabledOdds :one
INSERT INTO disabled_odd (
odds_market_id,
company_id,
event_id,
raw_odd_id
)
VALUES ($1, $2, $3, $4)
RETURNING *;
-- name: GetAllDisabledOdds :many
SELECT *
FROM disabled_odd;
-- name: GetDisabledOddByRawOddID :one
SELECT *
FROM disabled_odd
WHERE raw_odd_id = $1;
-- name: GetDisabledOddByID :one
SELECT *
FROM disabled_odd
WHERE raw_odd_id = $1;
-- name: DeleteDisabledOddsByID :exec
DELETE FROM disabled_odd
WHERE raw_odd_id = $1;
-- name: DeleteDisabledOddsByRawOddID :exec
DELETE FROM disabled_odd
WHERE raw_odd_id = $1;

View File

@ -0,0 +1,36 @@
-- name: InsertEventHistory :one
INSERT INTO event_history (event_id, status)
VALUES ($1, $2)
RETURNING *;
-- name: GetAllEventHistory :many
SELECT *
FROM event_history
WHERE (
event_id = sqlc.narg('event_id')
OR sqlc.narg('event_id') IS NULL
)
AND (
created_at > sqlc.narg('created_before')
OR sqlc.narg('created_before') IS NULL
)
AND (
created_at < sqlc.narg('created_after')
OR sqlc.narg('created_after') IS NULL
);
-- name: GetInitialEventPerDay :many
SELECT DISTINCT ON (DATE_TRUNC('day', created_at)) *
FROM event_history
WHERE (
event_id = sqlc.narg('event_id')
OR sqlc.narg('event_id') IS NULL
)
AND (
created_at > sqlc.narg('created_before')
OR sqlc.narg('created_before') IS NULL
)
AND (
created_at < sqlc.narg('created_after')
OR sqlc.narg('created_after') IS NULL
)
ORDER BY DATE_TRUNC('day', created_at),
created_at ASC;

View File

@ -11,13 +11,7 @@ INSERT INTO events (
away_kit_image,
league_id,
league_name,
league_cc,
start_time,
score,
match_minute,
timer_status,
added_time,
match_period,
is_live,
status,
source
@ -37,13 +31,7 @@ VALUES (
$12,
$13,
$14,
$15,
$16,
$17,
$18,
$19,
$20,
$21
$15
) ON CONFLICT (id) DO
UPDATE
SET sport_id = EXCLUDED.sport_id,
@ -64,79 +52,35 @@ SET sport_id = EXCLUDED.sport_id,
added_time = EXCLUDED.added_time,
match_period = EXCLUDED.match_period,
is_live = EXCLUDED.is_live,
status = EXCLUDED.status,
source = EXCLUDED.source,
fetched_at = now();
-- name: InsertUpcomingEvent :exec
INSERT INTO events (
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,
source
-- name: InsertEventSettings :exec
INSERT INTO company_event_settings (
company_id,
event_id,
is_active,
is_featured,
winning_upper_limit
)
VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12,
$13,
false,
'upcoming',
$14
) ON CONFLICT (id) DO
VALUES ($1, $2, $3, $4, $5) ON CONFLICT(company_id, event_id) DO
UPDATE
SET sport_id = EXCLUDED.sport_id,
match_name = EXCLUDED.match_name,
home_team = EXCLUDED.home_team,
away_team = EXCLUDED.away_team,
home_team_id = EXCLUDED.home_team_id,
away_team_id = EXCLUDED.away_team_id,
home_kit_image = EXCLUDED.home_kit_image,
away_kit_image = EXCLUDED.away_kit_image,
league_id = EXCLUDED.league_id,
league_name = EXCLUDED.league_name,
league_cc = EXCLUDED.league_cc,
start_time = EXCLUDED.start_time,
is_live = false,
status = 'upcoming',
source = EXCLUDED.source,
fetched_at = now();
SET is_active = EXCLUDED.is_active,
is_featured = EXCLUDED.is_featured,
winning_upper_limit = EXCLUDED.winning_upper_limit;
-- name: ListLiveEvents :many
SELECT id
FROM events
FROM event_with_country
WHERE is_live = true;
-- name: GetAllUpcomingEvents :many
SELECT *
FROM events
FROM event_with_country
WHERE start_time > now()
AND is_live = false
AND status = 'upcoming'
ORDER BY start_time ASC;
-- name: GetExpiredUpcomingEvents :many
SELECT events.*,
leagues.country_code as league_cc
FROM events
LEFT JOIN leagues ON leagues.id = league_id
-- name: GetExpiredEvents :many
SELECT *
FROM event_with_country
WHERE start_time < now()
and (
status = sqlc.narg('status')
@ -145,8 +89,7 @@ WHERE start_time < now()
ORDER BY start_time ASC;
-- name: GetTotalEvents :one
SELECT COUNT(*)
FROM events
LEFT JOIN leagues ON leagues.id = league_id
FROM event_with_country
WHERE is_live = false
AND status = 'upcoming'
AND (
@ -154,7 +97,7 @@ WHERE is_live = false
OR sqlc.narg('league_id') IS NULL
)
AND (
events.sport_id = sqlc.narg('sport_id')
sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL
)
AND (
@ -171,18 +114,12 @@ WHERE is_live = false
OR sqlc.narg('first_start_time') IS NULL
)
AND (
leagues.country_code = sqlc.narg('country_code')
league_cc = sqlc.narg('country_code')
OR sqlc.narg('country_code') IS NULL
)
AND (
events.is_featured = sqlc.narg('is_featured')
OR sqlc.narg('is_featured') IS NULL
);
-- name: GetPaginatedUpcomingEvents :many
SELECT events.*,
leagues.country_code as league_cc
FROM events
LEFT JOIN leagues ON leagues.id = league_id
SELECT *
FROM event_with_country
WHERE start_time > now()
AND is_live = false
AND status = 'upcoming'
@ -191,7 +128,7 @@ WHERE start_time > now()
OR sqlc.narg('league_id') IS NULL
)
AND (
events.sport_id = sqlc.narg('sport_id')
sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL
)
AND (
@ -208,31 +145,117 @@ WHERE start_time > now()
OR sqlc.narg('first_start_time') IS NULL
)
AND (
leagues.country_code = sqlc.narg('country_code')
league_cc = sqlc.narg('country_code')
OR sqlc.narg('country_code') IS NULL
)
ORDER BY start_time ASC
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetTotalCompanyEvents :one
SELECT COUNT(*)
FROM event_with_settings
WHERE company_id = $1
AND is_live = false
AND status = 'upcoming'
AND (
events.is_featured = sqlc.narg('is_featured')
OR sqlc.narg('is_featured') IS NULL
league_id = sqlc.narg('league_id')
OR sqlc.narg('league_id') IS NULL
)
AND (
sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL
)
AND (
match_name ILIKE '%' || sqlc.narg('query') || '%'
OR league_name ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
AND (
start_time < sqlc.narg('last_start_time')
OR sqlc.narg('last_start_time') IS NULL
)
AND (
start_time > sqlc.narg('first_start_time')
OR sqlc.narg('first_start_time') IS NULL
)
AND (
league_cc = sqlc.narg('country_code')
OR sqlc.narg('country_code') IS NULL
);
-- name: GetEventsWithSettings :many
SELECT *
FROM event_with_settings
WHERE company_id = $1
AND start_time > now()
AND is_live = false
AND status = 'upcoming'
AND (
league_id = sqlc.narg('league_id')
OR sqlc.narg('league_id') IS NULL
)
AND (
sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL
)
AND (
match_name ILIKE '%' || sqlc.narg('query') || '%'
OR league_name ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
AND (
start_time < sqlc.narg('last_start_time')
OR sqlc.narg('last_start_time') IS NULL
)
AND (
start_time > sqlc.narg('first_start_time')
OR sqlc.narg('first_start_time') IS NULL
)
AND (
league_cc = sqlc.narg('country_code')
OR sqlc.narg('country_code') IS NULL
)
ORDER BY start_time ASC
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetUpcomingByID :one
SELECT *
FROM events
FROM event_with_country
WHERE id = $1
AND is_live = false
AND status = 'upcoming'
LIMIT 1;
-- name: GetEventWithSettingByID :one
SELECT *
FROM event_with_settings
WHERE id = $1
AND company_id = $2
AND is_live = false
AND status = 'upcoming'
LIMIT 1;
-- name: UpdateMatchResult :exec
UPDATE events
SET score = $1,
status = $2
WHERE id = $3;
-- name: UpdateFeatured :exec
-- name: IsEventMonitored :one
SELECT is_monitored
FROM events
WHERE id = $1;
-- name: UpdateEventMonitored :exec
UPDATE events
SET is_featured = $1
SET is_monitored = $1
WHERE id = $2;
-- name: UpdateEventSettings :exec
UPDATE company_event_settings
SET is_active = COALESCE(sqlc.narg('is_active'), is_active),
is_featured = COALESCE(
sqlc.narg('is_featured'),
is_featured
),
winning_upper_limit = COALESCE(
sqlc.narg('winning_upper_limit'),
winning_upper_limit
)
WHERE event_id = $1
AND company_id = $2;
-- name: DeleteEvent :exec
DELETE FROM events
WHERE id = $1;

View File

@ -4,16 +4,55 @@ SELECT DATE_TRUNC('month', start_time) AS month,
FROM events
JOIN leagues ON leagues.id = events.league_id
WHERE (
events.is_featured = sqlc.narg('is_event_featured')
OR sqlc.narg('is_event_featured') IS NULL
)
AND (
leagues.is_featured = sqlc.narg('is_league_featured')
OR sqlc.narg('is_league_featured') IS NULL
)
AND (
events.league_id = sqlc.narg('league_id')
OR sqlc.narg('league_id') IS NULL
)
GROUP BY month
ORDER BY month;
-- name: GetLeagueEventStat :many
SELECT leagues.id,
leagues.name,
COUNT(*) AS total_events,
COUNT(*) FILTER (
WHERE events.status = 'pending'
) AS pending,
COUNT(*) FILTER (
WHERE events.status = 'in_play'
) AS in_play,
COUNT(*) FILTER (
WHERE events.status = 'to_be_fixed'
) AS to_be_fixed,
COUNT(*) FILTER (
WHERE events.status = 'ended'
) AS ended,
COUNT(*) FILTER (
WHERE events.status = 'postponed'
) AS postponed,
COUNT(*) FILTER (
WHERE events.status = 'cancelled'
) AS cancelled,
COUNT(*) FILTER (
WHERE events.status = 'walkover'
) AS walkover,
COUNT(*) FILTER (
WHERE events.status = 'interrupted'
) AS interrupted,
COUNT(*) FILTER (
WHERE events.status = 'abandoned'
) AS abandoned,
COUNT(*) FILTER (
WHERE events.status = 'retired'
) AS retired,
COUNT(*) FILTER (
WHERE events.status = 'suspended'
) AS suspended,
COUNT(*) FILTER (
WHERE events.status = 'decided_by_fa'
) AS decided_by_fa,
COUNT(*) FILTER (
WHERE events.status = 'removed'
) AS removed
FROM leagues
JOIN events ON leagues.id = events.league_id
GROUP BY leagues.id,
leagues.name;

View File

@ -1,7 +1,7 @@
-- name: CreateFlag :one
INSERT INTO flags (
bet_id,
odd_id,
odds_market_id,
reason
) VALUES (
$1, $2, $3

View File

@ -5,25 +5,28 @@ INSERT INTO leagues (
country_code,
bet365_id,
sport_id,
is_active,
is_featured
default_is_active,
default_is_featured
)
VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT (id) DO
UPDATE
SET name = EXCLUDED.name,
country_code = EXCLUDED.country_code,
bet365_id = EXCLUDED.bet365_id,
is_active = EXCLUDED.is_active,
is_featured = EXCLUDED.is_featured,
sport_id = EXCLUDED.sport_id;
-- name: InsertLeagueSettings :exec
INSERT INTO company_league_settings (
company_id,
league_id,
is_active,
is_featured
)
VALUES ($1, $2, $3, $4) ON CONFLICT(company_id, league_id) DO
UPDATE
SET is_active = EXCLUDED.is_active,
is_featured = EXCLUDED.is_featured;
-- name: GetAllLeagues :many
SELECT id,
name,
country_code,
bet365_id,
is_active,
is_featured,
sport_id
SELECT *
FROM leagues
WHERE (
country_code = sqlc.narg('country_code')
@ -33,6 +36,20 @@ WHERE (
sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL
)
ORDER BY name ASC
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetAllLeaguesWithSettings :many
SELECT *
FROM league_with_settings
WHERE (company_id = $1)
AND (
country_code = sqlc.narg('country_code')
OR sqlc.narg('country_code') IS NULL
)
AND (
sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL
)
AND (
is_active = sqlc.narg('is_active')
OR sqlc.narg('is_active') IS NULL
@ -44,21 +61,12 @@ WHERE (
ORDER BY is_featured DESC,
name ASC
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetFeaturedLeagues :many
SELECT id,
name,
country_code,
bet365_id,
is_active,
is_featured,
sport_id
FROM leagues
WHERE is_featured = true;
-- name: CheckLeagueSupport :one
SELECT EXISTS(
SELECT 1
FROM leagues
WHERE id = $1
FROM company_league_settings
WHERE league_id = $1
AND company_id = $2
AND is_active = true
);
-- name: UpdateLeague :exec
@ -66,20 +74,14 @@ UPDATE leagues
SET name = COALESCE(sqlc.narg('name'), name),
country_code = COALESCE(sqlc.narg('country_code'), country_code),
bet365_id = COALESCE(sqlc.narg('bet365_id'), bet365_id),
is_active = COALESCE(sqlc.narg('is_active'), is_active),
is_featured = COALESCE(sqlc.narg('is_featured'), is_featured),
sport_id = COALESCE(sqlc.narg('sport_id'), sport_id)
WHERE id = $1;
-- name: UpdateLeagueByBet365ID :exec
UPDATE leagues
SET name = COALESCE(sqlc.narg('name'), name),
id = COALESCE(sqlc.narg('id'), id),
country_code = COALESCE(sqlc.narg('country_code'), country_code),
is_active = COALESCE(sqlc.narg('is_active'), is_active),
is_featured = COALESCE(sqlc.narg('is_featured'), is_featured),
sport_id = COALESCE(sqlc.narg('sport_id'), sport_id)
WHERE bet365_id = $1;
-- name: SetLeagueActive :exec
UPDATE leagues
SET is_active = $2
WHERE id = $1;
-- name: UpdateLeagueSettings :exec
UPDATE company_league_settings
SET is_active = COALESCE(sqlc.narg('is_active'), is_active),
is_featured = COALESCE(
sqlc.narg('is_featured'),
is_featured
)
WHERE league_id = $1
AND company_id = $2;

66
db/query/odd_history.sql Normal file
View File

@ -0,0 +1,66 @@
-- name: InsertOddHistory :one
INSERT INTO odd_history (
odds_market_id,
market_id,
raw_odd_id,
event_id,
odd_value
)
VALUES ($1, $2, $3, $4, $5)
RETURNING *;
-- name: GetAllOddHistory :many
SELECT *
FROM odd_history
WHERE (
odds_market_id = sqlc.narg('odd_id')
OR sqlc.narg('odd_id') IS NULL
)
AND (
market_id = sqlc.narg('market_id')
OR sqlc.narg('market_id') IS NULL
)
AND (
raw_odd_id = sqlc.narg('raw_odd_id')
OR sqlc.narg('raw_odd_id') IS NULL
)
AND (
event_id = sqlc.narg('event_id')
OR sqlc.narg('event_id') IS NULL
)
AND (
created_at > sqlc.narg('created_before')
OR sqlc.narg('created_before') IS NULL
)
AND (
created_at < sqlc.narg('created_after')
OR sqlc.narg('created_after') IS NULL
);
-- name: GetInitialOddPerDay :many
SELECT DISTINCT ON (DATE_TRUNC($1, created_at)) *
FROM odd_history
WHERE (
odds_market_id = sqlc.narg('odd_id')
OR sqlc.narg('odd_id') IS NULL
)
AND (
market_id = sqlc.narg('market_id')
OR sqlc.narg('market_id') IS NULL
)
AND (
raw_odd_id = sqlc.narg('raw_odd_id')
OR sqlc.narg('raw_odd_id') IS NULL
)
AND (
event_id = sqlc.narg('event_id')
OR sqlc.narg('event_id') IS NULL
)
AND (
created_at > sqlc.narg('created_before')
OR sqlc.narg('created_before') IS NULL
)
AND (
created_at < sqlc.narg('created_after')
OR sqlc.narg('created_after') IS NULL
)
ORDER BY DATE_TRUNC($1, created_at),
created_at ASC;

View File

@ -1,20 +1,13 @@
-- name: InsertNonLiveOdd :exec
INSERT INTO odds (
-- name: InsertOddsMarket :exec
INSERT INTO odds_market (
event_id,
fi,
market_type,
market_name,
market_category,
market_id,
name,
handicap,
odds_value,
section,
category,
raw_odds,
is_active,
source,
fetched_at
fetched_at,
expires_at
)
VALUES (
$1,
@ -24,95 +17,69 @@ VALUES (
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12,
$13,
$14,
$15
$8
) ON CONFLICT (event_id, market_id) DO
UPDATE
SET odds_value = EXCLUDED.odds_value,
raw_odds = EXCLUDED.raw_odds,
market_type = EXCLUDED.market_type,
SET market_type = EXCLUDED.market_type,
market_name = EXCLUDED.market_name,
market_category = EXCLUDED.market_category,
name = EXCLUDED.name,
handicap = EXCLUDED.handicap,
raw_odds = EXCLUDED.raw_odds,
fetched_at = EXCLUDED.fetched_at,
is_active = EXCLUDED.is_active,
source = EXCLUDED.source,
fi = EXCLUDED.fi;
-- name: GetPrematchOdds :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 = 'bet365';
-- 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 = 'bet365';
-- name: GetRawOddsByMarketID :one
SELECT id,
market_name,
handicap,
raw_odds,
fetched_at
FROM odds
expires_at = EXCLUDED.expires_at;
-- name: InsertOddSettings :exec
INSERT INTO company_odd_settings (
company_id,
odds_market_id,
is_active,
custom_raw_odds
)
VALUES ($1, $2, $3, $4) ON CONFLICT (company_id, odds_market_id) DO
UPDATE
SET is_active = EXCLUDED.is_active,
custom_raw_odds = EXCLUDED.custom_raw_odds;
-- name: GetAllOdds :many
SELECT *
FROM odds_market_with_event
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetAllOddsWithSettings :many
SELECT *
FROM odds_market_with_settings
WHERE company_id = $1
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetOddsByMarketID :one
SELECT *
FROM odds_market_with_event
WHERE market_id = $1
AND fi = $2
AND is_active = true
AND source = 'bet365';
-- name: GetPrematchOddsByUpcomingID :many
SELECT o.*
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 = 'bet365';
-- name: GetPaginatedPrematchOddsByUpcomingID :many
SELECT o.*
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 = 'bet365'
AND event_id = $2;
-- name: GetOddsWithSettingsByMarketID :one
SELECT *
FROM odds_market_with_settings
WHERE market_id = $1
AND event_id = $2
AND company_id = $3;
-- name: GetOddsByEventID :many
SELECT *
FROM odds_market_with_event
WHERE event_id = $1
AND (
is_live = sqlc.narg('is_live')
OR sqlc.narg('is_live') IS NULL
)
AND (
status = sqlc.narg('status')
OR sqlc.narg('status') IS NULL
)
AND (
source = sqlc.narg('source')
OR sqlc.narg('source') IS NULL
)
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetOddsWithSettingsByEventID :many
SELECT *
FROM odds_market_with_settings
WHERE event_id = $1
AND company_id = $2
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: DeleteOddsForEvent :exec
DELETE FROM odds
Where fi = $1;
DELETE FROM odds_market
Where event_id = $1;

28
db/query/result_log.sql Normal file
View File

@ -0,0 +1,28 @@
-- name: CreateResultLog :one
INSERT INTO result_log (
status_not_finished_count,
status_not_finished_bets,
status_to_be_fixed_count,
status_to_be_fixed_bets,
status_postponed_count,
status_postponed_bets,
status_ended_count,
status_ended_bets,
status_removed_count,
status_removed_bets,
removed_count
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
RETURNING *;
-- name: GetAllResultLog :many
SELECT *
FROM result_log
WHERE (
created_at < sqlc.narg('created_before')
OR sqlc.narg('created_before') IS NULL
)
AND (
created_at > sqlc.narg('created_after')
OR sqlc.narg('created_after') IS NULL
)
ORDER BY created_at DESC;

View File

@ -1,13 +1,41 @@
-- name: GetSettings :many
-- name: GetGlobalSettings :many
SELECT *
FROM settings;
-- name: GetSetting :one
FROM global_settings;
-- name: GetGlobalSetting :one
SELECT *
FROM settings
FROM global_settings
WHERE key = $1;
-- name: SaveSetting :one
INSERT INTO settings (key, value, updated_at)
VALUES ($1, $2, CURRENT_TIMESTAMP) ON CONFLICT (key) DO
-- name: UpdateGlobalSetting :exec
UPDATE global_settings
SET value = $2,
updated_at = CURRENT_TIMESTAMP
WHERE key = $1;
-- name: InsertCompanySetting :exec
INSERT INTO company_settings (company_id, key, value)
VALUES ($1, $2, $3) ON CONFLICT (company_id, key) DO
UPDATE
SET value = EXCLUDED.value
RETURNING *;
SET value = EXCLUDED.value;
-- name: GetAllCompanySettings :many
SELECT *
FROM company_settings;
-- name: GetCompanySetting :many
SELECT *
FROM company_settings
WHERE company_id = $1;
-- name: GetCompanySettingsByKey :many
SELECT *
FROM company_settings
WHERE key = $1;
-- name: GetOverrideSettings :many
SELECT gs.*,
COALESCE(cs.value, gs.value) AS value
FROM global_settings gs
LEFT JOIN company_settings cs ON cs.key = gs.key
AND cs.company_id = $1;
-- name: DeleteCompanySetting :exec
DELETE FROM company_settings
WHERE company_id = $1
AND key = $2;
-- name: DeleteAllCompanySetting :exec
DELETE FROM company_settings
WHERE company_id = $1;

View File

@ -1,6 +1,6 @@
-- name: CreateTicket :one
INSERT INTO tickets (amount, total_odds, ip)
VALUES ($1, $2, $3)
INSERT INTO tickets (amount, total_odds, ip, company_id)
VALUES ($1, $2, $3, $4)
RETURNING *;
-- name: CreateTicketOutcome :copyfrom
INSERT INTO ticket_outcomes (
@ -33,7 +33,11 @@ VALUES (
);
-- name: GetAllTickets :many
SELECT *
FROM ticket_with_outcomes;
FROM ticket_with_outcomes
WHERE (
company_id = sqlc.narg('company_id')
OR sqlc.narg('company_id') IS NULL
);
-- name: GetTicketByID :one
SELECT *
FROM ticket_with_outcomes
@ -60,6 +64,7 @@ where created_at < now() - interval '1 day';
Delete from ticket_outcomes
where ticket_id = $1;
-- name: GetAllTicketsInRange :one
SELECT COUNT(*) as total_tickets, COALESCE(SUM(amount), 0) as total_amount
SELECT COUNT(*) as total_tickets,
COALESCE(SUM(amount), 0) as total_amount
FROM tickets
WHERE created_at BETWEEN $1 AND $2;

View File

@ -107,18 +107,15 @@ SELECT id,
suspended_at,
company_id
FROM users
WHERE (
first_name ILIKE '%' || $1 || '%'
OR last_name ILIKE '%' || $1 || '%'
OR phone_number LIKE '%' || $1 || '%'
WHERE (company_id = $1)
AND (
first_name ILIKE '%' || $2 || '%'
OR last_name ILIKE '%' || $2 || '%'
OR phone_number LIKE '%' || $2 || '%'
)
AND (
role = sqlc.narg('role')
OR sqlc.narg('role') IS NULL
)
AND (
company_id = sqlc.narg('company_id')
OR sqlc.narg('company_id') IS NULL
);
-- name: UpdateUser :exec
UPDATE users
@ -146,12 +143,14 @@ SELECT EXISTS (
FROM users
WHERE users.phone_number = $1
AND users.phone_number IS NOT NULL
AND users.company_id = $2
) AS phone_exists,
EXISTS (
SELECT 1
FROM users
WHERE users.email = $2
WHERE users.email = $3
AND users.email IS NOT NULL
AND users.company_id = $2
) AS email_exists;
-- name: GetUserByEmail :one
SELECT id,
@ -168,7 +167,8 @@ SELECT id,
suspended_at,
company_id
FROM users
WHERE email = $1;
WHERE email = $1
AND company_id = $2;
-- name: GetUserByPhone :one
SELECT id,
first_name,
@ -184,7 +184,8 @@ SELECT id,
suspended_at,
company_id
FROM users
WHERE phone_number = $1;
WHERE phone_number = $1
AND company_id = $2;
-- name: UpdatePassword :exec
UPDATE users
SET password = $1,
@ -192,6 +193,7 @@ SET password = $1,
WHERE (
email = $2
OR phone_number = $3
AND company_id = $4
);
-- name: GetAdminByCompanyID :one
SELECT users.*

View File

@ -18,6 +18,7 @@ services:
retries: 5
volumes:
- postgres_data:/var/lib/postgresql/data
- ./exports:/exports
mongo:
container_name: fortunebet-mongo

View File

@ -78,17 +78,24 @@ func (q *Queries) GetRefreshTokenByUserID(ctx context.Context, userID int64) (Re
const GetUserByEmailPhone = `-- name: GetUserByEmailPhone :one
SELECT id, first_name, last_name, email, phone_number, role, password, email_verified, phone_verified, created_at, updated_at, company_id, suspended_at, suspended, referral_code, referred_by
FROM users
WHERE email = $1
OR phone_number = $2
WHERE (
email = $1
OR phone_number = $2
)
AND (
company_id = $3
OR $3 IS NULL
)
`
type GetUserByEmailPhoneParams struct {
Email pgtype.Text `json:"email"`
PhoneNumber pgtype.Text `json:"phone_number"`
CompanyID pgtype.Int8 `json:"company_id"`
}
func (q *Queries) GetUserByEmailPhone(ctx context.Context, arg GetUserByEmailPhoneParams) (User, error) {
row := q.db.QueryRow(ctx, GetUserByEmailPhone, arg.Email, arg.PhoneNumber)
row := q.db.QueryRow(ctx, GetUserByEmailPhone, arg.Email, arg.PhoneNumber, arg.CompanyID)
var i User
err := row.Scan(
&i.ID,

View File

@ -19,10 +19,11 @@ INSERT INTO bets (
user_id,
is_shop_bet,
outcomes_hash,
fast_code
fast_code,
company_id
)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING id, company_id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at
`
type CreateBetParams struct {
@ -33,6 +34,7 @@ type CreateBetParams struct {
IsShopBet bool `json:"is_shop_bet"`
OutcomesHash string `json:"outcomes_hash"`
FastCode string `json:"fast_code"`
CompanyID int64 `json:"company_id"`
}
func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, error) {
@ -44,10 +46,12 @@ func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, erro
arg.IsShopBet,
arg.OutcomesHash,
arg.FastCode,
arg.CompanyID,
)
var i Bet
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.Amount,
&i.TotalOdds,
&i.Status,
@ -100,7 +104,7 @@ func (q *Queries) DeleteBetOutcome(ctx context.Context, betID int64) error {
}
const GetAllBets = `-- name: GetAllBets :many
SELECT id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes
SELECT id, company_id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes
FROM bet_with_outcomes
wHERE (
user_id = $1
@ -111,27 +115,32 @@ wHERE (
OR $2 IS NULL
)
AND (
cashed_out = $3
company_id = $3
OR $3 IS NULL
)
AND (
full_name ILIKE '%' || $4 || '%'
OR phone_number ILIKE '%' || $4 || '%'
cashed_out = $4
OR $4 IS NULL
)
AND (
created_at > $5
full_name ILIKE '%' || $5 || '%'
OR phone_number ILIKE '%' || $5 || '%'
OR $5 IS NULL
)
AND (
created_at < $6
created_at > $6
OR $6 IS NULL
)
AND (
created_at < $7
OR $7 IS NULL
)
`
type GetAllBetsParams struct {
UserID pgtype.Int8 `json:"user_id"`
IsShopBet pgtype.Bool `json:"is_shop_bet"`
CompanyID pgtype.Int8 `json:"company_id"`
CashedOut pgtype.Bool `json:"cashed_out"`
Query pgtype.Text `json:"query"`
CreatedBefore pgtype.Timestamp `json:"created_before"`
@ -142,6 +151,7 @@ func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWi
rows, err := q.db.Query(ctx, GetAllBets,
arg.UserID,
arg.IsShopBet,
arg.CompanyID,
arg.CashedOut,
arg.Query,
arg.CreatedBefore,
@ -156,6 +166,7 @@ func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWi
var i BetWithOutcome
if err := rows.Scan(
&i.ID,
&i.CompanyID,
&i.Amount,
&i.TotalOdds,
&i.Status,
@ -182,7 +193,7 @@ func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWi
}
const GetBetByFastCode = `-- name: GetBetByFastCode :one
SELECT id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes
SELECT id, company_id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes
FROM bet_with_outcomes
WHERE fast_code = $1
LIMIT 1
@ -193,6 +204,7 @@ func (q *Queries) GetBetByFastCode(ctx context.Context, fastCode string) (BetWit
var i BetWithOutcome
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.Amount,
&i.TotalOdds,
&i.Status,
@ -212,7 +224,7 @@ func (q *Queries) GetBetByFastCode(ctx context.Context, fastCode string) (BetWit
}
const GetBetByID = `-- name: GetBetByID :one
SELECT id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes
SELECT id, company_id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes
FROM bet_with_outcomes
WHERE id = $1
`
@ -222,6 +234,7 @@ func (q *Queries) GetBetByID(ctx context.Context, id int64) (BetWithOutcome, err
var i BetWithOutcome
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.Amount,
&i.TotalOdds,
&i.Status,
@ -241,7 +254,7 @@ func (q *Queries) GetBetByID(ctx context.Context, id int64) (BetWithOutcome, err
}
const GetBetByUserID = `-- name: GetBetByUserID :many
SELECT id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes
SELECT id, company_id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes
FROM bet_with_outcomes
WHERE user_id = $1
`
@ -257,6 +270,7 @@ func (q *Queries) GetBetByUserID(ctx context.Context, userID int64) ([]BetWithOu
var i BetWithOutcome
if err := rows.Scan(
&i.ID,
&i.CompanyID,
&i.Amount,
&i.TotalOdds,
&i.Status,
@ -424,7 +438,7 @@ func (q *Queries) GetBetOutcomeCountByOddID(ctx context.Context, oddID int64) (i
}
const GetBetsForCashback = `-- name: GetBetsForCashback :many
SELECT id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes
SELECT id, company_id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes
FROM bet_with_outcomes
WHERE status = 2
AND processed = false
@ -441,6 +455,7 @@ func (q *Queries) GetBetsForCashback(ctx context.Context) ([]BetWithOutcome, err
var i BetWithOutcome
if err := rows.Scan(
&i.ID,
&i.CompanyID,
&i.Amount,
&i.TotalOdds,
&i.Status,

View File

@ -14,16 +14,18 @@ import (
const CreateCompany = `-- name: CreateCompany :one
INSERT INTO companies (
name,
slug,
admin_id,
wallet_id,
deducted_percentage
)
VALUES ($1, $2, $3, $4)
RETURNING id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at
VALUES ($1, $2, $3, $4, $5)
RETURNING id, name, slug, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at
`
type CreateCompanyParams struct {
Name string `json:"name"`
Slug string `json:"slug"`
AdminID int64 `json:"admin_id"`
WalletID int64 `json:"wallet_id"`
DeductedPercentage float32 `json:"deducted_percentage"`
@ -32,6 +34,7 @@ type CreateCompanyParams struct {
func (q *Queries) CreateCompany(ctx context.Context, arg CreateCompanyParams) (Company, error) {
row := q.db.QueryRow(ctx, CreateCompany,
arg.Name,
arg.Slug,
arg.AdminID,
arg.WalletID,
arg.DeductedPercentage,
@ -40,6 +43,7 @@ func (q *Queries) CreateCompany(ctx context.Context, arg CreateCompanyParams) (C
err := row.Scan(
&i.ID,
&i.Name,
&i.Slug,
&i.AdminID,
&i.WalletID,
&i.DeductedPercentage,
@ -61,7 +65,7 @@ func (q *Queries) DeleteCompany(ctx context.Context, id int64) error {
}
const GetAllCompanies = `-- name: GetAllCompanies :many
SELECT id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at, balance, wallet_is_active, admin_first_name, admin_last_name, admin_phone_number
SELECT id, name, slug, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at, balance, wallet_is_active, admin_first_name, admin_last_name, admin_phone_number
FROM companies_details
WHERE (
name ILIKE '%' || $1 || '%'
@ -98,6 +102,7 @@ func (q *Queries) GetAllCompanies(ctx context.Context, arg GetAllCompaniesParams
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Slug,
&i.AdminID,
&i.WalletID,
&i.DeductedPercentage,
@ -121,7 +126,7 @@ func (q *Queries) GetAllCompanies(ctx context.Context, arg GetAllCompaniesParams
}
const GetCompanyByID = `-- name: GetCompanyByID :one
SELECT id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at, balance, wallet_is_active, admin_first_name, admin_last_name, admin_phone_number
SELECT id, name, slug, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at, balance, wallet_is_active, admin_first_name, admin_last_name, admin_phone_number
FROM companies_details
WHERE id = $1
`
@ -132,6 +137,7 @@ func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (CompaniesDetail
err := row.Scan(
&i.ID,
&i.Name,
&i.Slug,
&i.AdminID,
&i.WalletID,
&i.DeductedPercentage,
@ -147,8 +153,21 @@ func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (CompaniesDetail
return i, err
}
const GetCompanyIDUsingSlug = `-- name: GetCompanyIDUsingSlug :one
SELECT id
FROM companies
WHERE slug = $1
`
func (q *Queries) GetCompanyIDUsingSlug(ctx context.Context, slug string) (int64, error) {
row := q.db.QueryRow(ctx, GetCompanyIDUsingSlug, slug)
var id int64
err := row.Scan(&id)
return id, err
}
const SearchCompanyByName = `-- name: SearchCompanyByName :many
SELECT id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at, balance, wallet_is_active, admin_first_name, admin_last_name, admin_phone_number
SELECT id, name, slug, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at, balance, wallet_is_active, admin_first_name, admin_last_name, admin_phone_number
FROM companies_details
WHERE name ILIKE '%' || $1 || '%'
`
@ -165,6 +184,7 @@ func (q *Queries) SearchCompanyByName(ctx context.Context, dollar_1 pgtype.Text)
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Slug,
&i.AdminID,
&i.WalletID,
&i.DeductedPercentage,
@ -198,7 +218,7 @@ SET name = COALESCE($2, name),
),
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at
RETURNING id, name, slug, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at
`
type UpdateCompanyParams struct {
@ -221,6 +241,7 @@ func (q *Queries) UpdateCompany(ctx context.Context, arg UpdateCompanyParams) (C
err := row.Scan(
&i.ID,
&i.Name,
&i.Slug,
&i.AdminID,
&i.WalletID,
&i.DeductedPercentage,

139
gen/db/disabled_odds.sql.go Normal file
View File

@ -0,0 +1,139 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.29.0
// source: disabled_odds.sql
package dbgen
import (
"context"
)
const DeleteDisabledOddsByID = `-- name: DeleteDisabledOddsByID :exec
DELETE FROM disabled_odd
WHERE raw_odd_id = $1
`
func (q *Queries) DeleteDisabledOddsByID(ctx context.Context, rawOddID int64) error {
_, err := q.db.Exec(ctx, DeleteDisabledOddsByID, rawOddID)
return err
}
const DeleteDisabledOddsByRawOddID = `-- name: DeleteDisabledOddsByRawOddID :exec
DELETE FROM disabled_odd
WHERE raw_odd_id = $1
`
func (q *Queries) DeleteDisabledOddsByRawOddID(ctx context.Context, rawOddID int64) error {
_, err := q.db.Exec(ctx, DeleteDisabledOddsByRawOddID, rawOddID)
return err
}
const GetAllDisabledOdds = `-- name: GetAllDisabledOdds :many
SELECT id, company_id, odds_market_id, raw_odd_id, event_id, created_at
FROM disabled_odd
`
func (q *Queries) GetAllDisabledOdds(ctx context.Context) ([]DisabledOdd, error) {
rows, err := q.db.Query(ctx, GetAllDisabledOdds)
if err != nil {
return nil, err
}
defer rows.Close()
var items []DisabledOdd
for rows.Next() {
var i DisabledOdd
if err := rows.Scan(
&i.ID,
&i.CompanyID,
&i.OddsMarketID,
&i.RawOddID,
&i.EventID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetDisabledOddByID = `-- name: GetDisabledOddByID :one
SELECT id, company_id, odds_market_id, raw_odd_id, event_id, created_at
FROM disabled_odd
WHERE raw_odd_id = $1
`
func (q *Queries) GetDisabledOddByID(ctx context.Context, rawOddID int64) (DisabledOdd, error) {
row := q.db.QueryRow(ctx, GetDisabledOddByID, rawOddID)
var i DisabledOdd
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.OddsMarketID,
&i.RawOddID,
&i.EventID,
&i.CreatedAt,
)
return i, err
}
const GetDisabledOddByRawOddID = `-- name: GetDisabledOddByRawOddID :one
SELECT id, company_id, odds_market_id, raw_odd_id, event_id, created_at
FROM disabled_odd
WHERE raw_odd_id = $1
`
func (q *Queries) GetDisabledOddByRawOddID(ctx context.Context, rawOddID int64) (DisabledOdd, error) {
row := q.db.QueryRow(ctx, GetDisabledOddByRawOddID, rawOddID)
var i DisabledOdd
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.OddsMarketID,
&i.RawOddID,
&i.EventID,
&i.CreatedAt,
)
return i, err
}
const InsertDisabledOdds = `-- name: InsertDisabledOdds :one
INSERT INTO disabled_odd (
odds_market_id,
company_id,
event_id,
raw_odd_id
)
VALUES ($1, $2, $3, $4)
RETURNING id, company_id, odds_market_id, raw_odd_id, event_id, created_at
`
type InsertDisabledOddsParams struct {
OddsMarketID int64 `json:"odds_market_id"`
CompanyID int64 `json:"company_id"`
EventID string `json:"event_id"`
RawOddID int64 `json:"raw_odd_id"`
}
func (q *Queries) InsertDisabledOdds(ctx context.Context, arg InsertDisabledOddsParams) (DisabledOdd, error) {
row := q.db.QueryRow(ctx, InsertDisabledOdds,
arg.OddsMarketID,
arg.CompanyID,
arg.EventID,
arg.RawOddID,
)
var i DisabledOdd
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.OddsMarketID,
&i.RawOddID,
&i.EventID,
&i.CreatedAt,
)
return i, err
}

133
gen/db/event_history.sql.go Normal file
View File

@ -0,0 +1,133 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.29.0
// source: event_history.sql
package dbgen
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const GetAllEventHistory = `-- name: GetAllEventHistory :many
SELECT id, event_id, status, created_at
FROM event_history
WHERE (
event_id = $1
OR $1 IS NULL
)
AND (
created_at > $2
OR $2 IS NULL
)
AND (
created_at < $3
OR $3 IS NULL
)
`
type GetAllEventHistoryParams struct {
EventID pgtype.Text `json:"event_id"`
CreatedBefore pgtype.Timestamp `json:"created_before"`
CreatedAfter pgtype.Timestamp `json:"created_after"`
}
func (q *Queries) GetAllEventHistory(ctx context.Context, arg GetAllEventHistoryParams) ([]EventHistory, error) {
rows, err := q.db.Query(ctx, GetAllEventHistory, arg.EventID, arg.CreatedBefore, arg.CreatedAfter)
if err != nil {
return nil, err
}
defer rows.Close()
var items []EventHistory
for rows.Next() {
var i EventHistory
if err := rows.Scan(
&i.ID,
&i.EventID,
&i.Status,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetInitialEventPerDay = `-- name: GetInitialEventPerDay :many
SELECT DISTINCT ON (DATE_TRUNC('day', created_at)) id, event_id, status, created_at
FROM event_history
WHERE (
event_id = $1
OR $1 IS NULL
)
AND (
created_at > $2
OR $2 IS NULL
)
AND (
created_at < $3
OR $3 IS NULL
)
ORDER BY DATE_TRUNC('day', created_at),
created_at ASC
`
type GetInitialEventPerDayParams struct {
EventID pgtype.Text `json:"event_id"`
CreatedBefore pgtype.Timestamp `json:"created_before"`
CreatedAfter pgtype.Timestamp `json:"created_after"`
}
func (q *Queries) GetInitialEventPerDay(ctx context.Context, arg GetInitialEventPerDayParams) ([]EventHistory, error) {
rows, err := q.db.Query(ctx, GetInitialEventPerDay, arg.EventID, arg.CreatedBefore, arg.CreatedAfter)
if err != nil {
return nil, err
}
defer rows.Close()
var items []EventHistory
for rows.Next() {
var i EventHistory
if err := rows.Scan(
&i.ID,
&i.EventID,
&i.Status,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const InsertEventHistory = `-- name: InsertEventHistory :one
INSERT INTO event_history (event_id, status)
VALUES ($1, $2)
RETURNING id, event_id, status, created_at
`
type InsertEventHistoryParams struct {
EventID string `json:"event_id"`
Status string `json:"status"`
}
func (q *Queries) InsertEventHistory(ctx context.Context, arg InsertEventHistoryParams) (EventHistory, error) {
row := q.db.QueryRow(ctx, InsertEventHistory, arg.EventID, arg.Status)
var i EventHistory
err := row.Scan(
&i.ID,
&i.EventID,
&i.Status,
&i.CreatedAt,
)
return i, err
}

File diff suppressed because it is too large Load Diff

View File

@ -11,40 +11,131 @@ import (
"github.com/jackc/pgx/v5/pgtype"
)
const GetLeagueEventStat = `-- name: GetLeagueEventStat :many
SELECT leagues.id,
leagues.name,
COUNT(*) AS total_events,
COUNT(*) FILTER (
WHERE events.status = 'pending'
) AS pending,
COUNT(*) FILTER (
WHERE events.status = 'in_play'
) AS in_play,
COUNT(*) FILTER (
WHERE events.status = 'to_be_fixed'
) AS to_be_fixed,
COUNT(*) FILTER (
WHERE events.status = 'ended'
) AS ended,
COUNT(*) FILTER (
WHERE events.status = 'postponed'
) AS postponed,
COUNT(*) FILTER (
WHERE events.status = 'cancelled'
) AS cancelled,
COUNT(*) FILTER (
WHERE events.status = 'walkover'
) AS walkover,
COUNT(*) FILTER (
WHERE events.status = 'interrupted'
) AS interrupted,
COUNT(*) FILTER (
WHERE events.status = 'abandoned'
) AS abandoned,
COUNT(*) FILTER (
WHERE events.status = 'retired'
) AS retired,
COUNT(*) FILTER (
WHERE events.status = 'suspended'
) AS suspended,
COUNT(*) FILTER (
WHERE events.status = 'decided_by_fa'
) AS decided_by_fa,
COUNT(*) FILTER (
WHERE events.status = 'removed'
) AS removed
FROM leagues
JOIN events ON leagues.id = events.league_id
GROUP BY leagues.id,
leagues.name
`
type GetLeagueEventStatRow struct {
ID int64 `json:"id"`
Name string `json:"name"`
TotalEvents int64 `json:"total_events"`
Pending int64 `json:"pending"`
InPlay int64 `json:"in_play"`
ToBeFixed int64 `json:"to_be_fixed"`
Ended int64 `json:"ended"`
Postponed int64 `json:"postponed"`
Cancelled int64 `json:"cancelled"`
Walkover int64 `json:"walkover"`
Interrupted int64 `json:"interrupted"`
Abandoned int64 `json:"abandoned"`
Retired int64 `json:"retired"`
Suspended int64 `json:"suspended"`
DecidedByFa int64 `json:"decided_by_fa"`
Removed int64 `json:"removed"`
}
func (q *Queries) GetLeagueEventStat(ctx context.Context) ([]GetLeagueEventStatRow, error) {
rows, err := q.db.Query(ctx, GetLeagueEventStat)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetLeagueEventStatRow
for rows.Next() {
var i GetLeagueEventStatRow
if err := rows.Scan(
&i.ID,
&i.Name,
&i.TotalEvents,
&i.Pending,
&i.InPlay,
&i.ToBeFixed,
&i.Ended,
&i.Postponed,
&i.Cancelled,
&i.Walkover,
&i.Interrupted,
&i.Abandoned,
&i.Retired,
&i.Suspended,
&i.DecidedByFa,
&i.Removed,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetTotalMontlyEventStat = `-- name: GetTotalMontlyEventStat :many
SELECT DATE_TRUNC('month', start_time) AS month,
COUNT(*) AS event_count
FROM events
JOIN leagues ON leagues.id = events.league_id
WHERE (
events.is_featured = $1
events.league_id = $1
OR $1 IS NULL
)
AND (
leagues.is_featured = $2
OR $2 IS NULL
)
AND (
events.league_id = $3
OR $3 IS NULL
)
GROUP BY month
ORDER BY month
`
type GetTotalMontlyEventStatParams struct {
IsEventFeatured pgtype.Bool `json:"is_event_featured"`
IsLeagueFeatured pgtype.Bool `json:"is_league_featured"`
LeagueID pgtype.Int4 `json:"league_id"`
}
type GetTotalMontlyEventStatRow struct {
Month pgtype.Interval `json:"month"`
EventCount int64 `json:"event_count"`
}
func (q *Queries) GetTotalMontlyEventStat(ctx context.Context, arg GetTotalMontlyEventStatParams) ([]GetTotalMontlyEventStatRow, error) {
rows, err := q.db.Query(ctx, GetTotalMontlyEventStat, arg.IsEventFeatured, arg.IsLeagueFeatured, arg.LeagueID)
func (q *Queries) GetTotalMontlyEventStat(ctx context.Context, leagueID pgtype.Int8) ([]GetTotalMontlyEventStatRow, error) {
rows, err := q.db.Query(ctx, GetTotalMontlyEventStat, leagueID)
if err != nil {
return nil, err
}

View File

@ -14,26 +14,26 @@ import (
const CreateFlag = `-- name: CreateFlag :one
INSERT INTO flags (
bet_id,
odd_id,
odds_market_id,
reason
) VALUES (
$1, $2, $3
) RETURNING id, bet_id, odd_id, reason, flagged_at, resolved
) RETURNING id, bet_id, odds_market_id, reason, flagged_at, resolved
`
type CreateFlagParams struct {
BetID pgtype.Int8 `json:"bet_id"`
OddID pgtype.Int8 `json:"odd_id"`
Reason pgtype.Text `json:"reason"`
BetID pgtype.Int8 `json:"bet_id"`
OddsMarketID pgtype.Int8 `json:"odds_market_id"`
Reason pgtype.Text `json:"reason"`
}
func (q *Queries) CreateFlag(ctx context.Context, arg CreateFlagParams) (Flag, error) {
row := q.db.QueryRow(ctx, CreateFlag, arg.BetID, arg.OddID, arg.Reason)
row := q.db.QueryRow(ctx, CreateFlag, arg.BetID, arg.OddsMarketID, arg.Reason)
var i Flag
err := row.Scan(
&i.ID,
&i.BetID,
&i.OddID,
&i.OddsMarketID,
&i.Reason,
&i.FlaggedAt,
&i.Resolved,

View File

@ -14,27 +14,27 @@ import (
const CheckLeagueSupport = `-- name: CheckLeagueSupport :one
SELECT EXISTS(
SELECT 1
FROM leagues
WHERE id = $1
FROM company_league_settings
WHERE league_id = $1
AND company_id = $2
AND is_active = true
)
`
func (q *Queries) CheckLeagueSupport(ctx context.Context, id int64) (bool, error) {
row := q.db.QueryRow(ctx, CheckLeagueSupport, id)
type CheckLeagueSupportParams struct {
LeagueID int64 `json:"league_id"`
CompanyID int64 `json:"company_id"`
}
func (q *Queries) CheckLeagueSupport(ctx context.Context, arg CheckLeagueSupportParams) (bool, error) {
row := q.db.QueryRow(ctx, CheckLeagueSupport, arg.LeagueID, arg.CompanyID)
var exists bool
err := row.Scan(&exists)
return exists, err
}
const GetAllLeagues = `-- name: GetAllLeagues :many
SELECT id,
name,
country_code,
bet365_id,
is_active,
is_featured,
sport_id
SELECT id, name, img_url, country_code, bet365_id, sport_id, default_is_active, default_is_featured
FROM leagues
WHERE (
country_code = $1
@ -44,44 +44,21 @@ WHERE (
sport_id = $2
OR $2 IS NULL
)
AND (
is_active = $3
OR $3 IS NULL
)
AND (
is_featured = $4
OR $4 IS NULL
)
ORDER BY is_featured DESC,
name ASC
LIMIT $6 OFFSET $5
ORDER BY name ASC
LIMIT $4 OFFSET $3
`
type GetAllLeaguesParams struct {
CountryCode pgtype.Text `json:"country_code"`
SportID pgtype.Int4 `json:"sport_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"`
}
type GetAllLeaguesRow struct {
ID int64 `json:"id"`
Name string `json:"name"`
CountryCode pgtype.Text `json:"country_code"`
Bet365ID pgtype.Int4 `json:"bet365_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
SportID int32 `json:"sport_id"`
}
func (q *Queries) GetAllLeagues(ctx context.Context, arg GetAllLeaguesParams) ([]GetAllLeaguesRow, error) {
func (q *Queries) GetAllLeagues(ctx context.Context, arg GetAllLeaguesParams) ([]League, error) {
rows, err := q.db.Query(ctx, GetAllLeagues,
arg.CountryCode,
arg.SportID,
arg.IsActive,
arg.IsFeatured,
arg.Offset,
arg.Limit,
)
@ -89,17 +66,18 @@ func (q *Queries) GetAllLeagues(ctx context.Context, arg GetAllLeaguesParams) ([
return nil, err
}
defer rows.Close()
var items []GetAllLeaguesRow
var items []League
for rows.Next() {
var i GetAllLeaguesRow
var i League
if err := rows.Scan(
&i.ID,
&i.Name,
&i.ImgUrl,
&i.CountryCode,
&i.Bet365ID,
&i.IsActive,
&i.IsFeatured,
&i.SportID,
&i.DefaultIsActive,
&i.DefaultIsFeatured,
); err != nil {
return nil, err
}
@ -111,45 +89,71 @@ func (q *Queries) GetAllLeagues(ctx context.Context, arg GetAllLeaguesParams) ([
return items, nil
}
const GetFeaturedLeagues = `-- name: GetFeaturedLeagues :many
SELECT id,
name,
country_code,
bet365_id,
is_active,
is_featured,
sport_id
FROM leagues
WHERE is_featured = true
const GetAllLeaguesWithSettings = `-- name: GetAllLeaguesWithSettings :many
SELECT id, name, img_url, country_code, bet365_id, sport_id, default_is_active, default_is_featured, company_id, is_active, is_featured, updated_at
FROM league_with_settings
WHERE (company_id = $1)
AND (
country_code = $2
OR $2 IS NULL
)
AND (
sport_id = $3
OR $3 IS NULL
)
AND (
is_active = $4
OR $4 IS NULL
)
AND (
is_featured = $5
OR $5 IS NULL
)
ORDER BY is_featured DESC,
name ASC
LIMIT $7 OFFSET $6
`
type GetFeaturedLeaguesRow struct {
ID int64 `json:"id"`
Name string `json:"name"`
type GetAllLeaguesWithSettingsParams struct {
CompanyID int64 `json:"company_id"`
CountryCode pgtype.Text `json:"country_code"`
Bet365ID pgtype.Int4 `json:"bet365_id"`
SportID pgtype.Int4 `json:"sport_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
SportID int32 `json:"sport_id"`
Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"`
}
func (q *Queries) GetFeaturedLeagues(ctx context.Context) ([]GetFeaturedLeaguesRow, error) {
rows, err := q.db.Query(ctx, GetFeaturedLeagues)
func (q *Queries) GetAllLeaguesWithSettings(ctx context.Context, arg GetAllLeaguesWithSettingsParams) ([]LeagueWithSetting, error) {
rows, err := q.db.Query(ctx, GetAllLeaguesWithSettings,
arg.CompanyID,
arg.CountryCode,
arg.SportID,
arg.IsActive,
arg.IsFeatured,
arg.Offset,
arg.Limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetFeaturedLeaguesRow
var items []LeagueWithSetting
for rows.Next() {
var i GetFeaturedLeaguesRow
var i LeagueWithSetting
if err := rows.Scan(
&i.ID,
&i.Name,
&i.ImgUrl,
&i.CountryCode,
&i.Bet365ID,
&i.SportID,
&i.DefaultIsActive,
&i.DefaultIsFeatured,
&i.CompanyID,
&i.IsActive,
&i.IsFeatured,
&i.SportID,
&i.UpdatedAt,
); err != nil {
return nil, err
}
@ -168,27 +172,25 @@ INSERT INTO leagues (
country_code,
bet365_id,
sport_id,
is_active,
is_featured
default_is_active,
default_is_featured
)
VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT (id) DO
UPDATE
SET name = EXCLUDED.name,
country_code = EXCLUDED.country_code,
bet365_id = EXCLUDED.bet365_id,
is_active = EXCLUDED.is_active,
is_featured = EXCLUDED.is_featured,
sport_id = EXCLUDED.sport_id
`
type InsertLeagueParams struct {
ID int64 `json:"id"`
Name string `json:"name"`
CountryCode pgtype.Text `json:"country_code"`
Bet365ID pgtype.Int4 `json:"bet365_id"`
SportID int32 `json:"sport_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
ID int64 `json:"id"`
Name string `json:"name"`
CountryCode pgtype.Text `json:"country_code"`
Bet365ID pgtype.Int4 `json:"bet365_id"`
SportID int32 `json:"sport_id"`
DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"`
}
func (q *Queries) InsertLeague(ctx context.Context, arg InsertLeagueParams) error {
@ -198,25 +200,39 @@ func (q *Queries) InsertLeague(ctx context.Context, arg InsertLeagueParams) erro
arg.CountryCode,
arg.Bet365ID,
arg.SportID,
arg.IsActive,
arg.IsFeatured,
arg.DefaultIsActive,
arg.DefaultIsFeatured,
)
return err
}
const SetLeagueActive = `-- name: SetLeagueActive :exec
UPDATE leagues
SET is_active = $2
WHERE id = $1
const InsertLeagueSettings = `-- name: InsertLeagueSettings :exec
INSERT INTO company_league_settings (
company_id,
league_id,
is_active,
is_featured
)
VALUES ($1, $2, $3, $4) ON CONFLICT(company_id, league_id) DO
UPDATE
SET is_active = EXCLUDED.is_active,
is_featured = EXCLUDED.is_featured
`
type SetLeagueActiveParams struct {
ID int64 `json:"id"`
IsActive pgtype.Bool `json:"is_active"`
type InsertLeagueSettingsParams struct {
CompanyID int64 `json:"company_id"`
LeagueID int64 `json:"league_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
}
func (q *Queries) SetLeagueActive(ctx context.Context, arg SetLeagueActiveParams) error {
_, err := q.db.Exec(ctx, SetLeagueActive, arg.ID, arg.IsActive)
func (q *Queries) InsertLeagueSettings(ctx context.Context, arg InsertLeagueSettingsParams) error {
_, err := q.db.Exec(ctx, InsertLeagueSettings,
arg.CompanyID,
arg.LeagueID,
arg.IsActive,
arg.IsFeatured,
)
return err
}
@ -225,9 +241,7 @@ UPDATE leagues
SET name = COALESCE($2, name),
country_code = COALESCE($3, country_code),
bet365_id = COALESCE($4, bet365_id),
is_active = COALESCE($5, is_active),
is_featured = COALESCE($6, is_featured),
sport_id = COALESCE($7, sport_id)
sport_id = COALESCE($5, sport_id)
WHERE id = $1
`
@ -236,8 +250,6 @@ type UpdateLeagueParams struct {
Name pgtype.Text `json:"name"`
CountryCode pgtype.Text `json:"country_code"`
Bet365ID pgtype.Int4 `json:"bet365_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
SportID pgtype.Int4 `json:"sport_id"`
}
@ -247,43 +259,35 @@ func (q *Queries) UpdateLeague(ctx context.Context, arg UpdateLeagueParams) erro
arg.Name,
arg.CountryCode,
arg.Bet365ID,
arg.IsActive,
arg.IsFeatured,
arg.SportID,
)
return err
}
const UpdateLeagueByBet365ID = `-- name: UpdateLeagueByBet365ID :exec
UPDATE leagues
SET name = COALESCE($2, name),
id = COALESCE($3, id),
country_code = COALESCE($4, country_code),
is_active = COALESCE($5, is_active),
is_featured = COALESCE($6, is_featured),
sport_id = COALESCE($7, sport_id)
WHERE bet365_id = $1
const UpdateLeagueSettings = `-- name: UpdateLeagueSettings :exec
UPDATE company_league_settings
SET is_active = COALESCE($3, is_active),
is_featured = COALESCE(
$4,
is_featured
)
WHERE league_id = $1
AND company_id = $2
`
type UpdateLeagueByBet365IDParams struct {
Bet365ID pgtype.Int4 `json:"bet365_id"`
Name pgtype.Text `json:"name"`
ID pgtype.Int8 `json:"id"`
CountryCode pgtype.Text `json:"country_code"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
SportID pgtype.Int4 `json:"sport_id"`
type UpdateLeagueSettingsParams struct {
LeagueID int64 `json:"league_id"`
CompanyID int64 `json:"company_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
}
func (q *Queries) UpdateLeagueByBet365ID(ctx context.Context, arg UpdateLeagueByBet365IDParams) error {
_, err := q.db.Exec(ctx, UpdateLeagueByBet365ID,
arg.Bet365ID,
arg.Name,
arg.ID,
arg.CountryCode,
func (q *Queries) UpdateLeagueSettings(ctx context.Context, arg UpdateLeagueSettingsParams) error {
_, err := q.db.Exec(ctx, UpdateLeagueSettings,
arg.LeagueID,
arg.CompanyID,
arg.IsActive,
arg.IsFeatured,
arg.SportID,
)
return err
}

View File

@ -75,6 +75,7 @@ type Bank struct {
type Bet struct {
ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
Amount int64 `json:"amount"`
TotalOdds float32 `json:"total_odds"`
Status int32 `json:"status"`
@ -108,6 +109,7 @@ type BetOutcome struct {
type BetWithOutcome struct {
ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
Amount int64 `json:"amount"`
TotalOdds float32 `json:"total_odds"`
Status int32 `json:"status"`
@ -125,8 +127,8 @@ type BetWithOutcome struct {
}
type Bonu struct {
ID int64 `json:"id"`
Multiplier float32 `json:"multiplier"`
ID int64 `json:"id"`
BalanceCap int64 `json:"balance_cap"`
}
@ -184,6 +186,7 @@ type BranchOperation struct {
type CompaniesDetail struct {
ID int64 `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
AdminID int64 `json:"admin_id"`
WalletID int64 `json:"wallet_id"`
DeductedPercentage float32 `json:"deducted_percentage"`
@ -200,6 +203,7 @@ type CompaniesDetail struct {
type Company struct {
ID int64 `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
AdminID int64 `json:"admin_id"`
WalletID int64 `json:"wallet_id"`
DeductedPercentage float32 `json:"deducted_percentage"`
@ -208,6 +212,42 @@ type Company struct {
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
type CompanyEventSetting struct {
ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
EventID string `json:"event_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
WinningUpperLimit pgtype.Int4 `json:"winning_upper_limit"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
type CompanyLeagueSetting struct {
ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
LeagueID int64 `json:"league_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
type CompanyOddSetting struct {
ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
OddsMarketID int64 `json:"odds_market_id"`
IsActive pgtype.Bool `json:"is_active"`
CustomRawOdds []byte `json:"custom_raw_odds"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
type CompanySetting struct {
CompanyID int64 `json:"company_id"`
Key string `json:"key"`
Value string `json:"value"`
CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
type CustomerWallet struct {
ID int64 `json:"id"`
CustomerID int64 `json:"customer_id"`
@ -248,31 +288,111 @@ type DirectDeposit struct {
VerifiedAt pgtype.Timestamp `json:"verified_at"`
}
type DisabledOdd struct {
ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
OddsMarketID int64 `json:"odds_market_id"`
RawOddID int64 `json:"raw_odd_id"`
EventID string `json:"event_id"`
CreatedAt pgtype.Timestamp `json:"created_at"`
}
type Event struct {
ID string `json:"id"`
SportID pgtype.Int4 `json:"sport_id"`
MatchName pgtype.Text `json:"match_name"`
HomeTeam pgtype.Text `json:"home_team"`
AwayTeam pgtype.Text `json:"away_team"`
HomeTeamID pgtype.Int4 `json:"home_team_id"`
AwayTeamID pgtype.Int4 `json:"away_team_id"`
HomeKitImage pgtype.Text `json:"home_kit_image"`
AwayKitImage pgtype.Text `json:"away_kit_image"`
LeagueID pgtype.Int4 `json:"league_id"`
LeagueName pgtype.Text `json:"league_name"`
LeagueCc pgtype.Text `json:"league_cc"`
StartTime pgtype.Timestamp `json:"start_time"`
Score pgtype.Text `json:"score"`
MatchMinute pgtype.Int4 `json:"match_minute"`
TimerStatus pgtype.Text `json:"timer_status"`
AddedTime pgtype.Int4 `json:"added_time"`
MatchPeriod pgtype.Int4 `json:"match_period"`
IsLive pgtype.Bool `json:"is_live"`
Status pgtype.Text `json:"status"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
Source pgtype.Text `json:"source"`
IsFeatured bool `json:"is_featured"`
IsActive bool `json:"is_active"`
ID string `json:"id"`
SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"`
HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int64 `json:"away_team_id"`
HomeKitImage string `json:"home_kit_image"`
AwayKitImage string `json:"away_kit_image"`
LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"`
StartTime pgtype.Timestamp `json:"start_time"`
Score pgtype.Text `json:"score"`
MatchMinute pgtype.Int4 `json:"match_minute"`
TimerStatus pgtype.Text `json:"timer_status"`
AddedTime pgtype.Int4 `json:"added_time"`
MatchPeriod pgtype.Int4 `json:"match_period"`
IsLive bool `json:"is_live"`
Status string `json:"status"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
Source string `json:"source"`
DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"`
DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"`
IsMonitored bool `json:"is_monitored"`
}
type EventHistory struct {
ID int64 `json:"id"`
EventID string `json:"event_id"`
Status string `json:"status"`
CreatedAt pgtype.Timestamp `json:"created_at"`
}
type EventWithCountry struct {
ID string `json:"id"`
SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"`
HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int64 `json:"away_team_id"`
HomeKitImage string `json:"home_kit_image"`
AwayKitImage string `json:"away_kit_image"`
LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"`
StartTime pgtype.Timestamp `json:"start_time"`
Score pgtype.Text `json:"score"`
MatchMinute pgtype.Int4 `json:"match_minute"`
TimerStatus pgtype.Text `json:"timer_status"`
AddedTime pgtype.Int4 `json:"added_time"`
MatchPeriod pgtype.Int4 `json:"match_period"`
IsLive bool `json:"is_live"`
Status string `json:"status"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
Source string `json:"source"`
DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"`
DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"`
IsMonitored bool `json:"is_monitored"`
LeagueCc pgtype.Text `json:"league_cc"`
}
type EventWithSetting struct {
ID string `json:"id"`
SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"`
HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int64 `json:"away_team_id"`
HomeKitImage string `json:"home_kit_image"`
AwayKitImage string `json:"away_kit_image"`
LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"`
StartTime pgtype.Timestamp `json:"start_time"`
Score pgtype.Text `json:"score"`
MatchMinute pgtype.Int4 `json:"match_minute"`
TimerStatus pgtype.Text `json:"timer_status"`
AddedTime pgtype.Int4 `json:"added_time"`
MatchPeriod pgtype.Int4 `json:"match_period"`
IsLive bool `json:"is_live"`
Status string `json:"status"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
Source string `json:"source"`
DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"`
DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"`
IsMonitored bool `json:"is_monitored"`
CompanyID int64 `json:"company_id"`
IsActive bool `json:"is_active"`
IsFeatured bool `json:"is_featured"`
WinningUpperLimit int32 `json:"winning_upper_limit"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
LeagueCc pgtype.Text `json:"league_cc"`
}
type ExchangeRate struct {
@ -292,23 +412,45 @@ type FavoriteGame struct {
}
type Flag struct {
ID int64 `json:"id"`
BetID pgtype.Int8 `json:"bet_id"`
OddID pgtype.Int8 `json:"odd_id"`
Reason pgtype.Text `json:"reason"`
FlaggedAt pgtype.Timestamp `json:"flagged_at"`
Resolved pgtype.Bool `json:"resolved"`
ID int64 `json:"id"`
BetID pgtype.Int8 `json:"bet_id"`
OddsMarketID pgtype.Int8 `json:"odds_market_id"`
Reason pgtype.Text `json:"reason"`
FlaggedAt pgtype.Timestamp `json:"flagged_at"`
Resolved pgtype.Bool `json:"resolved"`
}
type GlobalSetting struct {
Key string `json:"key"`
Value string `json:"value"`
CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
type League struct {
ID int64 `json:"id"`
Name string `json:"name"`
Img pgtype.Text `json:"img"`
CountryCode pgtype.Text `json:"country_code"`
Bet365ID pgtype.Int4 `json:"bet365_id"`
SportID int32 `json:"sport_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
ID int64 `json:"id"`
Name string `json:"name"`
ImgUrl pgtype.Text `json:"img_url"`
CountryCode pgtype.Text `json:"country_code"`
Bet365ID pgtype.Int4 `json:"bet365_id"`
SportID int32 `json:"sport_id"`
DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"`
}
type LeagueWithSetting struct {
ID int64 `json:"id"`
Name string `json:"name"`
ImgUrl pgtype.Text `json:"img_url"`
CountryCode pgtype.Text `json:"country_code"`
Bet365ID pgtype.Int4 `json:"bet365_id"`
SportID int32 `json:"sport_id"`
DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"`
CompanyID int64 `json:"company_id"`
IsActive bool `json:"is_active"`
IsFeatured bool `json:"is_featured"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
type Notification struct {
@ -328,23 +470,60 @@ type Notification struct {
Metadata []byte `json:"metadata"`
}
type Odd struct {
ID int32 `json:"id"`
EventID pgtype.Text `json:"event_id"`
Fi pgtype.Text `json:"fi"`
MarketType string `json:"market_type"`
MarketName pgtype.Text `json:"market_name"`
MarketCategory pgtype.Text `json:"market_category"`
MarketID pgtype.Text `json:"market_id"`
Name pgtype.Text `json:"name"`
Handicap pgtype.Text `json:"handicap"`
OddsValue pgtype.Float8 `json:"odds_value"`
Section string `json:"section"`
Category pgtype.Text `json:"category"`
RawOdds []byte `json:"raw_odds"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
Source pgtype.Text `json:"source"`
IsActive pgtype.Bool `json:"is_active"`
type OddHistory struct {
ID int64 `json:"id"`
OddsMarketID int64 `json:"odds_market_id"`
RawOddID int64 `json:"raw_odd_id"`
MarketID string `json:"market_id"`
EventID string `json:"event_id"`
OddValue float64 `json:"odd_value"`
CreatedAt pgtype.Timestamp `json:"created_at"`
}
type OddsMarket struct {
ID int64 `json:"id"`
EventID string `json:"event_id"`
MarketType string `json:"market_type"`
MarketName string `json:"market_name"`
MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"`
RawOdds []byte `json:"raw_odds"`
DefaultIsActive bool `json:"default_is_active"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
}
type OddsMarketWithEvent struct {
ID int64 `json:"id"`
EventID string `json:"event_id"`
MarketType string `json:"market_type"`
MarketName string `json:"market_name"`
MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"`
RawOdds []byte `json:"raw_odds"`
DefaultIsActive bool `json:"default_is_active"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
IsMonitored bool `json:"is_monitored"`
IsLive bool `json:"is_live"`
Status string `json:"status"`
Source string `json:"source"`
}
type OddsMarketWithSetting struct {
ID int64 `json:"id"`
EventID string `json:"event_id"`
MarketType string `json:"market_type"`
MarketName string `json:"market_name"`
MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"`
DefaultIsActive bool `json:"default_is_active"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
CompanyID int64 `json:"company_id"`
IsActive bool `json:"is_active"`
RawOdds []byte `json:"raw_odds"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
type Otp struct {
@ -422,11 +601,21 @@ type Result struct {
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
type Setting struct {
Key string `json:"key"`
Value string `json:"value"`
CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
type ResultLog struct {
ID int64 `json:"id"`
StatusNotFinishedCount int32 `json:"status_not_finished_count"`
StatusNotFinishedBets int32 `json:"status_not_finished_bets"`
StatusToBeFixedCount int32 `json:"status_to_be_fixed_count"`
StatusToBeFixedBets int32 `json:"status_to_be_fixed_bets"`
StatusPostponedCount int32 `json:"status_postponed_count"`
StatusPostponedBets int32 `json:"status_postponed_bets"`
StatusEndedCount int32 `json:"status_ended_count"`
StatusEndedBets int32 `json:"status_ended_bets"`
StatusRemovedCount int32 `json:"status_removed_count"`
StatusRemovedBets int32 `json:"status_removed_bets"`
RemovedCount int32 `json:"removed_count"`
CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
type ShopBet struct {
@ -545,15 +734,16 @@ type SupportedOperation struct {
}
type Team struct {
ID string `json:"id"`
TeamName string `json:"team_name"`
Country pgtype.Text `json:"country"`
Bet365ID pgtype.Int4 `json:"bet365_id"`
LogoUrl pgtype.Text `json:"logo_url"`
ID int64 `json:"id"`
TeamName string `json:"team_name"`
CountryCode string `json:"country_code"`
Bet365ID pgtype.Int8 `json:"bet365_id"`
ImgUrl pgtype.Text `json:"img_url"`
}
type Ticket struct {
ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
Amount int64 `json:"amount"`
TotalOdds float32 `json:"total_odds"`
Ip string `json:"ip"`
@ -580,6 +770,7 @@ type TicketOutcome struct {
type TicketWithOutcome struct {
ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
Amount int64 `json:"amount"`
TotalOdds float32 `json:"total_odds"`
Ip string `json:"ip"`
@ -695,6 +886,7 @@ type VirtualGameTransaction struct {
type Wallet struct {
ID int64 `json:"id"`
Balance int64 `json:"balance"`
Currency string `json:"currency"`
IsWithdraw bool `json:"is_withdraw"`
IsBettable bool `json:"is_bettable"`
IsTransferable bool `json:"is_transferable"`
@ -703,7 +895,6 @@ type Wallet struct {
IsActive bool `json:"is_active"`
CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
Currency string `json:"currency"`
BonusBalance pgtype.Numeric `json:"bonus_balance"`
CashBalance pgtype.Numeric `json:"cash_balance"`
}

203
gen/db/odd_history.sql.go Normal file
View File

@ -0,0 +1,203 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.29.0
// source: odd_history.sql
package dbgen
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const GetAllOddHistory = `-- name: GetAllOddHistory :many
SELECT id, odds_market_id, raw_odd_id, market_id, event_id, odd_value, created_at
FROM odd_history
WHERE (
odds_market_id = $1
OR $1 IS NULL
)
AND (
market_id = $2
OR $2 IS NULL
)
AND (
raw_odd_id = $3
OR $3 IS NULL
)
AND (
event_id = $4
OR $4 IS NULL
)
AND (
created_at > $5
OR $5 IS NULL
)
AND (
created_at < $6
OR $6 IS NULL
)
`
type GetAllOddHistoryParams struct {
OddID pgtype.Int8 `json:"odd_id"`
MarketID pgtype.Text `json:"market_id"`
RawOddID pgtype.Int8 `json:"raw_odd_id"`
EventID pgtype.Text `json:"event_id"`
CreatedBefore pgtype.Timestamp `json:"created_before"`
CreatedAfter pgtype.Timestamp `json:"created_after"`
}
func (q *Queries) GetAllOddHistory(ctx context.Context, arg GetAllOddHistoryParams) ([]OddHistory, error) {
rows, err := q.db.Query(ctx, GetAllOddHistory,
arg.OddID,
arg.MarketID,
arg.RawOddID,
arg.EventID,
arg.CreatedBefore,
arg.CreatedAfter,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []OddHistory
for rows.Next() {
var i OddHistory
if err := rows.Scan(
&i.ID,
&i.OddsMarketID,
&i.RawOddID,
&i.MarketID,
&i.EventID,
&i.OddValue,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetInitialOddPerDay = `-- name: GetInitialOddPerDay :many
SELECT DISTINCT ON (DATE_TRUNC($1, created_at)) id, odds_market_id, raw_odd_id, market_id, event_id, odd_value, created_at
FROM odd_history
WHERE (
odds_market_id = $2
OR $2 IS NULL
)
AND (
market_id = $3
OR $3 IS NULL
)
AND (
raw_odd_id = $4
OR $4 IS NULL
)
AND (
event_id = $5
OR $5 IS NULL
)
AND (
created_at > $6
OR $6 IS NULL
)
AND (
created_at < $7
OR $7 IS NULL
)
ORDER BY DATE_TRUNC($1, created_at),
created_at ASC
`
type GetInitialOddPerDayParams struct {
DateTrunc string `json:"date_trunc"`
OddID pgtype.Int8 `json:"odd_id"`
MarketID pgtype.Text `json:"market_id"`
RawOddID pgtype.Int8 `json:"raw_odd_id"`
EventID pgtype.Text `json:"event_id"`
CreatedBefore pgtype.Timestamp `json:"created_before"`
CreatedAfter pgtype.Timestamp `json:"created_after"`
}
func (q *Queries) GetInitialOddPerDay(ctx context.Context, arg GetInitialOddPerDayParams) ([]OddHistory, error) {
rows, err := q.db.Query(ctx, GetInitialOddPerDay,
arg.DateTrunc,
arg.OddID,
arg.MarketID,
arg.RawOddID,
arg.EventID,
arg.CreatedBefore,
arg.CreatedAfter,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []OddHistory
for rows.Next() {
var i OddHistory
if err := rows.Scan(
&i.ID,
&i.OddsMarketID,
&i.RawOddID,
&i.MarketID,
&i.EventID,
&i.OddValue,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const InsertOddHistory = `-- name: InsertOddHistory :one
INSERT INTO odd_history (
odds_market_id,
market_id,
raw_odd_id,
event_id,
odd_value
)
VALUES ($1, $2, $3, $4, $5)
RETURNING id, odds_market_id, raw_odd_id, market_id, event_id, odd_value, created_at
`
type InsertOddHistoryParams struct {
OddsMarketID int64 `json:"odds_market_id"`
MarketID string `json:"market_id"`
RawOddID int64 `json:"raw_odd_id"`
EventID string `json:"event_id"`
OddValue float64 `json:"odd_value"`
}
func (q *Queries) InsertOddHistory(ctx context.Context, arg InsertOddHistoryParams) (OddHistory, error) {
row := q.db.QueryRow(ctx, InsertOddHistory,
arg.OddsMarketID,
arg.MarketID,
arg.RawOddID,
arg.EventID,
arg.OddValue,
)
var i OddHistory
err := row.Scan(
&i.ID,
&i.OddsMarketID,
&i.RawOddID,
&i.MarketID,
&i.EventID,
&i.OddValue,
&i.CreatedAt,
)
return i, err
}

View File

@ -12,134 +12,50 @@ import (
)
const DeleteOddsForEvent = `-- name: DeleteOddsForEvent :exec
DELETE FROM odds
Where fi = $1
DELETE FROM odds_market
Where event_id = $1
`
func (q *Queries) DeleteOddsForEvent(ctx context.Context, fi pgtype.Text) error {
_, err := q.db.Exec(ctx, DeleteOddsForEvent, fi)
func (q *Queries) DeleteOddsForEvent(ctx context.Context, eventID string) error {
_, err := q.db.Exec(ctx, DeleteOddsForEvent, eventID)
return err
}
const GetALLPrematchOdds = `-- 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 = 'bet365'
const GetAllOdds = `-- name: GetAllOdds :many
SELECT id, event_id, market_type, market_name, market_category, market_id, raw_odds, default_is_active, fetched_at, expires_at, is_monitored, is_live, status, source
FROM odds_market_with_event
LIMIT $2 OFFSET $1
`
type GetALLPrematchOddsRow struct {
EventID pgtype.Text `json:"event_id"`
Fi pgtype.Text `json:"fi"`
MarketType string `json:"market_type"`
MarketName pgtype.Text `json:"market_name"`
MarketCategory pgtype.Text `json:"market_category"`
MarketID pgtype.Text `json:"market_id"`
Name pgtype.Text `json:"name"`
Handicap pgtype.Text `json:"handicap"`
OddsValue pgtype.Float8 `json:"odds_value"`
Section string `json:"section"`
Category pgtype.Text `json:"category"`
RawOdds []byte `json:"raw_odds"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
Source pgtype.Text `json:"source"`
IsActive pgtype.Bool `json:"is_active"`
}
func (q *Queries) GetALLPrematchOdds(ctx context.Context) ([]GetALLPrematchOddsRow, error) {
rows, err := q.db.Query(ctx, GetALLPrematchOdds)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetALLPrematchOddsRow
for rows.Next() {
var i GetALLPrematchOddsRow
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 GetPaginatedPrematchOddsByUpcomingID = `-- name: GetPaginatedPrematchOddsByUpcomingID :many
SELECT o.id, 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 = 'bet365'
LIMIT $3 OFFSET $2
`
type GetPaginatedPrematchOddsByUpcomingIDParams struct {
ID string `json:"id"`
type GetAllOddsParams struct {
Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"`
}
func (q *Queries) GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, arg GetPaginatedPrematchOddsByUpcomingIDParams) ([]Odd, error) {
rows, err := q.db.Query(ctx, GetPaginatedPrematchOddsByUpcomingID, arg.ID, arg.Offset, arg.Limit)
func (q *Queries) GetAllOdds(ctx context.Context, arg GetAllOddsParams) ([]OddsMarketWithEvent, error) {
rows, err := q.db.Query(ctx, GetAllOdds, arg.Offset, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Odd
var items []OddsMarketWithEvent
for rows.Next() {
var i Odd
var i OddsMarketWithEvent
if err := rows.Scan(
&i.ID,
&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.DefaultIsActive,
&i.FetchedAt,
&i.ExpiresAt,
&i.IsMonitored,
&i.IsLive,
&i.Status,
&i.Source,
&i.IsActive,
); err != nil {
return nil, err
}
@ -151,118 +67,42 @@ func (q *Queries) GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, arg
return items, nil
}
const GetPrematchOdds = `-- name: GetPrematchOdds :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 = 'bet365'
const GetAllOddsWithSettings = `-- name: GetAllOddsWithSettings :many
SELECT id, event_id, market_type, market_name, market_category, market_id, default_is_active, fetched_at, expires_at, company_id, is_active, raw_odds, updated_at
FROM odds_market_with_settings
WHERE company_id = $1
LIMIT $3 OFFSET $2
`
type GetPrematchOddsRow struct {
EventID pgtype.Text `json:"event_id"`
Fi pgtype.Text `json:"fi"`
MarketType string `json:"market_type"`
MarketName pgtype.Text `json:"market_name"`
MarketCategory pgtype.Text `json:"market_category"`
MarketID pgtype.Text `json:"market_id"`
Name pgtype.Text `json:"name"`
Handicap pgtype.Text `json:"handicap"`
OddsValue pgtype.Float8 `json:"odds_value"`
Section string `json:"section"`
Category pgtype.Text `json:"category"`
RawOdds []byte `json:"raw_odds"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
Source pgtype.Text `json:"source"`
IsActive pgtype.Bool `json:"is_active"`
type GetAllOddsWithSettingsParams struct {
CompanyID int64 `json:"company_id"`
Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"`
}
func (q *Queries) GetPrematchOdds(ctx context.Context) ([]GetPrematchOddsRow, error) {
rows, err := q.db.Query(ctx, GetPrematchOdds)
func (q *Queries) GetAllOddsWithSettings(ctx context.Context, arg GetAllOddsWithSettingsParams) ([]OddsMarketWithSetting, error) {
rows, err := q.db.Query(ctx, GetAllOddsWithSettings, arg.CompanyID, arg.Offset, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetPrematchOddsRow
var items []OddsMarketWithSetting
for rows.Next() {
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.id, 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 = 'bet365'
`
func (q *Queries) GetPrematchOddsByUpcomingID(ctx context.Context, id string) ([]Odd, error) {
rows, err := q.db.Query(ctx, GetPrematchOddsByUpcomingID, id)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Odd
for rows.Next() {
var i Odd
var i OddsMarketWithSetting
if err := rows.Scan(
&i.ID,
&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.DefaultIsActive,
&i.FetchedAt,
&i.Source,
&i.ExpiresAt,
&i.CompanyID,
&i.IsActive,
&i.RawOdds,
&i.UpdatedAt,
); err != nil {
return nil, err
}
@ -274,62 +114,239 @@ func (q *Queries) GetPrematchOddsByUpcomingID(ctx context.Context, id string) ([
return items, nil
}
const GetRawOddsByMarketID = `-- name: GetRawOddsByMarketID :one
SELECT id,
market_name,
handicap,
raw_odds,
fetched_at
FROM odds
const GetOddsByEventID = `-- name: GetOddsByEventID :many
SELECT id, event_id, market_type, market_name, market_category, market_id, raw_odds, default_is_active, fetched_at, expires_at, is_monitored, is_live, status, source
FROM odds_market_with_event
WHERE event_id = $1
AND (
is_live = $2
OR $2 IS NULL
)
AND (
status = $3
OR $3 IS NULL
)
AND (
source = $4
OR $4 IS NULL
)
LIMIT $6 OFFSET $5
`
type GetOddsByEventIDParams struct {
EventID string `json:"event_id"`
IsLive pgtype.Bool `json:"is_live"`
Status pgtype.Text `json:"status"`
Source pgtype.Text `json:"source"`
Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"`
}
func (q *Queries) GetOddsByEventID(ctx context.Context, arg GetOddsByEventIDParams) ([]OddsMarketWithEvent, error) {
rows, err := q.db.Query(ctx, GetOddsByEventID,
arg.EventID,
arg.IsLive,
arg.Status,
arg.Source,
arg.Offset,
arg.Limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []OddsMarketWithEvent
for rows.Next() {
var i OddsMarketWithEvent
if err := rows.Scan(
&i.ID,
&i.EventID,
&i.MarketType,
&i.MarketName,
&i.MarketCategory,
&i.MarketID,
&i.RawOdds,
&i.DefaultIsActive,
&i.FetchedAt,
&i.ExpiresAt,
&i.IsMonitored,
&i.IsLive,
&i.Status,
&i.Source,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetOddsByMarketID = `-- name: GetOddsByMarketID :one
SELECT id, event_id, market_type, market_name, market_category, market_id, raw_odds, default_is_active, fetched_at, expires_at, is_monitored, is_live, status, source
FROM odds_market_with_event
WHERE market_id = $1
AND fi = $2
AND is_active = true
AND source = 'bet365'
AND event_id = $2
`
type GetRawOddsByMarketIDParams struct {
MarketID pgtype.Text `json:"market_id"`
Fi pgtype.Text `json:"fi"`
type GetOddsByMarketIDParams struct {
MarketID string `json:"market_id"`
EventID string `json:"event_id"`
}
type GetRawOddsByMarketIDRow struct {
ID int32 `json:"id"`
MarketName pgtype.Text `json:"market_name"`
Handicap pgtype.Text `json:"handicap"`
RawOdds []byte `json:"raw_odds"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
}
func (q *Queries) GetRawOddsByMarketID(ctx context.Context, arg GetRawOddsByMarketIDParams) (GetRawOddsByMarketIDRow, error) {
row := q.db.QueryRow(ctx, GetRawOddsByMarketID, arg.MarketID, arg.Fi)
var i GetRawOddsByMarketIDRow
func (q *Queries) GetOddsByMarketID(ctx context.Context, arg GetOddsByMarketIDParams) (OddsMarketWithEvent, error) {
row := q.db.QueryRow(ctx, GetOddsByMarketID, arg.MarketID, arg.EventID)
var i OddsMarketWithEvent
err := row.Scan(
&i.ID,
&i.EventID,
&i.MarketType,
&i.MarketName,
&i.Handicap,
&i.MarketCategory,
&i.MarketID,
&i.RawOdds,
&i.DefaultIsActive,
&i.FetchedAt,
&i.ExpiresAt,
&i.IsMonitored,
&i.IsLive,
&i.Status,
&i.Source,
)
return i, err
}
const InsertNonLiveOdd = `-- name: InsertNonLiveOdd :exec
INSERT INTO odds (
const GetOddsWithSettingsByEventID = `-- name: GetOddsWithSettingsByEventID :many
SELECT id, event_id, market_type, market_name, market_category, market_id, default_is_active, fetched_at, expires_at, company_id, is_active, raw_odds, updated_at
FROM odds_market_with_settings
WHERE event_id = $1
AND company_id = $2
LIMIT $4 OFFSET $3
`
type GetOddsWithSettingsByEventIDParams struct {
EventID string `json:"event_id"`
CompanyID int64 `json:"company_id"`
Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"`
}
func (q *Queries) GetOddsWithSettingsByEventID(ctx context.Context, arg GetOddsWithSettingsByEventIDParams) ([]OddsMarketWithSetting, error) {
rows, err := q.db.Query(ctx, GetOddsWithSettingsByEventID,
arg.EventID,
arg.CompanyID,
arg.Offset,
arg.Limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []OddsMarketWithSetting
for rows.Next() {
var i OddsMarketWithSetting
if err := rows.Scan(
&i.ID,
&i.EventID,
&i.MarketType,
&i.MarketName,
&i.MarketCategory,
&i.MarketID,
&i.DefaultIsActive,
&i.FetchedAt,
&i.ExpiresAt,
&i.CompanyID,
&i.IsActive,
&i.RawOdds,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetOddsWithSettingsByMarketID = `-- name: GetOddsWithSettingsByMarketID :one
SELECT id, event_id, market_type, market_name, market_category, market_id, default_is_active, fetched_at, expires_at, company_id, is_active, raw_odds, updated_at
FROM odds_market_with_settings
WHERE market_id = $1
AND event_id = $2
AND company_id = $3
`
type GetOddsWithSettingsByMarketIDParams struct {
MarketID string `json:"market_id"`
EventID string `json:"event_id"`
CompanyID int64 `json:"company_id"`
}
func (q *Queries) GetOddsWithSettingsByMarketID(ctx context.Context, arg GetOddsWithSettingsByMarketIDParams) (OddsMarketWithSetting, error) {
row := q.db.QueryRow(ctx, GetOddsWithSettingsByMarketID, arg.MarketID, arg.EventID, arg.CompanyID)
var i OddsMarketWithSetting
err := row.Scan(
&i.ID,
&i.EventID,
&i.MarketType,
&i.MarketName,
&i.MarketCategory,
&i.MarketID,
&i.DefaultIsActive,
&i.FetchedAt,
&i.ExpiresAt,
&i.CompanyID,
&i.IsActive,
&i.RawOdds,
&i.UpdatedAt,
)
return i, err
}
const InsertOddSettings = `-- name: InsertOddSettings :exec
INSERT INTO company_odd_settings (
company_id,
odds_market_id,
is_active,
custom_raw_odds
)
VALUES ($1, $2, $3, $4) ON CONFLICT (company_id, odds_market_id) DO
UPDATE
SET is_active = EXCLUDED.is_active,
custom_raw_odds = EXCLUDED.custom_raw_odds
`
type InsertOddSettingsParams struct {
CompanyID int64 `json:"company_id"`
OddsMarketID int64 `json:"odds_market_id"`
IsActive pgtype.Bool `json:"is_active"`
CustomRawOdds []byte `json:"custom_raw_odds"`
}
func (q *Queries) InsertOddSettings(ctx context.Context, arg InsertOddSettingsParams) error {
_, err := q.db.Exec(ctx, InsertOddSettings,
arg.CompanyID,
arg.OddsMarketID,
arg.IsActive,
arg.CustomRawOdds,
)
return err
}
const InsertOddsMarket = `-- name: InsertOddsMarket :exec
INSERT INTO odds_market (
event_id,
fi,
market_type,
market_name,
market_category,
market_id,
name,
handicap,
odds_value,
section,
category,
raw_odds,
is_active,
source,
fetched_at
fetched_at,
expires_at
)
VALUES (
$1,
@ -339,64 +356,38 @@ VALUES (
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12,
$13,
$14,
$15
$8
) ON CONFLICT (event_id, market_id) DO
UPDATE
SET odds_value = EXCLUDED.odds_value,
raw_odds = EXCLUDED.raw_odds,
market_type = EXCLUDED.market_type,
SET market_type = EXCLUDED.market_type,
market_name = EXCLUDED.market_name,
market_category = EXCLUDED.market_category,
name = EXCLUDED.name,
handicap = EXCLUDED.handicap,
raw_odds = EXCLUDED.raw_odds,
fetched_at = EXCLUDED.fetched_at,
is_active = EXCLUDED.is_active,
source = EXCLUDED.source,
fi = EXCLUDED.fi
expires_at = EXCLUDED.expires_at
`
type InsertNonLiveOddParams struct {
EventID pgtype.Text `json:"event_id"`
Fi pgtype.Text `json:"fi"`
type InsertOddsMarketParams struct {
EventID string `json:"event_id"`
MarketType string `json:"market_type"`
MarketName pgtype.Text `json:"market_name"`
MarketCategory pgtype.Text `json:"market_category"`
MarketID pgtype.Text `json:"market_id"`
Name pgtype.Text `json:"name"`
Handicap pgtype.Text `json:"handicap"`
OddsValue pgtype.Float8 `json:"odds_value"`
Section string `json:"section"`
Category pgtype.Text `json:"category"`
MarketName string `json:"market_name"`
MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"`
RawOdds []byte `json:"raw_odds"`
IsActive pgtype.Bool `json:"is_active"`
Source pgtype.Text `json:"source"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
}
func (q *Queries) InsertNonLiveOdd(ctx context.Context, arg InsertNonLiveOddParams) error {
_, err := q.db.Exec(ctx, InsertNonLiveOdd,
func (q *Queries) InsertOddsMarket(ctx context.Context, arg InsertOddsMarketParams) error {
_, err := q.db.Exec(ctx, InsertOddsMarket,
arg.EventID,
arg.Fi,
arg.MarketType,
arg.MarketName,
arg.MarketCategory,
arg.MarketID,
arg.Name,
arg.Handicap,
arg.OddsValue,
arg.Section,
arg.Category,
arg.RawOdds,
arg.IsActive,
arg.Source,
arg.FetchedAt,
arg.ExpiresAt,
)
return err
}

132
gen/db/result_log.sql.go Normal file
View File

@ -0,0 +1,132 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.29.0
// source: result_log.sql
package dbgen
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const CreateResultLog = `-- name: CreateResultLog :one
INSERT INTO result_log (
status_not_finished_count,
status_not_finished_bets,
status_to_be_fixed_count,
status_to_be_fixed_bets,
status_postponed_count,
status_postponed_bets,
status_ended_count,
status_ended_bets,
status_removed_count,
status_removed_bets,
removed_count
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
RETURNING id, status_not_finished_count, status_not_finished_bets, status_to_be_fixed_count, status_to_be_fixed_bets, status_postponed_count, status_postponed_bets, status_ended_count, status_ended_bets, status_removed_count, status_removed_bets, removed_count, created_at, updated_at
`
type CreateResultLogParams struct {
StatusNotFinishedCount int32 `json:"status_not_finished_count"`
StatusNotFinishedBets int32 `json:"status_not_finished_bets"`
StatusToBeFixedCount int32 `json:"status_to_be_fixed_count"`
StatusToBeFixedBets int32 `json:"status_to_be_fixed_bets"`
StatusPostponedCount int32 `json:"status_postponed_count"`
StatusPostponedBets int32 `json:"status_postponed_bets"`
StatusEndedCount int32 `json:"status_ended_count"`
StatusEndedBets int32 `json:"status_ended_bets"`
StatusRemovedCount int32 `json:"status_removed_count"`
StatusRemovedBets int32 `json:"status_removed_bets"`
RemovedCount int32 `json:"removed_count"`
}
func (q *Queries) CreateResultLog(ctx context.Context, arg CreateResultLogParams) (ResultLog, error) {
row := q.db.QueryRow(ctx, CreateResultLog,
arg.StatusNotFinishedCount,
arg.StatusNotFinishedBets,
arg.StatusToBeFixedCount,
arg.StatusToBeFixedBets,
arg.StatusPostponedCount,
arg.StatusPostponedBets,
arg.StatusEndedCount,
arg.StatusEndedBets,
arg.StatusRemovedCount,
arg.StatusRemovedBets,
arg.RemovedCount,
)
var i ResultLog
err := row.Scan(
&i.ID,
&i.StatusNotFinishedCount,
&i.StatusNotFinishedBets,
&i.StatusToBeFixedCount,
&i.StatusToBeFixedBets,
&i.StatusPostponedCount,
&i.StatusPostponedBets,
&i.StatusEndedCount,
&i.StatusEndedBets,
&i.StatusRemovedCount,
&i.StatusRemovedBets,
&i.RemovedCount,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetAllResultLog = `-- name: GetAllResultLog :many
SELECT id, status_not_finished_count, status_not_finished_bets, status_to_be_fixed_count, status_to_be_fixed_bets, status_postponed_count, status_postponed_bets, status_ended_count, status_ended_bets, status_removed_count, status_removed_bets, removed_count, created_at, updated_at
FROM result_log
WHERE (
created_at < $1
OR $1 IS NULL
)
AND (
created_at > $2
OR $2 IS NULL
)
ORDER BY created_at DESC
`
type GetAllResultLogParams struct {
CreatedBefore pgtype.Timestamp `json:"created_before"`
CreatedAfter pgtype.Timestamp `json:"created_after"`
}
func (q *Queries) GetAllResultLog(ctx context.Context, arg GetAllResultLogParams) ([]ResultLog, error) {
rows, err := q.db.Query(ctx, GetAllResultLog, arg.CreatedBefore, arg.CreatedAfter)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ResultLog
for rows.Next() {
var i ResultLog
if err := rows.Scan(
&i.ID,
&i.StatusNotFinishedCount,
&i.StatusNotFinishedBets,
&i.StatusToBeFixedCount,
&i.StatusToBeFixedBets,
&i.StatusPostponedCount,
&i.StatusPostponedBets,
&i.StatusEndedCount,
&i.StatusEndedBets,
&i.StatusRemovedCount,
&i.StatusRemovedBets,
&i.RemovedCount,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}

View File

@ -7,17 +7,140 @@ package dbgen
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const GetSetting = `-- name: GetSetting :one
SELECT key, value, created_at, updated_at
FROM settings
const DeleteAllCompanySetting = `-- name: DeleteAllCompanySetting :exec
DELETE FROM company_settings
WHERE company_id = $1
`
func (q *Queries) DeleteAllCompanySetting(ctx context.Context, companyID int64) error {
_, err := q.db.Exec(ctx, DeleteAllCompanySetting, companyID)
return err
}
const DeleteCompanySetting = `-- name: DeleteCompanySetting :exec
DELETE FROM company_settings
WHERE company_id = $1
AND key = $2
`
type DeleteCompanySettingParams struct {
CompanyID int64 `json:"company_id"`
Key string `json:"key"`
}
func (q *Queries) DeleteCompanySetting(ctx context.Context, arg DeleteCompanySettingParams) error {
_, err := q.db.Exec(ctx, DeleteCompanySetting, arg.CompanyID, arg.Key)
return err
}
const GetAllCompanySettings = `-- name: GetAllCompanySettings :many
SELECT company_id, key, value, created_at, updated_at
FROM company_settings
`
func (q *Queries) GetAllCompanySettings(ctx context.Context) ([]CompanySetting, error) {
rows, err := q.db.Query(ctx, GetAllCompanySettings)
if err != nil {
return nil, err
}
defer rows.Close()
var items []CompanySetting
for rows.Next() {
var i CompanySetting
if err := rows.Scan(
&i.CompanyID,
&i.Key,
&i.Value,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetCompanySetting = `-- name: GetCompanySetting :many
SELECT company_id, key, value, created_at, updated_at
FROM company_settings
WHERE company_id = $1
`
func (q *Queries) GetCompanySetting(ctx context.Context, companyID int64) ([]CompanySetting, error) {
rows, err := q.db.Query(ctx, GetCompanySetting, companyID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []CompanySetting
for rows.Next() {
var i CompanySetting
if err := rows.Scan(
&i.CompanyID,
&i.Key,
&i.Value,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetCompanySettingsByKey = `-- name: GetCompanySettingsByKey :many
SELECT company_id, key, value, created_at, updated_at
FROM company_settings
WHERE key = $1
`
func (q *Queries) GetSetting(ctx context.Context, key string) (Setting, error) {
row := q.db.QueryRow(ctx, GetSetting, key)
var i Setting
func (q *Queries) GetCompanySettingsByKey(ctx context.Context, key string) ([]CompanySetting, error) {
rows, err := q.db.Query(ctx, GetCompanySettingsByKey, key)
if err != nil {
return nil, err
}
defer rows.Close()
var items []CompanySetting
for rows.Next() {
var i CompanySetting
if err := rows.Scan(
&i.CompanyID,
&i.Key,
&i.Value,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetGlobalSetting = `-- name: GetGlobalSetting :one
SELECT key, value, created_at, updated_at
FROM global_settings
WHERE key = $1
`
func (q *Queries) GetGlobalSetting(ctx context.Context, key string) (GlobalSetting, error) {
row := q.db.QueryRow(ctx, GetGlobalSetting, key)
var i GlobalSetting
err := row.Scan(
&i.Key,
&i.Value,
@ -27,20 +150,20 @@ func (q *Queries) GetSetting(ctx context.Context, key string) (Setting, error) {
return i, err
}
const GetSettings = `-- name: GetSettings :many
const GetGlobalSettings = `-- name: GetGlobalSettings :many
SELECT key, value, created_at, updated_at
FROM settings
FROM global_settings
`
func (q *Queries) GetSettings(ctx context.Context) ([]Setting, error) {
rows, err := q.db.Query(ctx, GetSettings)
func (q *Queries) GetGlobalSettings(ctx context.Context) ([]GlobalSetting, error) {
rows, err := q.db.Query(ctx, GetGlobalSettings)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Setting
var items []GlobalSetting
for rows.Next() {
var i Setting
var i GlobalSetting
if err := rows.Scan(
&i.Key,
&i.Value,
@ -57,27 +180,79 @@ func (q *Queries) GetSettings(ctx context.Context) ([]Setting, error) {
return items, nil
}
const SaveSetting = `-- name: SaveSetting :one
INSERT INTO settings (key, value, updated_at)
VALUES ($1, $2, CURRENT_TIMESTAMP) ON CONFLICT (key) DO
UPDATE
SET value = EXCLUDED.value
RETURNING key, value, created_at, updated_at
const GetOverrideSettings = `-- name: GetOverrideSettings :many
SELECT gs.key, gs.value, gs.created_at, gs.updated_at,
COALESCE(cs.value, gs.value) AS value
FROM global_settings gs
LEFT JOIN company_settings cs ON cs.key = gs.key
AND cs.company_id = $1
`
type SaveSettingParams struct {
type GetOverrideSettingsRow struct {
Key string `json:"key"`
Value string `json:"value"`
CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
Value_2 string `json:"value_2"`
}
func (q *Queries) GetOverrideSettings(ctx context.Context, companyID int64) ([]GetOverrideSettingsRow, error) {
rows, err := q.db.Query(ctx, GetOverrideSettings, companyID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetOverrideSettingsRow
for rows.Next() {
var i GetOverrideSettingsRow
if err := rows.Scan(
&i.Key,
&i.Value,
&i.CreatedAt,
&i.UpdatedAt,
&i.Value_2,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const InsertCompanySetting = `-- name: InsertCompanySetting :exec
INSERT INTO company_settings (company_id, key, value)
VALUES ($1, $2, $3) ON CONFLICT (company_id, key) DO
UPDATE
SET value = EXCLUDED.value
`
type InsertCompanySettingParams struct {
CompanyID int64 `json:"company_id"`
Key string `json:"key"`
Value string `json:"value"`
}
func (q *Queries) InsertCompanySetting(ctx context.Context, arg InsertCompanySettingParams) error {
_, err := q.db.Exec(ctx, InsertCompanySetting, arg.CompanyID, arg.Key, arg.Value)
return err
}
const UpdateGlobalSetting = `-- name: UpdateGlobalSetting :exec
UPDATE global_settings
SET value = $2,
updated_at = CURRENT_TIMESTAMP
WHERE key = $1
`
type UpdateGlobalSettingParams struct {
Key string `json:"key"`
Value string `json:"value"`
}
func (q *Queries) SaveSetting(ctx context.Context, arg SaveSettingParams) (Setting, error) {
row := q.db.QueryRow(ctx, SaveSetting, arg.Key, arg.Value)
var i Setting
err := row.Scan(
&i.Key,
&i.Value,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
func (q *Queries) UpdateGlobalSetting(ctx context.Context, arg UpdateGlobalSettingParams) error {
_, err := q.db.Exec(ctx, UpdateGlobalSetting, arg.Key, arg.Value)
return err
}

View File

@ -25,22 +25,29 @@ func (q *Queries) CountTicketByIP(ctx context.Context, ip string) (int64, error)
}
const CreateTicket = `-- name: CreateTicket :one
INSERT INTO tickets (amount, total_odds, ip)
VALUES ($1, $2, $3)
RETURNING id, amount, total_odds, ip, created_at, updated_at
INSERT INTO tickets (amount, total_odds, ip, company_id)
VALUES ($1, $2, $3, $4)
RETURNING id, company_id, amount, total_odds, ip, created_at, updated_at
`
type CreateTicketParams struct {
Amount int64 `json:"amount"`
TotalOdds float32 `json:"total_odds"`
Ip string `json:"ip"`
CompanyID int64 `json:"company_id"`
}
func (q *Queries) CreateTicket(ctx context.Context, arg CreateTicketParams) (Ticket, error) {
row := q.db.QueryRow(ctx, CreateTicket, arg.Amount, arg.TotalOdds, arg.Ip)
row := q.db.QueryRow(ctx, CreateTicket,
arg.Amount,
arg.TotalOdds,
arg.Ip,
arg.CompanyID,
)
var i Ticket
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.Amount,
&i.TotalOdds,
&i.Ip,
@ -96,12 +103,16 @@ func (q *Queries) DeleteTicketOutcome(ctx context.Context, ticketID int64) error
}
const GetAllTickets = `-- name: GetAllTickets :many
SELECT id, amount, total_odds, ip, created_at, updated_at, outcomes
SELECT id, company_id, amount, total_odds, ip, created_at, updated_at, outcomes
FROM ticket_with_outcomes
WHERE (
company_id = $1
OR $1 IS NULL
)
`
func (q *Queries) GetAllTickets(ctx context.Context) ([]TicketWithOutcome, error) {
rows, err := q.db.Query(ctx, GetAllTickets)
func (q *Queries) GetAllTickets(ctx context.Context, companyID pgtype.Int8) ([]TicketWithOutcome, error) {
rows, err := q.db.Query(ctx, GetAllTickets, companyID)
if err != nil {
return nil, err
}
@ -111,6 +122,7 @@ func (q *Queries) GetAllTickets(ctx context.Context) ([]TicketWithOutcome, error
var i TicketWithOutcome
if err := rows.Scan(
&i.ID,
&i.CompanyID,
&i.Amount,
&i.TotalOdds,
&i.Ip,
@ -129,7 +141,8 @@ func (q *Queries) GetAllTickets(ctx context.Context) ([]TicketWithOutcome, error
}
const GetAllTicketsInRange = `-- name: GetAllTicketsInRange :one
SELECT COUNT(*) as total_tickets, COALESCE(SUM(amount), 0) as total_amount
SELECT COUNT(*) as total_tickets,
COALESCE(SUM(amount), 0) as total_amount
FROM tickets
WHERE created_at BETWEEN $1 AND $2
`
@ -152,7 +165,7 @@ func (q *Queries) GetAllTicketsInRange(ctx context.Context, arg GetAllTicketsInR
}
const GetTicketByID = `-- name: GetTicketByID :one
SELECT id, amount, total_odds, ip, created_at, updated_at, outcomes
SELECT id, company_id, amount, total_odds, ip, created_at, updated_at, outcomes
FROM ticket_with_outcomes
WHERE id = $1
`
@ -162,6 +175,7 @@ func (q *Queries) GetTicketByID(ctx context.Context, id int64) (TicketWithOutcom
var i TicketWithOutcome
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.Amount,
&i.TotalOdds,
&i.Ip,

View File

@ -17,17 +17,20 @@ SELECT EXISTS (
FROM users
WHERE users.phone_number = $1
AND users.phone_number IS NOT NULL
AND users.company_id = $2
) AS phone_exists,
EXISTS (
SELECT 1
FROM users
WHERE users.email = $2
WHERE users.email = $3
AND users.email IS NOT NULL
AND users.company_id = $2
) AS email_exists
`
type CheckPhoneEmailExistParams struct {
PhoneNumber pgtype.Text `json:"phone_number"`
CompanyID pgtype.Int8 `json:"company_id"`
Email pgtype.Text `json:"email"`
}
@ -37,7 +40,7 @@ type CheckPhoneEmailExistRow struct {
}
func (q *Queries) CheckPhoneEmailExist(ctx context.Context, arg CheckPhoneEmailExistParams) (CheckPhoneEmailExistRow, error) {
row := q.db.QueryRow(ctx, CheckPhoneEmailExist, arg.PhoneNumber, arg.Email)
row := q.db.QueryRow(ctx, CheckPhoneEmailExist, arg.PhoneNumber, arg.CompanyID, arg.Email)
var i CheckPhoneEmailExistRow
err := row.Scan(&i.PhoneExists, &i.EmailExists)
return i, err
@ -339,8 +342,14 @@ SELECT id,
company_id
FROM users
WHERE email = $1
AND company_id = $2
`
type GetUserByEmailParams struct {
Email pgtype.Text `json:"email"`
CompanyID pgtype.Int8 `json:"company_id"`
}
type GetUserByEmailRow struct {
ID int64 `json:"id"`
FirstName string `json:"first_name"`
@ -357,8 +366,8 @@ type GetUserByEmailRow struct {
CompanyID pgtype.Int8 `json:"company_id"`
}
func (q *Queries) GetUserByEmail(ctx context.Context, email pgtype.Text) (GetUserByEmailRow, error) {
row := q.db.QueryRow(ctx, GetUserByEmail, email)
func (q *Queries) GetUserByEmail(ctx context.Context, arg GetUserByEmailParams) (GetUserByEmailRow, error) {
row := q.db.QueryRow(ctx, GetUserByEmail, arg.Email, arg.CompanyID)
var i GetUserByEmailRow
err := row.Scan(
&i.ID,
@ -424,8 +433,14 @@ SELECT id,
company_id
FROM users
WHERE phone_number = $1
AND company_id = $2
`
type GetUserByPhoneParams struct {
PhoneNumber pgtype.Text `json:"phone_number"`
CompanyID pgtype.Int8 `json:"company_id"`
}
type GetUserByPhoneRow struct {
ID int64 `json:"id"`
FirstName string `json:"first_name"`
@ -442,8 +457,8 @@ type GetUserByPhoneRow struct {
CompanyID pgtype.Int8 `json:"company_id"`
}
func (q *Queries) GetUserByPhone(ctx context.Context, phoneNumber pgtype.Text) (GetUserByPhoneRow, error) {
row := q.db.QueryRow(ctx, GetUserByPhone, phoneNumber)
func (q *Queries) GetUserByPhone(ctx context.Context, arg GetUserByPhoneParams) (GetUserByPhoneRow, error) {
row := q.db.QueryRow(ctx, GetUserByPhone, arg.PhoneNumber, arg.CompanyID)
var i GetUserByPhoneRow
err := row.Scan(
&i.ID,
@ -478,25 +493,22 @@ SELECT id,
suspended_at,
company_id
FROM users
WHERE (
first_name ILIKE '%' || $1 || '%'
OR last_name ILIKE '%' || $1 || '%'
OR phone_number LIKE '%' || $1 || '%'
WHERE (company_id = $1)
AND (
first_name ILIKE '%' || $2 || '%'
OR last_name ILIKE '%' || $2 || '%'
OR phone_number LIKE '%' || $2 || '%'
)
AND (
role = $2
OR $2 IS NULL
)
AND (
company_id = $3
role = $3
OR $3 IS NULL
)
`
type SearchUserByNameOrPhoneParams struct {
Column1 pgtype.Text `json:"column_1"`
Role pgtype.Text `json:"role"`
CompanyID pgtype.Int8 `json:"company_id"`
Column2 pgtype.Text `json:"column_2"`
Role pgtype.Text `json:"role"`
}
type SearchUserByNameOrPhoneRow struct {
@ -516,7 +528,7 @@ type SearchUserByNameOrPhoneRow struct {
}
func (q *Queries) SearchUserByNameOrPhone(ctx context.Context, arg SearchUserByNameOrPhoneParams) ([]SearchUserByNameOrPhoneRow, error) {
rows, err := q.db.Query(ctx, SearchUserByNameOrPhone, arg.Column1, arg.Role, arg.CompanyID)
rows, err := q.db.Query(ctx, SearchUserByNameOrPhone, arg.CompanyID, arg.Column2, arg.Role)
if err != nil {
return nil, err
}
@ -575,6 +587,7 @@ SET password = $1,
WHERE (
email = $2
OR phone_number = $3
AND company_id = $4
)
`

View File

@ -50,7 +50,7 @@ INSERT INTO wallets (
type
)
VALUES ($1, $2, $3, $4, $5)
RETURNING id, balance, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
RETURNING id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, bonus_balance, cash_balance
`
type CreateWalletParams struct {
@ -73,6 +73,7 @@ func (q *Queries) CreateWallet(ctx context.Context, arg CreateWalletParams) (Wal
err := row.Scan(
&i.ID,
&i.Balance,
&i.Currency,
&i.IsWithdraw,
&i.IsBettable,
&i.IsTransferable,
@ -81,7 +82,6 @@ func (q *Queries) CreateWallet(ctx context.Context, arg CreateWalletParams) (Wal
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
&i.Currency,
&i.BonusBalance,
&i.CashBalance,
)
@ -188,7 +188,7 @@ func (q *Queries) GetAllCustomerWallet(ctx context.Context) ([]CustomerWalletDet
}
const GetAllWallets = `-- name: GetAllWallets :many
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
SELECT id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, bonus_balance, cash_balance
FROM wallets
`
@ -204,6 +204,7 @@ func (q *Queries) GetAllWallets(ctx context.Context) ([]Wallet, error) {
if err := rows.Scan(
&i.ID,
&i.Balance,
&i.Currency,
&i.IsWithdraw,
&i.IsBettable,
&i.IsTransferable,
@ -212,7 +213,6 @@ func (q *Queries) GetAllWallets(ctx context.Context) ([]Wallet, error) {
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
&i.Currency,
&i.BonusBalance,
&i.CashBalance,
); err != nil {
@ -319,7 +319,7 @@ func (q *Queries) GetCustomerWallet(ctx context.Context, customerID int64) (Cust
}
const GetWalletByID = `-- name: GetWalletByID :one
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
SELECT id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, bonus_balance, cash_balance
FROM wallets
WHERE id = $1
`
@ -330,6 +330,7 @@ func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
err := row.Scan(
&i.ID,
&i.Balance,
&i.Currency,
&i.IsWithdraw,
&i.IsBettable,
&i.IsTransferable,
@ -338,7 +339,6 @@ func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
&i.Currency,
&i.BonusBalance,
&i.CashBalance,
)
@ -346,7 +346,7 @@ func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
}
const GetWalletByUserID = `-- name: GetWalletByUserID :many
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
SELECT id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, bonus_balance, cash_balance
FROM wallets
WHERE user_id = $1
`
@ -363,6 +363,7 @@ func (q *Queries) GetWalletByUserID(ctx context.Context, userID int64) ([]Wallet
if err := rows.Scan(
&i.ID,
&i.Balance,
&i.Currency,
&i.IsWithdraw,
&i.IsBettable,
&i.IsTransferable,
@ -371,7 +372,6 @@ func (q *Queries) GetWalletByUserID(ctx context.Context, userID int64) ([]Wallet
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
&i.Currency,
&i.BonusBalance,
&i.CashBalance,
); err != nil {

View File

@ -2,8 +2,14 @@ package domain
import (
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/jackc/pgx/v5/pgtype"
)
// The Odd ID here is not the odd id from our database
// but the raw_odd_id from the betapi.from within the raw_odds json
// This can be refactor later
type BetOutcome struct {
ID int64 `json:"id" example:"1"`
BetID int64 `json:"bet_id" example:"1"`
@ -46,6 +52,7 @@ type Bet struct {
TotalOdds float32
Status OutcomeStatus
UserID int64
CompanyID int64
IsShopBet bool
CashedOut bool
FastCode string
@ -54,6 +61,7 @@ type Bet struct {
type BetFilter struct {
UserID ValidInt64
CompanyID ValidInt64
CashedOut ValidBool
IsShopBet ValidBool
Query ValidString
@ -78,6 +86,7 @@ type GetBet struct {
FullName string
PhoneNumber string
UserID int64
CompanyID int64
IsShopBet bool
CashedOut bool
Outcomes []BetOutcome
@ -90,6 +99,7 @@ type CreateBet struct {
TotalOdds float32
Status OutcomeStatus
UserID int64
CompanyID int64
IsShopBet bool
OutcomesHash string
FastCode string
@ -130,6 +140,7 @@ type CreateBetRes struct {
TotalOdds float32 `json:"total_odds" example:"4.22"`
Status OutcomeStatus `json:"status" example:"1"`
UserID int64 `json:"user_id" example:"2"`
CompanyID int64 `json:"company_id" example:"1"`
IsShopBet bool `json:"is_shop_bet" example:"false"`
CreatedNumber int64 `json:"created_number" example:"2"`
FastCode string `json:"fast_code"`
@ -142,19 +153,21 @@ type BetRes struct {
Status OutcomeStatus `json:"status" example:"1"`
Fullname string `json:"full_name" example:"John Smith"`
UserID int64 `json:"user_id" example:"2"`
CompanyID int64 `json:"company_id" example:"1"`
IsShopBet bool `json:"is_shop_bet" example:"false"`
CashedOut bool `json:"cashed_out" example:"false"`
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
FastCode string `json:"fast_code"`
}
func ConvertCreateBet(bet Bet, createdNumber int64) CreateBetRes {
func ConvertCreateBetRes(bet Bet, createdNumber int64) CreateBetRes {
return CreateBetRes{
ID: bet.ID,
Amount: bet.Amount.Float32(),
TotalOdds: bet.TotalOdds,
Status: bet.Status,
UserID: bet.UserID,
CompanyID: bet.CompanyID,
CreatedNumber: createdNumber,
IsShopBet: bet.IsShopBet,
FastCode: bet.FastCode,
@ -169,6 +182,7 @@ func ConvertBet(bet GetBet) BetRes {
Status: bet.Status,
Fullname: bet.FullName,
UserID: bet.UserID,
CompanyID: bet.CompanyID,
Outcomes: bet.Outcomes,
IsShopBet: bet.IsShopBet,
CashedOut: bet.CashedOut,
@ -176,3 +190,106 @@ func ConvertBet(bet GetBet) BetRes {
FastCode: bet.FastCode,
}
}
func ConvertDBBet(bet dbgen.Bet) Bet {
return Bet{
ID: bet.ID,
Amount: Currency(bet.Amount),
TotalOdds: bet.TotalOdds,
Status: OutcomeStatus(bet.Status),
UserID: bet.UserID,
CompanyID: bet.CompanyID,
IsShopBet: bet.IsShopBet,
CashedOut: bet.CashedOut,
FastCode: bet.FastCode,
CreatedAt: bet.CreatedAt.Time,
}
}
func ConvertDBBetOutcomes(outcome dbgen.BetOutcome) BetOutcome {
return BetOutcome{
ID: outcome.ID,
BetID: outcome.BetID,
SportID: outcome.SportID,
EventID: outcome.EventID,
OddID: outcome.OddID,
HomeTeamName: outcome.HomeTeamName,
AwayTeamName: outcome.AwayTeamName,
MarketID: outcome.MarketID,
MarketName: outcome.MarketName,
Odd: outcome.Odd,
OddName: outcome.OddName,
OddHeader: outcome.OddHeader,
OddHandicap: outcome.OddHandicap,
Status: OutcomeStatus(outcome.Status),
Expires: outcome.Expires.Time,
}
}
func ConvertDBBetWithOutcomes(bet dbgen.BetWithOutcome) GetBet {
var outcomes []BetOutcome = make([]BetOutcome, 0, len(bet.Outcomes))
for _, outcome := range bet.Outcomes {
outcomes = append(outcomes, ConvertDBBetOutcomes(outcome))
}
return GetBet{
ID: bet.ID,
Amount: Currency(bet.Amount),
TotalOdds: bet.TotalOdds,
Status: OutcomeStatus(bet.Status),
FullName: bet.FullName.(string),
PhoneNumber: bet.PhoneNumber.String,
UserID: bet.UserID,
IsShopBet: bet.IsShopBet,
CashedOut: bet.CashedOut,
Outcomes: outcomes,
FastCode: bet.FastCode,
CreatedAt: bet.CreatedAt.Time,
}
}
func ConvertDBFlag(flag dbgen.Flag) Flag {
return Flag{
ID: flag.ID,
BetID: flag.BetID.Int64,
OddID: flag.OddsMarketID.Int64,
Reason: flag.Reason.String,
FlaggedAt: flag.FlaggedAt.Time,
Resolved: flag.Resolved.Bool,
}
}
func ConvertDBCreateBetOutcome(betOutcome CreateBetOutcome) dbgen.CreateBetOutcomeParams {
return dbgen.CreateBetOutcomeParams{
BetID: betOutcome.BetID,
EventID: betOutcome.EventID,
SportID: betOutcome.SportID,
OddID: betOutcome.OddID,
HomeTeamName: betOutcome.HomeTeamName,
AwayTeamName: betOutcome.AwayTeamName,
MarketID: betOutcome.MarketID,
MarketName: betOutcome.MarketName,
Odd: betOutcome.Odd,
OddName: betOutcome.OddName,
OddHeader: betOutcome.OddHeader,
OddHandicap: betOutcome.OddHandicap,
Expires: pgtype.Timestamp{
Time: betOutcome.Expires,
Valid: true,
},
}
}
func ConvertCreateBet(bet CreateBet) dbgen.CreateBetParams {
return dbgen.CreateBetParams{
Amount: int64(bet.Amount),
TotalOdds: bet.TotalOdds,
Status: int32(bet.Status),
UserID: bet.UserID,
CompanyID: bet.CompanyID,
IsShopBet: bet.IsShopBet,
OutcomesHash: bet.OutcomesHash,
FastCode: bet.FastCode,
}
}

View File

@ -1,68 +1,11 @@
package domain
import (
"encoding/json"
"fmt"
"strconv"
"time"
"go.uber.org/zap"
)
var MongoDBLogger *zap.Logger
type ValidInt64 struct {
Value int64
Valid bool
}
type ValidInt struct {
Value int
Valid bool
}
type ValidInt32 struct {
Value int32
Valid bool
}
type ValidFloat32 struct {
Value float32
Valid bool
}
type ValidString struct {
Value string
Valid bool
}
type ValidTime struct {
Value time.Time
Valid bool
}
type ValidBool struct {
Value bool
Valid bool
}
type Currency int64
// ToCurrency converts a float32 to Currency
func ToCurrency(f float32) Currency {
return Currency((f * 100) + 0.5)
}
// Float32 converts a Currency to float32
func (m Currency) Float32() float32 {
x := float32(m)
x = x / 100
return x
}
// String returns a formatted Currency value
func (m Currency) String() string {
x := float32(m)
x = x / 100
return fmt.Sprintf("$%.2f", x)
}
type ResponseWDataFactory[T any] struct {
Data T `json:"data"`
Response
@ -95,73 +38,3 @@ type Pagination struct {
func PtrFloat64(v float64) *float64 { return &v }
func PtrInt64(v int64) *int64 { return &v }
type Int64JSON int64
// func (i *Int64JSON) Parse() (int64, error) {
// var asString string
// if err := json.Unmarshal(i, &asString); err == nil {
// // Try to parse the string to int64
// return strconv.ParseInt(strings.TrimSpace(asString), 10, 64)
// }
// var asInt int64
// if err := json.Unmarshal(i, &asInt); err == nil {
// return asInt, nil
// }
// // Neither string nor int worked
// return 0, fmt.Errorf("invalid int64 value: %s", string(i))
// }
func (i *Int64JSON) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err == nil {
// it was a string, parse it
v, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return err
}
*i = Int64JSON(v)
return nil
}
var v int64
if err := json.Unmarshal(data, &v); err == nil {
*i = Int64JSON(v)
return nil
}
return fmt.Errorf("invalid int64 value: %s", string(data))
}
type NullableInt64JSON struct {
Int64 int64
Valid bool
}
func (n *NullableInt64JSON) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err == nil {
if s == "" {
n.Valid = false
return nil
}
v, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return err
}
n.Int64, n.Valid = v, true
return nil
}
var v int64
if err := json.Unmarshal(data, &v); err == nil {
n.Int64, n.Valid = v, true
return nil
}
return fmt.Errorf("invalid int64 value: %s", string(data))
}

View File

@ -0,0 +1,34 @@
package domain
import (
"time"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
)
// var BadRequestZapFields = []zap.Field{
// zap.Int("status_code", fiber.StatusBadRequest),
// zap.Time("timestamp", time.Now()),
// }
// var InternalServerErrorZapFields = []zap.Field{
// zap.Int("status_code", fiber.StatusBadRequest),
// zap.Time("timestamp", time.Now()),
// }
var SuccessResZapFields = []zap.Field{
zap.Int("status_code", fiber.StatusBadRequest),
zap.Time("timestamp", time.Now()),
}
// var BadRequestLogger = MongoDBLogger.With(
// zap.Int("status_code", fiber.StatusBadRequest),
// zap.Time("timestamp", time.Now()))
// var InternalServerErrorLogger = MongoDBLogger.With(
// zap.Int("status_code", fiber.StatusInternalServerError),
// zap.Time("timestamp", time.Now()))
// var SuccessResLogger = MongoDBLogger.With(
// zap.Int("status_code", fiber.StatusOK),
// zap.Time("timestamp", time.Now()))

View File

@ -11,6 +11,7 @@ import (
type Company struct {
ID int64
Name string
Slug string
AdminID int64
WalletID int64
DeductedPercentage float32
@ -27,6 +28,7 @@ type CompanyFilter struct {
type GetCompany struct {
ID int64
Name string
Slug string
AdminID int64
AdminFirstName string
AdminLastName string
@ -68,6 +70,7 @@ type UpdateCompanyReq struct {
type CompanyRes struct {
ID int64 `json:"id" example:"1"`
Name string `json:"name" example:"CompanyName"`
Slug string `json:"slug" example:"slug"`
AdminID int64 `json:"admin_id" example:"1"`
WalletID int64 `json:"wallet_id" example:"1"`
DeductedPercentage float32 `json:"deducted_percentage" example:"0.1"`
@ -77,6 +80,7 @@ type CompanyRes struct {
type GetCompanyRes struct {
ID int64 `json:"id" example:"1"`
Name string `json:"name" example:"CompanyName"`
Slug string `json:"slug" example:"slug"`
AdminID int64 `json:"admin_id" example:"1"`
WalletID int64 `json:"wallet_id" example:"1"`
WalletBalance float32 `json:"balance" example:"1"`
@ -89,20 +93,14 @@ type GetCompanyRes struct {
}
func ConvertCompany(company Company) CompanyRes {
return CompanyRes{
ID: company.ID,
Name: company.Name,
AdminID: company.AdminID,
WalletID: company.WalletID,
IsActive: company.IsActive,
DeductedPercentage: company.DeductedPercentage,
}
return CompanyRes(company)
}
func ConvertGetCompany(company GetCompany) GetCompanyRes {
return GetCompanyRes{
ID: company.ID,
Name: company.Name,
Slug: company.Slug,
AdminID: company.AdminID,
WalletID: company.WalletID,
WalletBalance: company.WalletBalance.Float32(),
@ -112,13 +110,13 @@ func ConvertGetCompany(company GetCompany) GetCompanyRes {
AdminFirstName: company.AdminFirstName,
AdminLastName: company.AdminLastName,
AdminPhoneNumber: company.AdminPhoneNumber,
}
}
func ConvertCreateCompany(company CreateCompany) dbgen.CreateCompanyParams {
func ConvertCreateCompany(company CreateCompany, uniqueSlug string) dbgen.CreateCompanyParams {
return dbgen.CreateCompanyParams{
Name: company.Name,
Slug: uniqueSlug,
AdminID: company.AdminID,
WalletID: company.WalletID,
DeductedPercentage: company.DeductedPercentage,
@ -129,6 +127,7 @@ func ConvertDBCompany(dbCompany dbgen.Company) Company {
return Company{
ID: dbCompany.ID,
Name: dbCompany.Name,
Slug: dbCompany.Slug,
AdminID: dbCompany.AdminID,
WalletID: dbCompany.WalletID,
DeductedPercentage: dbCompany.DeductedPercentage,
@ -140,6 +139,7 @@ func ConvertDBCompanyDetails(dbCompany dbgen.CompaniesDetail) GetCompany {
return GetCompany{
ID: dbCompany.ID,
Name: dbCompany.Name,
Slug: dbCompany.Slug,
AdminID: dbCompany.AdminID,
WalletID: dbCompany.WalletID,
WalletBalance: Currency(dbCompany.Balance),

View File

@ -3,9 +3,28 @@ package domain
import (
"errors"
"fmt"
"math"
"time"
)
type Currency int64
// ToCurrency converts a float32 (like 12.34) into Currency (stored in cents).
func ToCurrency(f float32) Currency {
cents := math.Round(float64(f) * 100) // avoid float32 precision issues
return Currency(int64(cents))
}
// Float32 converts a Currency back into float32 (like 12.34).
func (m Currency) Float32() float32 {
return float32(m) / 100
}
// String returns a formatted Currency value for display.
func (m Currency) String() string {
return fmt.Sprintf("$%.2f", m.Float32())
}
type IntCurrency string
const (

View File

@ -0,0 +1,69 @@
package domain
// import (
// "encoding/json"
// "time"
// dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
// )
// type CustomOdd struct {
// ID int64
// OddID int64
// CompanyID int64
// EventID string
// RawOdds []json.RawMessage
// CreatedAt time.Time
// }
// type CreateCustomOdd struct {
// OddID int64
// CompanyID int64
// EventID string
// RawOdds []json.RawMessage
// }
// type CustomOddFilter struct {
// CompanyID ValidInt64
// }
// func ConvertCreateCustomOdd(odd CreateCustomOdd) (dbgen.InsertCustomOddParams, error) {
// rawOddsBytes, err := json.Marshal(odd.RawOdds)
// if err != nil {
// return dbgen.InsertCustomOddParams{}, err
// }
// return dbgen.InsertCustomOddParams{
// OddID: odd.OddID,
// CompanyID: odd.CompanyID,
// EventID: odd.EventID,
// RawOdds: rawOddsBytes,
// }, nil
// }
// func ConvertDBCustomOdd(dbCustomOdd dbgen.CustomOdd) (CustomOdd, error) {
// var rawOdds []json.RawMessage
// if err := json.Unmarshal(dbCustomOdd.RawOdds, &rawOdds); err != nil {
// return CustomOdd{}, err
// }
// return CustomOdd{
// ID: dbCustomOdd.ID,
// OddID: dbCustomOdd.OddID,
// CompanyID: dbCustomOdd.CompanyID,
// EventID: dbCustomOdd.EventID,
// RawOdds: rawOdds,
// CreatedAt: dbCustomOdd.CreatedAt.Time,
// }, nil
// }
// func ConvertDbCustomOdds(list []dbgen.CustomOdd) ([]CustomOdd, error) {
// result := make([]CustomOdd, 0, len(list))
// for _, item := range list {
// convertedItem, err := ConvertDBCustomOdd(item)
// if err != nil {
// return nil, err
// }
// result = append(result, convertedItem)
// }
// return result, nil
// }

View File

@ -0,0 +1,51 @@
package domain
import (
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
)
type DisabledOdd struct {
ID int64
OddMarketID int64
RawOddID int64
EventID string
CompanyID int64
CreatedAt time.Time
}
type CreateDisabledOdd struct {
OddMarketID int64
RawOddID int64
EventID string
CompanyID int64
}
func ConvertCreateDisabledOdd(odd CreateDisabledOdd) dbgen.InsertDisabledOddsParams {
return dbgen.InsertDisabledOddsParams{
OddsMarketID: odd.OddMarketID,
EventID: odd.EventID,
CompanyID: odd.CompanyID,
RawOddID: odd.RawOddID,
}
}
func ConvertDBDisabledOdd(dbDisabledOdd dbgen.DisabledOdd) DisabledOdd {
return DisabledOdd{
ID: dbDisabledOdd.ID,
OddMarketID: dbDisabledOdd.OddsMarketID,
RawOddID: dbDisabledOdd.RawOddID,
EventID: dbDisabledOdd.EventID,
CompanyID: dbDisabledOdd.CompanyID,
CreatedAt: dbDisabledOdd.CreatedAt.Time,
}
}
func ConvertDisabledOdds(list []dbgen.DisabledOdd) []DisabledOdd {
result := make([]DisabledOdd, 0, len(list))
for _, item := range list {
result = append(result, ConvertDBDisabledOdd(item))
}
return result
}

View File

@ -1,6 +1,11 @@
package domain
import "time"
import (
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/jackc/pgx/v5/pgtype"
)
// TODO: turn status into an enum
// Status represents the status of an event.
@ -35,100 +40,408 @@ const (
STATUS_REMOVED EventStatus = "removed"
)
type Event struct {
ID string
SportID int32
MatchName string
HomeTeam string
AwayTeam string
HomeTeamID int32
AwayTeamID int32
HomeKitImage string
AwayKitImage string
LeagueID int32
LeagueName string
LeagueCC string
StartTime string
Score string
MatchMinute int
TimerStatus string
AddedTime int
MatchPeriod int
IsLive bool
Status string
Source string
type EventSource string
const (
EVENT_SOURCE_BET365 EventSource = "b365api"
EVENT_SOURCE_BWIN EventSource = "bwin"
EVENT_SOURCE_BETFAIR EventSource = "bfair"
EVENT_SOURCE_1XBET EventSource = "1xbet"
EVENT_SOURCE_ENET EventSource = "enetpulse"
)
type BaseEvent struct {
ID string
SportID int32
MatchName string
HomeTeam string
AwayTeam string
HomeTeamID int64
AwayTeamID int64
HomeTeamImage string
AwayTeamImage string
LeagueID int64
LeagueName string
LeagueCC ValidString
StartTime time.Time
Source EventSource
Status EventStatus
IsMonitored bool
DefaultIsFeatured bool
DefaultIsActive bool
DefaultWinningUpperLimit int32
Score ValidString
MatchMinute ValidInt
TimerStatus ValidString
AddedTime ValidInt
MatchPeriod ValidInt
IsLive bool
FetchedAt time.Time
}
type BaseEventRes struct {
ID string `json:"id"`
SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"`
HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int64 `json:"away_team_id"`
HomeTeamImage string `json:"home_team_image"`
AwayTeamImage string `json:"away_team_image"`
LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"`
LeagueCC string `json:"league_cc"`
StartTime time.Time `json:"start_time"`
Source EventSource `json:"source"`
Status EventStatus `json:"status"`
IsMonitored bool `json:"is_monitored"`
DefaultIsFeatured bool `json:"default_is_featured"`
DefaultIsActive bool `json:"default_is_active"`
DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"`
Score string `json:"score,omitempty"`
MatchMinute int `json:"match_minute,omitempty"`
TimerStatus string `json:"timer_status,omitempty"`
AddedTime int `json:"added_time,omitempty"`
MatchPeriod int `json:"match_period,omitempty"`
IsLive bool `json:"is_live"`
FetchedAt time.Time `json:"fetched_at"`
}
type EventWithSettings struct {
ID string
SportID int32
MatchName string
HomeTeam string
AwayTeam string
HomeTeamID int64
AwayTeamID int64
HomeTeamImage string
AwayTeamImage string
LeagueID int64
LeagueName string
LeagueCC ValidString
StartTime time.Time
Source EventSource
Status EventStatus
IsFeatured bool
IsMonitored bool
IsActive bool
WinningUpperLimit int32
Score ValidString
MatchMinute ValidInt
TimerStatus ValidString
AddedTime ValidInt
MatchPeriod ValidInt
IsLive bool
UpdatedAt time.Time
FetchedAt time.Time
}
type BetResult struct {
Success int `json:"success"`
Pager struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
Total int `json:"total"`
}
Results []struct {
ID string `json:"id"`
SportID string `json:"sport_id"`
Time string `json:"time"`
League struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"league"`
Home struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"home"`
Away *struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"away"`
} `json:"results"`
type CreateEvent struct {
ID string
SportID int32
MatchName string
HomeTeam string
AwayTeam string
HomeTeamID int64
AwayTeamID int64
HomeTeamImage string
AwayTeamImage string
LeagueID int64
LeagueName string
StartTime time.Time
IsLive bool
Status EventStatus
Source EventSource
}
type UpcomingEvent struct {
ID string `json:"id"` // Event ID
SportID int32 `json:"sport_id"` // Sport ID
MatchName string `json:"match_name"` // Match or event name
HomeTeam string `json:"home_team"` // Home team name (if available)
AwayTeam string `json:"away_team"` // Away team name (can be empty/null)
HomeTeamID int32 `json:"home_team_id"` // Home team ID
AwayTeamID int32 `json:"away_team_id"` // Away team ID (can be empty/null)
HomeKitImage string `json:"home_kit_image"` // Kit or image for home team (optional)
AwayKitImage string `json:"away_kit_image"` // Kit or image for away team (optional)
LeagueID int32 `json:"league_id"` // League ID
LeagueName string `json:"league_name"` // League name
LeagueCC string `json:"league_cc"` // League country code
StartTime time.Time `json:"start_time"` // Converted from "time" field in UNIX format
Source string `json:"source"` // bet api provider (bet365, betfair)
Status EventStatus `json:"status"` //Match Status for event
IsFeatured bool `json:"is_featured"` //Whether the event is featured or not
IsActive bool `json:"is_active"` //Whether the event is featured or not
}
type MatchResult struct {
EventID string
FullScore string
HalfScore string
Status string
Scores map[string]map[string]string
type EventWithSettingsRes struct {
ID string `json:"id"`
SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"`
HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int64 `json:"away_team_id"`
HomeTeamImage string `json:"home_team_image"`
AwayTeamImage string `json:"away_team_image"`
LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"`
LeagueCC string `json:"league_cc"`
StartTime time.Time `json:"start_time"`
Source EventSource `json:"source"`
Status EventStatus `json:"status"`
IsFeatured bool `json:"is_featured"`
IsMonitored bool `json:"is_monitored"`
IsActive bool `json:"is_active"`
WinningUpperLimit int32 `json:"winning_upper_limit"`
Score string `json:"score,omitempty"`
MatchMinute int `json:"match_minute,omitempty"`
TimerStatus string `json:"timer_status,omitempty"`
AddedTime int `json:"added_time,omitempty"`
MatchPeriod int `json:"match_period,omitempty"`
IsLive bool `json:"is_live"`
UpdatedAt time.Time `json:"updated_at"`
FetchedAt time.Time `json:"fetched_at"`
}
type Odds struct {
ID int64 `json:"id"`
EventID string `json:"event_id"`
MarketType string `json:"market_type"`
Name string `json:"name"`
HitStatus string `json:"hit_status"`
type EventSettings struct {
CompanyID int64
EventID string
IsActive ValidBool
IsFeatured ValidBool
WinningUpperLimit ValidInt
UpdatedAt time.Time
}
type CreateEventSettings struct {
CompanyID int64
EventID string
IsActive ValidBool
IsFeatured ValidBool
WinningUpperLimit ValidInt
}
type EventFilter struct {
Query ValidString
SportID ValidInt32
LeagueID ValidInt32
LeagueID ValidInt64
CountryCode ValidString
FirstStartTime ValidTime
LastStartTime ValidTime
Limit ValidInt64
Offset ValidInt64
Limit ValidInt32
Offset ValidInt32
MatchStatus ValidString // e.g., "upcoming", "in_play", "ended"
Featured ValidBool
}
func ConvertDBEvent(event dbgen.EventWithCountry) BaseEvent {
return BaseEvent{
ID: event.ID,
SportID: event.SportID,
MatchName: event.MatchName,
HomeTeam: event.HomeTeam,
AwayTeam: event.AwayTeam,
HomeTeamID: event.HomeTeamID,
AwayTeamID: event.AwayTeamID,
HomeTeamImage: event.HomeKitImage,
AwayTeamImage: event.AwayKitImage,
LeagueID: event.LeagueID,
LeagueName: event.LeagueName,
LeagueCC: ValidString{
Value: event.LeagueCc.String,
Valid: event.LeagueCc.Valid,
},
StartTime: event.StartTime.Time.UTC(),
Source: EventSource(event.Source),
Status: EventStatus(event.Status),
DefaultIsFeatured: event.DefaultIsFeatured,
IsMonitored: event.IsMonitored,
DefaultIsActive: event.DefaultIsActive,
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
Score: ValidString{
Value: event.Score.String,
Valid: event.Score.Valid,
},
MatchMinute: ValidInt{
Value: int(event.MatchMinute.Int32),
Valid: event.MatchMinute.Valid,
},
TimerStatus: ValidString{
Value: event.TimerStatus.String,
Valid: event.TimerStatus.Valid,
},
AddedTime: ValidInt{
Value: int(event.AddedTime.Int32),
Valid: event.AddedTime.Valid,
},
MatchPeriod: ValidInt{
Value: int(event.MatchPeriod.Int32),
Valid: event.MatchPeriod.Valid,
},
IsLive: event.IsLive,
FetchedAt: event.FetchedAt.Time,
}
}
func ConvertDBEvents(events []dbgen.EventWithCountry) []BaseEvent {
result := make([]BaseEvent, len(events))
for i, e := range events {
result[i] = ConvertDBEvent(e)
}
return result
}
func ConvertCreateEvent(e CreateEvent) dbgen.InsertEventParams {
return dbgen.InsertEventParams{
ID: e.ID,
SportID: e.SportID,
MatchName: e.MatchName,
HomeTeam: e.HomeTeam,
AwayTeam: e.AwayTeam,
HomeTeamID: e.HomeTeamID,
AwayTeamID: e.AwayTeamID,
HomeKitImage: e.HomeTeamImage,
AwayKitImage: e.AwayTeamImage,
LeagueID: e.LeagueID,
LeagueName: e.LeagueName,
StartTime: pgtype.Timestamp{Time: e.StartTime, Valid: true},
IsLive: e.IsLive,
Status: string(e.Status),
Source: string(e.Source),
}
}
func ConvertCreateEventSettings(eventSettings CreateEventSettings) dbgen.InsertEventSettingsParams {
return dbgen.InsertEventSettingsParams{
CompanyID: eventSettings.CompanyID,
EventID: eventSettings.EventID,
IsActive: eventSettings.IsActive.ToPG(),
IsFeatured: eventSettings.IsFeatured.ToPG(),
WinningUpperLimit: eventSettings.WinningUpperLimit.ToPG(),
}
}
func ConvertDBEventWithSetting(event dbgen.EventWithSetting) EventWithSettings {
return EventWithSettings{
ID: event.ID,
SportID: event.SportID,
MatchName: event.MatchName,
HomeTeam: event.HomeTeam,
AwayTeam: event.AwayTeam,
HomeTeamID: event.HomeTeamID,
AwayTeamID: event.AwayTeamID,
HomeTeamImage: event.HomeKitImage,
AwayTeamImage: event.AwayKitImage,
LeagueID: event.LeagueID,
LeagueName: event.LeagueName,
LeagueCC: ValidString{
Value: event.LeagueCc.String,
Valid: event.LeagueCc.Valid,
},
StartTime: event.StartTime.Time.UTC(),
Source: EventSource(event.Source),
Status: EventStatus(event.Status),
IsFeatured: event.IsFeatured,
IsMonitored: event.IsMonitored,
IsActive: event.IsActive,
WinningUpperLimit: event.WinningUpperLimit,
Score: ValidString{
Value: event.Score.String,
Valid: event.Score.Valid,
},
MatchMinute: ValidInt{
Value: int(event.MatchMinute.Int32),
Valid: event.MatchMinute.Valid,
},
TimerStatus: ValidString{
Value: event.TimerStatus.String,
Valid: event.TimerStatus.Valid,
},
AddedTime: ValidInt{
Value: int(event.AddedTime.Int32),
Valid: event.AddedTime.Valid,
},
MatchPeriod: ValidInt{
Value: int(event.MatchPeriod.Int32),
Valid: event.MatchPeriod.Valid,
},
IsLive: event.IsLive,
UpdatedAt: event.UpdatedAt.Time,
FetchedAt: event.FetchedAt.Time,
}
}
func ConvertDBEventWithSettings(events []dbgen.EventWithSetting) []EventWithSettings {
result := make([]EventWithSettings, len(events))
for i, e := range events {
result[i] = ConvertDBEventWithSetting(e)
}
return result
}
func ConvertUpdateEventSettings(event CreateEventSettings) dbgen.UpdateEventSettingsParams {
return dbgen.UpdateEventSettingsParams{
EventID: event.EventID,
CompanyID: event.CompanyID,
IsActive: event.IsActive.ToPG(),
IsFeatured: event.IsFeatured.ToPG(),
WinningUpperLimit: event.WinningUpperLimit.ToPG(),
}
}
func ConvertEventRes(event BaseEvent) BaseEventRes {
return BaseEventRes{
ID: event.ID,
SportID: event.SportID,
MatchName: event.MatchName,
HomeTeam: event.HomeTeam,
AwayTeam: event.AwayTeam,
HomeTeamID: event.HomeTeamID,
AwayTeamID: event.AwayTeamID,
HomeTeamImage: event.HomeTeamImage,
AwayTeamImage: event.AwayTeamImage,
LeagueID: event.LeagueID,
LeagueName: event.LeagueName,
LeagueCC: event.LeagueCC.Value,
StartTime: event.StartTime.UTC(),
Source: EventSource(event.Source),
Status: EventStatus(event.Status),
DefaultIsFeatured: event.DefaultIsFeatured,
IsMonitored: event.IsMonitored,
DefaultIsActive: event.DefaultIsActive,
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
Score: event.Score.Value,
MatchMinute: event.MatchMinute.Value,
TimerStatus: event.TimerStatus.Value,
AddedTime: event.AddedTime.Value,
MatchPeriod: event.MatchPeriod.Value,
IsLive: event.IsLive,
FetchedAt: event.FetchedAt.UTC(),
}
}
func ConvertEventResList(events []BaseEvent) []BaseEventRes {
result := make([]BaseEventRes, 0, len(events))
for _, event := range events {
result = append(result, ConvertEventRes(event))
}
return result
}
func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes {
return EventWithSettingsRes{
ID: event.ID,
SportID: event.SportID,
MatchName: event.MatchName,
HomeTeam: event.HomeTeam,
AwayTeam: event.AwayTeam,
HomeTeamID: event.HomeTeamID,
AwayTeamID: event.AwayTeamID,
HomeTeamImage: event.HomeTeamImage,
AwayTeamImage: event.AwayTeamImage,
LeagueID: event.LeagueID,
LeagueName: event.LeagueName,
LeagueCC: event.LeagueCC.Value,
StartTime: event.StartTime.UTC(),
Source: EventSource(event.Source),
Status: EventStatus(event.Status),
IsFeatured: event.IsFeatured,
IsMonitored: event.IsMonitored,
IsActive: event.IsActive,
WinningUpperLimit: event.WinningUpperLimit,
Score: event.Score.Value,
MatchMinute: event.MatchMinute.Value,
TimerStatus: event.TimerStatus.Value,
AddedTime: event.AddedTime.Value,
MatchPeriod: event.MatchPeriod.Value,
IsLive: event.IsLive,
FetchedAt: event.FetchedAt.UTC(),
}
}
func ConvertEventWithSettingResList(events []EventWithSettings) []EventWithSettingsRes {
result := make([]EventWithSettingsRes, 0, len(events))
for _, event := range events {
result = append(result, ConvertEventWitSettingRes(event))
}
return result
}

View File

@ -0,0 +1,41 @@
package domain
import (
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
)
type EventHistory struct {
ID int64
EventID string
Status string
CreatedAt time.Time
}
type CreateEventHistory struct {
EventID string
Status string
}
type EventHistoryFilter struct {
EventID ValidString
CreatedBefore ValidTime
CreatedAfter ValidTime
}
func ConvertCreateEventHistory(eventHistory CreateEventHistory) dbgen.InsertEventHistoryParams {
return dbgen.InsertEventHistoryParams{
EventID: eventHistory.EventID,
Status: eventHistory.Status,
}
}
func ConvertDBEventHistory(eventHistory dbgen.EventHistory) EventHistory {
return EventHistory{
ID: eventHistory.ID,
EventID: eventHistory.EventID,
Status: eventHistory.Status,
CreatedAt: eventHistory.CreatedAt.Time,
}
}

View File

@ -0,0 +1,35 @@
package domain
type MatchResult struct {
EventID string
FullScore string
HalfScore string
Status string
Scores map[string]map[string]string
}
type B365UpcomingRes struct {
Success int `json:"success"`
Pager struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
Total int `json:"total"`
}
Results []struct {
ID string `json:"id"`
SportID string `json:"sport_id"`
Time string `json:"time"`
League struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"league"`
Home struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"home"`
Away *struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"away"`
} `json:"results"`
}

View File

@ -0,0 +1,63 @@
package domain
// These leagues are automatically featured when the league is created
var FeaturedLeagues = []int64{
// Football
10044469, // Ethiopian Premier League
10041282, //Premier League
10083364, //La Liga
10041095, //German Bundesliga
10041100, //Ligue 1
10041809, //UEFA Champions League
10041957, //UEFA Europa League
10079560, //UEFA Conference League
10050282, //UEFA Nations League
10044685, //FIFA Club World Cup
10050346, //UEFA Super Cup
10081269, //CONCACAF Champions Cup
10070189, //CONCACAF Gold Cup
10076185, //UEFA Regions Cup
10067913, //Europe - World Cup Qualifying
10040162, //Asia - World Cup Qualifying
10067624, //South America - World Cup Qualifying
10073057, //North & Central America - World Cup Qualifying
10037075, //International Match
10077480, //Womens International
10037109, //Europe Friendlies
10068837, //Euro U21
10041315, //Italian Serie A
10036538, //Spain Segunda
10047168, // US MLS
10043156, //England FA Cup
10042103, //France Cup
10041088, //Premier League 2
10084250, //Turkiye Super League
10041187, //Kenya Super League
10041391, //Netherlands Eredivisie
// Basketball
10041830, //NBA
10049984, //WNBA
10037165, //German Bundesliga
10036608, //Italian Lega 1
10040795, //EuroLeague
10041534, //Basketball Africa League
// Ice Hockey
10037477, //NHL
10037447, //AHL
10069385, //IIHF World Championship
// AMERICAN FOOTBALL
10037219, //NFL
// BASEBALL
10037485, // MLB
// VOLLEYBALL
10069666, //FIVB Nations League
}

View File

@ -1,6 +1,24 @@
package domain
type League struct {
import (
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
)
// The ID and the Bet365 IDs we have here are both gotten from the betapi
type LeagueWithSettings struct {
ID int64
Name string
CompanyID int64
CountryCode ValidString
Bet365ID ValidInt32
SportID int32
IsActive bool
IsFeatured bool
UpdatedAt time.Time
}
type LeagueWithSettingsRes struct {
ID int64 `json:"id" example:"1"`
Name string `json:"name" example:"BPL"`
CountryCode string `json:"cc" example:"uk"`
@ -9,6 +27,49 @@ type League struct {
SportID int32 `json:"sport_id" example:"1"`
IsFeatured bool `json:"is_featured" example:"false"`
}
type BaseLeague struct {
ID int64
Name string
CountryCode ValidString
Bet365ID ValidInt32
SportID int32
DefaultIsActive bool
DefaultIsFeatured bool
}
type BaseLeagueRes struct {
ID int64 `json:"id" example:"1"`
Name string `json:"name" example:"BPL"`
CountryCode string `json:"cc" example:"uk"`
Bet365ID int32 `json:"bet365_id" example:"1121"`
SportID int32 `json:"sport_id" example:"1"`
DefaultIsActive bool `json:"default_is_active" example:"false"`
DefaultIsFeatured bool `json:"default_is_featured" example:"false"`
}
type CreateLeague struct {
ID int64
Name string
CountryCode ValidString
Bet365ID ValidInt32
SportID int32
DefaultIsActive bool
DefaultIsFeatured bool
}
type LeagueSettings struct {
CompanyID int64
LeagueID int64
IsActive ValidBool
IsFeatured ValidBool
UpdatedAt time.Time
}
type CreateLeagueSettings struct {
CompanyID int64
LeagueID int64
IsActive ValidBool
IsFeatured ValidBool
}
type UpdateLeague struct {
ID int64 `json:"id" example:"1"`
@ -29,64 +90,87 @@ type LeagueFilter struct {
Offset ValidInt64
}
// These leagues are automatically featured when the league is created
var FeaturedLeagues = []int64{
// Football
10044469, // Ethiopian Premier League
10041282, //Premier League
10083364, //La Liga
10041095, //German Bundesliga
10041100, //Ligue 1
10041809, //UEFA Champions League
10041957, //UEFA Europa League
10079560, //UEFA Conference League
10050282, //UEFA Nations League
10044685, //FIFA Club World Cup
10050346, //UEFA Super Cup
10081269, //CONCACAF Champions Cup
10070189, //CONCACAF Gold Cup
10076185, //UEFA Regions Cup
10067913, //Europe - World Cup Qualifying
10040162, //Asia - World Cup Qualifying
10067624, //South America - World Cup Qualifying
10073057, //North & Central America - World Cup Qualifying
10037075, //International Match
10077480, //Womens International
10037109, //Europe Friendlies
10068837, //Euro U21
10041315, //Italian Serie A
10036538, //Spain Segunda
10047168, // US MLS
10043156, //England FA Cup
10042103, //France Cup
10041088, //Premier League 2
10084250, //Turkiye Super League
10041187, //Kenya Super League
10041391, //Netherlands Eredivisie
// Basketball
10041830, //NBA
10049984, //WNBA
10037165, //German Bundesliga
10036608, //Italian Lega 1
10040795, //EuroLeague
10041534, //Basketball Africa League
// Ice Hockey
10037477, //NHL
10037447, //AHL
10069385, //IIHF World Championship
// AMERICAN FOOTBALL
10037219, //NFL
// BASEBALL
10037485, // MLB
// VOLLEYBALL
10069666, //FIVB Nations League
func ConvertCreateLeague(league CreateLeague) dbgen.InsertLeagueParams {
return dbgen.InsertLeagueParams{
ID: league.ID,
Name: league.Name,
CountryCode: league.CountryCode.ToPG(),
Bet365ID: league.Bet365ID.ToPG(),
SportID: league.SportID,
DefaultIsActive: league.DefaultIsActive,
DefaultIsFeatured: league.DefaultIsFeatured,
}
}
func ConvertCreateLeagueSettings(leagueSetting CreateLeagueSettings) dbgen.InsertLeagueSettingsParams {
return dbgen.InsertLeagueSettingsParams{
CompanyID: leagueSetting.CompanyID,
LeagueID: leagueSetting.LeagueID,
IsActive: leagueSetting.IsActive.ToPG(),
IsFeatured: leagueSetting.IsFeatured.ToPG(),
}
}
func ConvertDBBaseLeague(league dbgen.League) BaseLeague {
return BaseLeague{
ID: league.ID,
Name: league.Name,
CountryCode: ValidString{
Value: league.CountryCode.String,
Valid: league.CountryCode.Valid,
},
Bet365ID: ValidInt32{
Value: league.Bet365ID.Int32,
Valid: league.Bet365ID.Valid,
},
SportID: league.SportID,
DefaultIsActive: league.DefaultIsActive,
DefaultIsFeatured: league.DefaultIsFeatured,
}
}
func ConvertDBBaseLeagues(leagues []dbgen.League) []BaseLeague {
result := make([]BaseLeague, len(leagues))
for i, league := range leagues {
result[i] = ConvertDBBaseLeague(league)
}
return result
}
func ConvertDBLeagueWithSetting(lws dbgen.LeagueWithSetting) LeagueWithSettings {
return LeagueWithSettings{
ID: lws.ID,
Name: lws.Name,
CompanyID: lws.CompanyID,
CountryCode: ValidString{
Value: lws.CountryCode.String,
Valid: lws.CountryCode.Valid,
},
Bet365ID: ValidInt32{
Value: lws.Bet365ID.Int32,
Valid: lws.Bet365ID.Valid,
},
IsActive: lws.IsActive,
SportID: lws.SportID,
IsFeatured: lws.IsFeatured,
UpdatedAt: lws.UpdatedAt.Time,
}
}
func ConvertDBLeagueWithSettings(lws []dbgen.LeagueWithSetting) []LeagueWithSettings {
result := make([]LeagueWithSettings, len(lws))
for i, league := range lws {
result[i] = ConvertDBLeagueWithSetting(league)
}
return result
}
func ConvertUpdateLeague(updateLeague UpdateLeague) dbgen.UpdateLeagueParams {
return dbgen.UpdateLeagueParams{
ID: updateLeague.ID,
Name: updateLeague.Name.ToPG(),
CountryCode: updateLeague.CountryCode.ToPG(),
Bet365ID: updateLeague.Bet365ID.ToPG(),
SportID: updateLeague.SportID.ToPG(),
}
}

View File

@ -27,7 +27,7 @@ type RawOdd struct {
// The Market ID for the json data can be either string / int which is causing problems when UnMarshalling
type OddsMarket struct {
ID NullableInt64JSON `json:"id"`
ID ValidInt64 `json:"id"`
Name string `json:"name"`
Odds []json.RawMessage `json:"odds"`
Header string `json:"header,omitempty"`

View File

@ -1,49 +1,186 @@
package domain
import (
"encoding/json"
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/jackc/pgx/v5/pgtype"
)
type RawMessage interface{}
type Market struct {
type CreateOddMarket struct {
EventID string
FI string
MarketCategory string
MarketType string
MarketName string
MarketID string
UpdatedAt time.Time
Odds []map[string]interface{}
Name string
Handicap string
OddsVal float64
Source string
}
type Odd struct {
EventID string `json:"event_id"`
Fi string `json:"fi"`
MarketType string `json:"market_type"`
MarketName string `json:"market_name"`
MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"`
Name string `json:"name"`
Handicap string `json:"handicap"`
OddsValue float64 `json:"odds_value"`
Section string `json:"section"`
Category string `json:"category"`
RawOdds []RawMessage `json:"raw_odds"`
FetchedAt time.Time `json:"fetched_at"`
Source string `json:"source"`
IsActive bool `json:"is_active"`
type OddMarket struct {
ID int64 `json:"id"`
EventID string `json:"event_id"`
MarketType string `json:"market_type"`
MarketName string `json:"market_name"`
MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"`
RawOdds []json.RawMessage `json:"raw_odds"`
FetchedAt time.Time `json:"fetched_at"`
ExpiresAt time.Time `json:"expires_at"`
DefaultIsActive bool `json:"is_active"`
IsMonitored bool `json:"is_monitored"`
IsLive bool `json:"is_live"`
Status EventStatus `json:"status"`
Source EventSource `json:"source"`
}
type RawOddsByMarketID struct {
ID int64 `json:"id"`
MarketName string `json:"market_name"`
Handicap string `json:"handicap"`
RawOdds []RawMessage `json:"raw_odds"`
FetchedAt time.Time `json:"fetched_at"`
type OddMarketWithSettings struct {
ID int64 `json:"id"`
EventID string `json:"event_id"`
MarketType string `json:"market_type"`
MarketName string `json:"market_name"`
MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"`
RawOdds []json.RawMessage `json:"raw_odds"`
FetchedAt time.Time `json:"fetched_at"`
ExpiresAt time.Time `json:"expires_at"`
IsActive bool `json:"is_active"`
}
type OddMarketSettings struct {
CompanyID int64
OddMarketID int64
IsActive ValidBool
CustomRawOdds string
UpdatedAt time.Time
}
type CreateOddMarketSettings struct {
CompanyID int64
OddMarketID int64
IsActive ValidBool
CustomRawOdds []map[string]interface{}
}
// type RawOddsByMarketID struct {
// ID int64 `json:"id"`
// MarketName string `json:"market_name"`
// Handicap string `json:"handicap"`
// RawOdds []json.RawMessage `json:"raw_odds"`
// FetchedAt time.Time `json:"fetched_at"`
// ExpiresAt time.Time `json:"expires_at"`
// }
type OddMarketFilter struct {
Limit ValidInt32
Offset ValidInt32
}
type OddMarketWithEventFilter struct {
Limit ValidInt32
Offset ValidInt32
}
func ConvertDBOddMarket(oddMarket dbgen.OddsMarketWithEvent) (OddMarket, error) {
var rawOdds []json.RawMessage
if len(oddMarket.RawOdds) > 0 {
if err := json.Unmarshal(oddMarket.RawOdds, &rawOdds); err != nil {
return OddMarket{}, err
}
} else {
rawOdds = []json.RawMessage{} // explicit empty slice
}
return OddMarket{
ID: oddMarket.ID,
EventID: oddMarket.EventID,
MarketType: oddMarket.MarketType,
MarketName: oddMarket.MarketName,
MarketCategory: oddMarket.MarketCategory,
MarketID: oddMarket.MarketID,
RawOdds: rawOdds,
FetchedAt: oddMarket.FetchedAt.Time,
ExpiresAt: oddMarket.ExpiresAt.Time,
DefaultIsActive: oddMarket.DefaultIsActive,
IsMonitored: oddMarket.IsMonitored,
IsLive: oddMarket.IsLive,
Status: EventStatus(oddMarket.Status),
Source: EventSource(oddMarket.Source),
}, nil
}
func ConvertDBOddMarkets(oddMarkets []dbgen.OddsMarketWithEvent) ([]OddMarket, error) {
result := make([]OddMarket, len(oddMarkets))
for i, om := range oddMarkets {
convertedMarket, err := ConvertDBOddMarket(om)
if err != nil {
return nil, err
}
result[i] = convertedMarket
}
return result, nil
}
func ConvertCreateOddMarket(oddMarket CreateOddMarket) (dbgen.InsertOddsMarketParams, error) {
rawOddsBytes, err := json.Marshal(oddMarket.Odds)
if err != nil {
return dbgen.InsertOddsMarketParams{}, err
}
return dbgen.InsertOddsMarketParams{
EventID: oddMarket.EventID,
MarketType: oddMarket.MarketType,
MarketName: oddMarket.MarketName,
MarketCategory: oddMarket.MarketCategory,
MarketID: oddMarket.MarketID,
RawOdds: rawOddsBytes,
FetchedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
ExpiresAt: pgtype.Timestamp{Time: (time.Now()).Add(time.Hour), Valid: true},
}, nil
}
func ConvertCreateOddMarketSetting(oms CreateOddMarketSettings) (dbgen.InsertOddSettingsParams, error) {
rawOddsBytes, err := json.Marshal(oms.CustomRawOdds)
if err != nil {
return dbgen.InsertOddSettingsParams{}, err
}
return dbgen.InsertOddSettingsParams{
CompanyID: oms.CompanyID,
OddsMarketID: oms.OddMarketID,
IsActive: oms.IsActive.ToPG(),
CustomRawOdds: rawOddsBytes,
}, nil
}
func ConvertDBOddMarketWithSetting(oms dbgen.OddsMarketWithSetting) (OddMarketWithSettings, error) {
var rawOdds []json.RawMessage
if len(oms.RawOdds) > 0 {
if err := json.Unmarshal(oms.RawOdds, &rawOdds); err != nil {
return OddMarketWithSettings{}, err
}
} else {
rawOdds = []json.RawMessage{} // explicit empty slice
}
return OddMarketWithSettings{
ID: oms.ID,
EventID: oms.EventID,
MarketType: oms.MarketType,
MarketName: oms.MarketName,
MarketCategory: oms.MarketCategory,
MarketID: oms.MarketID,
RawOdds: rawOdds,
FetchedAt: oms.FetchedAt.Time,
ExpiresAt: oms.ExpiresAt.Time,
IsActive: oms.IsActive,
}, nil
}
func ConvertDBOddMarketWithSettings(oms []dbgen.OddsMarketWithSetting) ([]OddMarketWithSettings, error) {
result := make([]OddMarketWithSettings, len(oms))
for i, o := range oms {
converted, err := ConvertDBOddMarketWithSetting(o)
if err != nil {
return nil, err
}
result[i] = converted
}
return result, nil
}

View File

@ -0,0 +1,64 @@
package domain
import (
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
)
type OddHistory struct {
ID int64
OddID int64
MarketID string
RawOddID int64
EventID string
OddValue float64
CreatedAt time.Time
}
type CreateOddHistory struct {
OddID int64
MarketID string
RawOddID int64
EventID string
OddValue float64
}
type OddHistoryFilter struct {
OddID ValidInt64
MarketID ValidString
RawOddID ValidInt64
EventID ValidString
CreatedBefore ValidTime
CreatedAfter ValidTime
}
func ConvertCreateOddHistory(odd CreateOddHistory) dbgen.InsertOddHistoryParams {
return dbgen.InsertOddHistoryParams{
OddsMarketID: odd.OddID,
MarketID: odd.MarketID,
RawOddID: odd.RawOddID,
EventID: odd.EventID,
OddValue: odd.OddValue,
}
}
func ConvertDBOddHistory(dbOddHistory dbgen.OddHistory) OddHistory {
return OddHistory{
ID: dbOddHistory.ID,
OddID: dbOddHistory.OddsMarketID,
MarketID: dbOddHistory.MarketID,
RawOddID: dbOddHistory.RawOddID,
EventID: dbOddHistory.EventID,
OddValue: dbOddHistory.OddValue,
CreatedAt: dbOddHistory.CreatedAt.Time,
}
}
func ConvertOddHistories(list []dbgen.OddHistory) []OddHistory {
result := make([]OddHistory, 0, len(list))
for _, item := range list {
result = append(result, ConvertDBOddHistory(item))
}
return result
}

View File

@ -2,6 +2,8 @@ package domain
import (
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
)
type MarketConfig struct {
@ -21,7 +23,7 @@ type Result struct {
FullTimeScore string
HalfTimeScore string
SS string
Scores map[string]Score
Scores map[string]ScoreResultResponse
CreatedAt time.Time
UpdatedAt time.Time
}
@ -83,22 +85,78 @@ const (
TIME_STATUS_REMOVED TimeStatus = 99
)
type ResultStatusCounts struct {
IsNotFinished int `json:"is_not_finished"`
IsNotFinishedBets int `json:"is_not_finished_bets"`
IsToBeFixed int `json:"is_to_be_fixed"`
IsToBeFixedBets int `json:"is_to_be_fixed_bets"`
IsPostponed int `json:"is_postponed"`
IsPostponedBets int `json:"is_postponed_bets"`
IsEnded int `json:"is_ended"`
IsEndedBets int `json:"is_ended_bets"`
IsRemoved int `json:"is_removed"`
IsRemovedBets int `json:"is_removed_bets"`
type ResultLog struct {
ID int64 `json:"id"`
StatusNotFinishedCount int `json:"status_not_finished_count"`
StatusNotFinishedBets int `json:"status_not_finished_bets"`
StatusToBeFixedCount int `json:"status_to_be_fixed_count"`
StatusToBeFixedBets int `json:"status_to_be_fixed_bets"`
StatusPostponedCount int `json:"status_postponed_count"`
StatusPostponedBets int `json:"status_postponed_bets"`
StatusEndedCount int `json:"status_ended_count"`
StatusEndedBets int `json:"status_ended_bets"`
StatusRemovedCount int `json:"status_removed_count"`
StatusRemovedBets int `json:"status_removed_bets"`
RemovedCount int `json:"removed"`
CreatedAt time.Time `json:"created_at"`
}
type CreateResultLog struct {
StatusNotFinishedCount int `json:"status_not_finished_count"`
StatusNotFinishedBets int `json:"status_not_finished_bets"`
StatusToBeFixedCount int `json:"status_to_be_fixed_count"`
StatusToBeFixedBets int `json:"status_to_be_fixed_bets"`
StatusPostponedCount int `json:"status_postponed_count"`
StatusPostponedBets int `json:"status_postponed_bets"`
StatusEndedCount int `json:"status_ended_count"`
StatusEndedBets int `json:"status_ended_bets"`
StatusRemovedCount int `json:"status_removed_count"`
StatusRemovedBets int `json:"status_removed_bets"`
RemovedCount int `json:"removed"`
}
type ResultFilter struct {
CreatedBefore ValidTime
CreatedAfter ValidTime
}
type ResultStatusBets struct {
IsNotFinished []int64 `json:"is_not_finished"`
IsToBeFixed []int64 `json:"is_to_be_fixed"`
IsPostponed []int64 `json:"is_postponed"`
IsEnded []int64 `json:"is_ended"`
IsRemoved []int64 `json:"is_removed"`
StatusNotFinished []int64 `json:"status_not_finished"`
StatusToBeFixed []int64 `json:"status_to_be_fixed"`
StatusPostponed []int64 `json:"status_postponed"`
StatusEnded []int64 `json:"status_ended"`
StatusRemoved []int64 `json:"status_removed"`
}
func ConvertDBResultLog(result dbgen.ResultLog) ResultLog {
return ResultLog{
ID: result.ID,
StatusNotFinishedCount: int(result.StatusNotFinishedCount),
StatusNotFinishedBets: int(result.StatusNotFinishedBets),
StatusToBeFixedCount: int(result.StatusToBeFixedCount),
StatusToBeFixedBets: int(result.StatusToBeFixedBets),
StatusPostponedCount: int(result.StatusPostponedCount),
StatusPostponedBets: int(result.StatusPostponedBets),
StatusEndedCount: int(result.StatusEndedCount),
StatusEndedBets: int(result.StatusEndedBets),
StatusRemovedCount: int(result.StatusRemovedCount),
StatusRemovedBets: int(result.StatusRemovedBets),
RemovedCount: int(result.RemovedCount),
CreatedAt: result.CreatedAt.Time,
}
}
func ConvertCreateResultLog(result CreateResultLog) dbgen.CreateResultLogParams {
return dbgen.CreateResultLogParams{
StatusNotFinishedCount: int32(result.StatusNotFinishedCount),
StatusNotFinishedBets: int32(result.StatusNotFinishedBets),
StatusToBeFixedCount: int32(result.StatusToBeFixedCount),
StatusToBeFixedBets: int32(result.StatusToBeFixedBets),
StatusPostponedCount: int32(result.StatusPostponedCount),
StatusPostponedBets: int32(result.StatusPostponedBets),
StatusEndedCount: int32(result.StatusEndedCount),
StatusEndedBets: int32(result.StatusEndedBets),
StatusRemovedCount: int32(result.StatusRemovedCount),
StatusRemovedBets: int32(result.StatusRemovedBets),
RemovedCount: int32(result.RemovedCount),
}
}

View File

@ -9,47 +9,47 @@ type BaseResultResponse struct {
Results []json.RawMessage `json:"results"`
}
type LeagueRes struct {
type LeagueResultResponse struct {
ID string `json:"id"`
Name string `json:"name"`
CC string `json:"cc"`
}
type Team struct {
ID string `json:"id"`
Name string `json:"name"`
ImageID NullableInt64JSON `json:"image_id"`
CC string `json:"cc"`
type TeamResultResponse struct {
ID string `json:"id"`
Name string `json:"name"`
ImageID ValidInt64 `json:"image_id"`
CC string `json:"cc"`
}
type Score struct {
type ScoreResultResponse struct {
Home string `json:"home"`
Away string `json:"away"`
}
type CommonResultResponse struct {
ID string `json:"id"`
SportID string `json:"sport_id"`
Time string `json:"time"`
TimeStatus NullableInt64JSON `json:"time_status"`
League LeagueRes `json:"league"`
Home Team `json:"home"`
Away Team `json:"away"`
SS string `json:"ss"`
ID string `json:"id"`
SportID string `json:"sport_id"`
Time string `json:"time"`
TimeStatus ValidInt64 `json:"time_status"`
League LeagueResultResponse `json:"league"`
Home TeamResultResponse `json:"home"`
Away TeamResultResponse `json:"away"`
SS string `json:"ss"`
}
type FootballResultResponse struct {
ID string `json:"id"`
SportID string `json:"sport_id"`
Time string `json:"time"`
TimeStatus string `json:"time_status"`
League LeagueRes `json:"league"`
Home Team `json:"home"`
Away Team `json:"away"`
SS string `json:"ss"`
ID string `json:"id"`
SportID string `json:"sport_id"`
Time string `json:"time"`
TimeStatus string `json:"time_status"`
League LeagueResultResponse `json:"league"`
Home TeamResultResponse `json:"home"`
Away TeamResultResponse `json:"away"`
SS string `json:"ss"`
Scores struct {
FirstHalf Score `json:"1"`
SecondHalf Score `json:"2"`
FirstHalf ScoreResultResponse `json:"1"`
SecondHalf ScoreResultResponse `json:"2"`
} `json:"scores"`
Stats struct {
Attacks []string `json:"attacks"`
@ -78,21 +78,21 @@ type FootballResultResponse struct {
}
type BasketballResultResponse struct {
ID string `json:"id"`
SportID string `json:"sport_id"`
Time string `json:"time"`
TimeStatus string `json:"time_status"`
League LeagueRes `json:"league"`
Home Team `json:"home"`
Away Team `json:"away"`
SS string `json:"ss"`
ID string `json:"id"`
SportID string `json:"sport_id"`
Time string `json:"time"`
TimeStatus string `json:"time_status"`
League LeagueResultResponse `json:"league"`
Home TeamResultResponse `json:"home"`
Away TeamResultResponse `json:"away"`
SS string `json:"ss"`
Scores struct {
FirstQuarter Score `json:"1"`
SecondQuarter Score `json:"2"`
FirstHalf Score `json:"3"`
ThirdQuarter Score `json:"4"`
FourthQuarter Score `json:"5"`
TotalScore Score `json:"7"`
FirstQuarter ScoreResultResponse `json:"1"`
SecondQuarter ScoreResultResponse `json:"2"`
FirstHalf ScoreResultResponse `json:"3"`
ThirdQuarter ScoreResultResponse `json:"4"`
FourthQuarter ScoreResultResponse `json:"5"`
TotalScore ScoreResultResponse `json:"7"`
} `json:"scores"`
Stats struct {
TwoPoints []string `json:"2points"`
@ -125,19 +125,19 @@ type BasketballResultResponse struct {
Bet365ID string `json:"bet365_id"`
}
type IceHockeyResultResponse struct {
ID string `json:"id"`
SportID string `json:"sport_id"`
Time string `json:"time"`
TimeStatus string `json:"time_status"`
League LeagueRes `json:"league"`
Home Team `json:"home"`
Away Team `json:"away"`
SS string `json:"ss"`
ID string `json:"id"`
SportID string `json:"sport_id"`
Time string `json:"time"`
TimeStatus string `json:"time_status"`
League LeagueResultResponse `json:"league"`
Home TeamResultResponse `json:"home"`
Away TeamResultResponse `json:"away"`
SS string `json:"ss"`
Scores struct {
FirstPeriod Score `json:"1"`
SecondPeriod Score `json:"2"`
ThirdPeriod Score `json:"3"`
TotalScore Score `json:"5"`
FirstPeriod ScoreResultResponse `json:"1"`
SecondPeriod ScoreResultResponse `json:"2"`
ThirdPeriod ScoreResultResponse `json:"3"`
TotalScore ScoreResultResponse `json:"5"`
} `json:"scores"`
Stats struct {
@ -222,11 +222,11 @@ type VolleyballResultResponse struct {
} `json:"away"`
SS string `json:"ss"`
Scores struct {
FirstSet Score `json:"1"`
SecondSet Score `json:"2"`
ThirdSet Score `json:"3"`
FourthSet Score `json:"4"`
FivethSet Score `json:"5"`
FirstSet ScoreResultResponse `json:"1"`
SecondSet ScoreResultResponse `json:"2"`
ThirdSet ScoreResultResponse `json:"3"`
FourthSet ScoreResultResponse `json:"4"`
FivethSet ScoreResultResponse `json:"5"`
} `json:"scores"`
Stats struct {
PointsWonOnServe []string `json:"points_won_on_serve"`
@ -290,10 +290,10 @@ type FutsalResultResponse struct {
} `json:"away"`
SS string `json:"ss"`
Scores struct {
FirstPeriod Score `json:"1"`
SecondPeriod Score `json:"2"`
ThirdPeriod Score `json:"3"`
TotalScore Score `json:"4"`
FirstPeriod ScoreResultResponse `json:"1"`
SecondPeriod ScoreResultResponse `json:"2"`
ThirdPeriod ScoreResultResponse `json:"3"`
TotalScore ScoreResultResponse `json:"4"`
} `json:"scores"`
Events []map[string]string `json:"events"`
InplayCreatedAt string `json:"inplay_created_at"`
@ -327,12 +327,12 @@ type NFLResultResponse struct {
} `json:"away"`
SS string `json:"ss"`
Scores struct {
FirstQuarter Score `json:"1"`
SecondQuarter Score `json:"2"`
ThirdQuarter Score `json:"3"`
FourthQuarter Score `json:"4"`
Overtime Score `json:"5"`
TotalScore Score `json:"7"`
FirstQuarter ScoreResultResponse `json:"1"`
SecondQuarter ScoreResultResponse `json:"2"`
ThirdQuarter ScoreResultResponse `json:"3"`
FourthQuarter ScoreResultResponse `json:"4"`
Overtime ScoreResultResponse `json:"5"`
TotalScore ScoreResultResponse `json:"7"`
} `json:"scores"`
Stats struct {
FirstDowns []string `json:"first_downs"`
@ -381,9 +381,9 @@ type RugbyResultResponse struct {
} `json:"away"`
SS string `json:"ss"`
Scores struct {
FirstHalf Score `json:"1"`
SecondHalf Score `json:"2"`
TotalScore Score `json:"7"`
FirstHalf ScoreResultResponse `json:"1"`
SecondHalf ScoreResultResponse `json:"2"`
TotalScore ScoreResultResponse `json:"7"`
} `json:"scores"`
Stats struct {
Tries []string `json:"tries"`
@ -433,17 +433,17 @@ type BaseballResultResponse struct {
} `json:"away"`
SS string `json:"ss"`
Scores struct {
FirstInning Score `json:"1"`
SecondInning Score `json:"2"`
ThirdInning Score `json:"3"`
FourthInning Score `json:"4"`
FifthInning Score `json:"5"`
SixthInning Score `json:"6"`
SeventhInning Score `json:"7"`
EighthInning Score `json:"8"`
NinthInning Score `json:"9"`
ExtraInnings Score `json:"10"`
TotalScore Score `json:"11"`
FirstInning ScoreResultResponse `json:"1"`
SecondInning ScoreResultResponse `json:"2"`
ThirdInning ScoreResultResponse `json:"3"`
FourthInning ScoreResultResponse `json:"4"`
FifthInning ScoreResultResponse `json:"5"`
SixthInning ScoreResultResponse `json:"6"`
SeventhInning ScoreResultResponse `json:"7"`
EighthInning ScoreResultResponse `json:"8"`
NinthInning ScoreResultResponse `json:"9"`
ExtraInnings ScoreResultResponse `json:"10"`
TotalScore ScoreResultResponse `json:"11"`
} `json:"scores"`
Stats struct {
Hits []string `json:"hits"`

View File

@ -9,3 +9,12 @@ const (
RoleCustomer Role = "customer"
RoleCashier Role = "cashier"
)
func (r Role) IsValid() bool {
switch r {
case RoleSuperAdmin, RoleAdmin, RoleBranchManager, RoleCustomer, RoleCashier:
return true
default:
return false
}
}

View File

@ -0,0 +1,447 @@
package domain
import (
"errors"
"fmt"
"strconv"
"strings"
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"go.uber.org/zap"
)
var (
ErrSettingNotFound = errors.New("cannot find setting in list")
)
type SettingList struct {
SMSProvider SMSProvider `json:"sms_provider"`
MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"`
BetAmountLimit Currency `json:"bet_amount_limit"`
DailyTicketPerIP int64 `json:"daily_ticket_limit"`
TotalWinningLimit Currency `json:"total_winning_limit"`
AmountForBetReferral Currency `json:"amount_for_bet_referral"`
CashbackAmountCap Currency `json:"cashback_amount_cap"`
}
type SettingListRes struct {
SMSProvider SMSProvider `json:"sms_provider"`
MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"`
BetAmountLimit float32 `json:"bet_amount_limit"`
DailyTicketPerIP int64 `json:"daily_ticket_limit"`
TotalWinningLimit float32 `json:"total_winning_limit"`
AmountForBetReferral float32 `json:"amount_for_bet_referral"`
CashbackAmountCap float32 `json:"cashback_amount_cap"`
}
type SaveSettingListReq struct {
SMSProvider *string `json:"sms_provider,omitempty"`
MaxNumberOfOutcomes *int64 `json:"max_number_of_outcomes,omitempty"`
BetAmountLimit *float32 `json:"bet_amount_limit,omitempty"`
DailyTicketPerIP *int64 `json:"daily_ticket_limit,omitempty"`
TotalWinningLimit *float32 `json:"total_winning_limit,omitempty"`
AmountForBetReferral *float32 `json:"amount_for_bet_referral,omitempty"`
CashbackAmountCap *float32 `json:"cashback_amount_cap,omitempty"`
}
func ConvertSaveSettingListReq(settings SaveSettingListReq) ValidSettingList {
return ValidSettingList{
SMSProvider: ConvertStringPtr(settings.SMSProvider),
MaxNumberOfOutcomes: ConvertInt64Ptr(settings.MaxNumberOfOutcomes),
BetAmountLimit: ConvertFloat32PtrToCurrency(settings.BetAmountLimit),
DailyTicketPerIP: ConvertInt64Ptr(settings.DailyTicketPerIP),
TotalWinningLimit: ConvertFloat32PtrToCurrency(settings.TotalWinningLimit),
AmountForBetReferral: ConvertFloat32PtrToCurrency(settings.AmountForBetReferral),
CashbackAmountCap: ConvertFloat32PtrToCurrency(settings.CashbackAmountCap),
}
}
type ValidSettingList struct {
SMSProvider ValidString
MaxNumberOfOutcomes ValidInt64
BetAmountLimit ValidCurrency
DailyTicketPerIP ValidInt64
TotalWinningLimit ValidCurrency
AmountForBetReferral ValidCurrency
CashbackAmountCap ValidCurrency
}
// Always make sure to run the validation before converting this
func (vsl *ValidSettingList) ToSettingList() SettingList {
return SettingList{
SMSProvider: SMSProvider(vsl.SMSProvider.Value),
MaxNumberOfOutcomes: vsl.MaxNumberOfOutcomes.Value,
BetAmountLimit: Currency(vsl.BetAmountLimit.Value),
DailyTicketPerIP: vsl.DailyTicketPerIP.Value,
TotalWinningLimit: Currency(vsl.TotalWinningLimit.Value),
AmountForBetReferral: Currency(vsl.AmountForBetReferral.Value),
CashbackAmountCap: Currency(vsl.CashbackAmountCap.Value),
}
}
// Custom Validations for non-generic types
func (vsl *ValidSettingList) CustomValidationSettings() error {
if !SMSProvider(vsl.SMSProvider.Value).IsValid() {
return fmt.Errorf("sms provider invalid")
}
return nil
}
func (vsl *ValidSettingList) GetInt64SettingsMap() map[string]*ValidInt64 {
return map[string]*ValidInt64{
"max_number_of_outcomes": &vsl.MaxNumberOfOutcomes,
"daily_ticket_limit": &vsl.DailyTicketPerIP,
}
}
func (vsl *ValidSettingList) GetCurrencySettingsMap() map[string]*ValidCurrency {
return map[string]*ValidCurrency{
"bet_amount_limit": &vsl.BetAmountLimit,
"total_winnings_limit": &vsl.TotalWinningLimit,
"amount_for_bet_referral": &vsl.AmountForBetReferral,
"cashback_amount_cap": &vsl.CashbackAmountCap,
}
}
func (vsl *ValidSettingList) GetStringSettingsMap() map[string]*ValidString {
return map[string]*ValidString{
"sms_provider": &vsl.SMSProvider,
}
}
func (vsl *ValidSettingList) GetBoolSettingsMap() map[string]*ValidBool {
return map[string]*ValidBool{}
}
func (vsl *ValidSettingList) GetFloat32SettingsMap() map[string]*ValidFloat32 {
return map[string]*ValidFloat32{}
}
func (vsl *ValidSettingList) GetTimeSettingsMap() map[string]*ValidTime {
return map[string]*ValidTime{}
}
func (vsl *ValidSettingList) GetTotalSettings() int {
return len(vsl.GetInt64SettingsMap()) +
len(vsl.GetCurrencySettingsMap()) +
len(vsl.GetStringSettingsMap()) +
len(vsl.GetBoolSettingsMap()) +
len(vsl.GetFloat32SettingsMap()) +
len(vsl.GetTimeSettingsMap())
}
func (vsl *ValidSettingList) GetAllValid() map[string]*bool {
settingValid := make(map[string]*bool)
for key, setting := range vsl.GetInt64SettingsMap() {
settingValid[key] = &(*setting).Valid
}
for key, setting := range vsl.GetCurrencySettingsMap() {
settingValid[key] = &(*setting).Valid
}
for key, setting := range vsl.GetStringSettingsMap() {
settingValid[key] = &(*setting).Valid
}
for key, setting := range vsl.GetBoolSettingsMap() {
settingValid[key] = &(*setting).Valid
}
for key, setting := range vsl.GetFloat32SettingsMap() {
settingValid[key] = &(*setting).Valid
}
for key, setting := range vsl.GetTimeSettingsMap() {
settingValid[key] = &(*setting).Valid
}
return settingValid
}
func setValidSetting[T any](settings map[string]*T, searchKey string, setVal T) error {
for key, setting := range settings {
if key == searchKey {
*setting = setVal
}
return nil
}
return ErrSettingNotFound
}
func (vsl *ValidSettingList) SetInt64Setting(searchKey string, searchVal string) error {
value, err := strconv.ParseInt(searchVal, 10, 64)
if err != nil {
return err
}
return setValidSetting(vsl.GetInt64SettingsMap(), searchKey, ValidInt64{Value: value, Valid: true})
}
func (vsl *ValidSettingList) SetCurrencySetting(searchKey string, searchVal string) error {
value, err := strconv.ParseInt(searchVal, 10, 64)
if err != nil {
return err
}
return setValidSetting(vsl.GetCurrencySettingsMap(), searchKey, ValidCurrency{Value: Currency(value), Valid: true})
}
func (vsl *ValidSettingList) SetStringSetting(searchKey string, searchVal string) error {
return setValidSetting(vsl.GetStringSettingsMap(), searchKey, ValidString{Value: searchVal, Valid: true})
}
func (vsl *ValidSettingList) SetBoolSetting(searchKey string, searchVal string) error {
value, err := strconv.ParseBool(searchVal)
if err != nil {
return err
}
return setValidSetting(vsl.GetBoolSettingsMap(), searchKey, ValidBool{Value: value, Valid: true})
}
func (vsl *ValidSettingList) SetFloat32Setting(searchKey string, searchVal string) error {
value, err := strconv.ParseFloat(searchVal, 32)
if err != nil {
return err
}
return setValidSetting(vsl.GetFloat32SettingsMap(), searchKey, ValidFloat32{Value: float32(value), Valid: true})
}
func (vsl *ValidSettingList) SetTimeSetting(searchKey string, searchVal string) error {
value, err := time.Parse(time.RFC3339, searchVal)
if err != nil {
return err
}
return setValidSetting(vsl.GetTimeSettingsMap(), searchKey, ValidTime{Value: value, Valid: true})
}
func (vsl *ValidSettingList) SetSetting(searchKey string, searchVal string) error {
setters := []func(string, string) error{
vsl.SetInt64Setting,
vsl.SetCurrencySetting,
vsl.SetStringSetting,
vsl.SetBoolSetting,
vsl.SetFloat32Setting,
vsl.SetTimeSetting,
}
for _, setter := range setters {
if err := setter(searchKey, searchVal); err != nil {
if err == ErrSettingNotFound {
continue // not this setter, try the next
}
return fmt.Errorf("error while processing setting %q: %w", searchKey, err)
}
return nil // successfully set
}
// If we get here, none of the setters matched
return ErrSettingNotFound
}
func convertValidSettings[T any](
settings map[string]*T,
isValid func(*T) bool,
toString func(*T) string,
) []Setting {
result := make([]Setting, 0, len(settings))
for key, s := range settings {
if isValid(s) {
result = append(result, Setting{
Key: key,
Value: toString(s),
})
}
}
return result
}
func (vsl *ValidSettingList) ConvertInt64Settings() []Setting {
return convertValidSettings(
vsl.GetInt64SettingsMap(),
func(s *ValidInt64) bool { return s.Valid },
func(s *ValidInt64) string { return strconv.FormatInt(s.Value, 10) },
)
}
func (vsl *ValidSettingList) ConvertCurrencySettings() []Setting {
return convertValidSettings(
vsl.GetCurrencySettingsMap(),
func(s *ValidCurrency) bool { return s.Valid },
func(s *ValidCurrency) string { return strconv.FormatInt(int64(s.Value), 10) },
)
}
func (vsl *ValidSettingList) ConvertStringSettings() []Setting {
return convertValidSettings(
vsl.GetStringSettingsMap(),
func(s *ValidString) bool { return s.Valid },
func(s *ValidString) string { return s.Value },
)
}
func (vsl *ValidSettingList) ConvertBoolSettings() []Setting {
return convertValidSettings(
vsl.GetBoolSettingsMap(),
func(s *ValidBool) bool { return s.Valid },
func(s *ValidBool) string { return strconv.FormatBool(s.Value) },
)
}
func (vsl *ValidSettingList) ConvertFloat32Settings() []Setting {
return convertValidSettings(
vsl.GetFloat32SettingsMap(),
func(s *ValidFloat32) bool { return s.Valid },
func(s *ValidFloat32) string { return strconv.FormatFloat(float64(s.Value), 'f', -1, 32) },
)
}
func (vsl *ValidSettingList) ConvertTimeSettings() []Setting {
return convertValidSettings(
vsl.GetTimeSettingsMap(),
func(s *ValidTime) bool { return s.Valid },
func(s *ValidTime) string { return s.Value.Format(time.RFC3339) },
)
}
func validateSettings[T any](
settings map[string]*T,
customValidator func(*T) bool,
) error {
var errs []string
for key, s := range settings {
if !customValidator(s) {
errs = append(errs, fmt.Sprintf("%v is invalid", key))
}
}
if len(errs) > 0 {
return errors.New(strings.Join(errs, "; "))
}
return nil
}
func (vsl *ValidSettingList) ValidateInt64Settings() error {
return validateSettings(vsl.GetInt64SettingsMap(),
func(s *ValidInt64) bool {
return s.Valid
},
)
}
func (vsl *ValidSettingList) ValidateCurrencySettings() error {
return validateSettings(vsl.GetCurrencySettingsMap(),
func(s *ValidCurrency) bool {
return s.Valid
},
)
}
func (vsl *ValidSettingList) ValidateStringSettings() error {
return validateSettings(vsl.GetStringSettingsMap(),
func(s *ValidString) bool {
return s.Valid
},
)
}
func (vsl *ValidSettingList) ValidateBoolSettings() error {
return validateSettings(vsl.GetBoolSettingsMap(),
func(s *ValidBool) bool {
return s.Valid
},
)
}
func (vsl *ValidSettingList) ValidateFloat32Settings() error {
return validateSettings(vsl.GetFloat32SettingsMap(),
func(s *ValidFloat32) bool {
return s.Valid
},
)
}
func (vsl *ValidSettingList) ValidateTimeSettings() error {
return validateSettings(vsl.GetTimeSettingsMap(),
func(s *ValidTime) bool {
return s.Valid
},
)
}
func (vsl *ValidSettingList) ValidateAllSettings() error {
var errs []string
validators := []func() error{
vsl.ValidateInt64Settings,
vsl.ValidateCurrencySettings,
vsl.ValidateStringSettings,
vsl.ValidateBoolSettings,
vsl.ValidateFloat32Settings,
vsl.ValidateTimeSettings,
vsl.CustomValidationSettings,
}
for _, validator := range validators {
if err := validator(); err != nil {
errs = append(errs, err.Error())
}
}
if len(errs) > 0 {
return errors.New(strings.Join(errs, "; "))
}
return nil
}
func (vsl *ValidSettingList) ConvertAllSettings() []Setting {
totalCap := vsl.GetTotalSettings()
all := make([]Setting, 0, totalCap)
all = append(all, vsl.ConvertInt64Settings()...)
all = append(all, vsl.ConvertCurrencySettings()...)
all = append(all, vsl.ConvertStringSettings()...)
all = append(all, vsl.ConvertBoolSettings()...)
all = append(all, vsl.ConvertFloat32Settings()...)
all = append(all, vsl.ConvertTimeSettings()...)
return all
}
func ConvertDBGlobalSettingList(settings []dbgen.GlobalSetting) (SettingList, error) {
var dbSettingList ValidSettingList
for _, setting := range settings {
if err := dbSettingList.SetSetting(setting.Key, setting.Value); err != nil {
if err == ErrSettingNotFound {
MongoDBLogger.Warn("unknown setting found on database", zap.String("setting", setting.Key))
}
}
}
if err := dbSettingList.ValidateAllSettings(); err != nil {
fmt.Printf("setting validation error: %v \n", err)
MongoDBLogger.Warn("setting validation error", zap.Error(err))
return SettingList{}, err
}
settingList := dbSettingList.ToSettingList()
return settingList, nil
}
func ConvertDBOverrideSettingList(settings []dbgen.GetOverrideSettingsRow) (SettingList, error) {
var dbSettingList ValidSettingList
for _, setting := range settings {
if err := dbSettingList.SetSetting(setting.Key, setting.Value); err != nil {
if err == ErrSettingNotFound {
MongoDBLogger.Warn("unknown setting found on database", zap.String("setting", setting.Key))
}
}
}
if err := dbSettingList.ValidateAllSettings(); err != nil {
fmt.Printf("setting validation error: %v \n", err)
MongoDBLogger.Warn("setting validation error", zap.Error(err))
return SettingList{}, err
}
settingList := dbSettingList.ToSettingList()
return settingList, nil
}

View File

@ -2,6 +2,8 @@ package domain
import (
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
)
type Setting struct {
@ -11,68 +13,44 @@ type Setting struct {
}
type SettingRes struct {
Key string `json:"key"`
Value string `json:"value"`
UpdatedAt string `json:"updated_at"`
Key string `json:"key"`
Value string `json:"value"`
UpdatedAt time.Time `json:"updated_at"`
}
type CompanySetting struct {
Key string
Value string
CompanyID int64
UpdatedAt time.Time
CreatedAt time.Time
}
type SettingList struct {
SMSProvider SMSProvider `json:"sms_provider"`
MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"`
BetAmountLimit Currency `json:"bet_amount_limit"`
DailyTicketPerIP int64 `json:"daily_ticket_limit"`
TotalWinningLimit Currency `json:"total_winning_limit"`
AmountForBetReferral Currency `json:"amount_for_bet_referral"`
CashbackAmountCap Currency `json:"cashback_amount_cap"`
type CompanySettingRes struct {
Key string `json:"key"`
Value string `json:"value"`
CompanyID int64 `json:"company_id"`
UpdatedAt time.Time `json:"updated_at"`
CreatedAt time.Time `json:"created_at"`
}
type DBSettingList struct {
SMSProvider ValidString
MaxNumberOfOutcomes ValidInt64
BetAmountLimit ValidInt64
DailyTicketPerIP ValidInt64
TotalWinningLimit ValidInt64
AmountForBetReferral ValidInt64
CashbackAmountCap ValidInt64
func ConvertSetting(setting Setting) SettingRes {
return SettingRes(setting)
}
func ConvertInt64SettingsMap(dbSettingList *DBSettingList) map[string]*ValidInt64 {
return map[string]*ValidInt64{
"max_number_of_outcomes": &dbSettingList.MaxNumberOfOutcomes,
"bet_amount_limit": &dbSettingList.BetAmountLimit,
"daily_ticket_limit": &dbSettingList.DailyTicketPerIP,
"total_winnings_limit": &dbSettingList.TotalWinningLimit,
"amount_for_bet_referral": &dbSettingList.AmountForBetReferral,
"cashback_amount_cap": &dbSettingList.CashbackAmountCap,
func ConvertCompanySetting(companySetting dbgen.CompanySetting) CompanySetting {
return CompanySetting{
Key: companySetting.Key,
Value: companySetting.Value,
CompanyID: companySetting.CompanyID,
UpdatedAt: companySetting.UpdatedAt.Time,
CreatedAt: companySetting.CreatedAt.Time,
}
}
func ConvertStringSettingsMap(dbSettingList *DBSettingList) map[string]*ValidString {
return map[string]*ValidString{
"sms_provider": &dbSettingList.SMSProvider,
}
}
func ConvertBoolSettingsMap(dbSettingList *DBSettingList) map[string]*ValidBool {
return map[string]*ValidBool{}
}
func ConvertFloat32SettingsMap(dbSettingList *DBSettingList) map[string]*ValidFloat32 {
return map[string]*ValidFloat32{}
}
func ConvertTimeSettingsMap(dbSettingList *DBSettingList) map[string]*ValidTime {
return map[string]*ValidTime{}
}
func ConvertDBSetting(dbSettingList DBSettingList) SettingList {
return SettingList{
SMSProvider: SMSProvider(dbSettingList.SMSProvider.Value),
MaxNumberOfOutcomes: dbSettingList.MaxNumberOfOutcomes.Value,
BetAmountLimit: Currency(dbSettingList.BetAmountLimit.Value),
DailyTicketPerIP: dbSettingList.DailyTicketPerIP.Value,
TotalWinningLimit: Currency(dbSettingList.TotalWinningLimit.Value),
AmountForBetReferral: Currency(dbSettingList.AmountForBetReferral.Value),
CashbackAmountCap: Currency(dbSettingList.CashbackAmountCap.Value),
func ConvertCompanySettings(settings []dbgen.CompanySetting) []CompanySetting {
result := make([]CompanySetting, 0, len(settings))
for _, setting := range settings {
result = append(result, ConvertCompanySetting(setting))
}
return result
}

View File

@ -39,6 +39,7 @@ type Ticket struct {
ID int64
Amount Currency
TotalOdds float32
CompanyID int64
}
type GetTicket struct {
@ -46,12 +47,14 @@ type GetTicket struct {
Amount Currency
TotalOdds float32
Outcomes []TicketOutcome
CompanyID int64
}
type CreateTicket struct {
Amount Currency
TotalOdds float32
IP string
CompanyID int64
}
type CreateTicketOutcomeReq struct {
@ -80,4 +83,9 @@ type TicketRes struct {
Outcomes []TicketOutcome `json:"outcomes"`
Amount float32 `json:"amount" example:"100.0"`
TotalOdds float32 `json:"total_odds" example:"4.22"`
CompanyID int64 `json:"company_id" example:"1"`
}
type TicketFilter struct {
CompanyID ValidInt64
}

View File

@ -10,24 +10,20 @@ var (
)
type User struct {
ID int64
FirstName string
LastName string
Email string `json:"email"`
PhoneNumber string `json:"phone_number"`
Password []byte
Role Role
//
ID int64
FirstName string
LastName string
Email string `json:"email"`
PhoneNumber string `json:"phone_number"`
Password []byte
Role Role
EmailVerified bool
PhoneVerified bool
//
CreatedAt time.Time
UpdatedAt time.Time
//
SuspendedAt time.Time
Suspended bool
//
CompanyID ValidInt64
CreatedAt time.Time
UpdatedAt time.Time
SuspendedAt time.Time
Suspended bool
CompanyID ValidInt64 //This should be null
}
type UserFilter struct {
@ -39,10 +35,7 @@ type UserFilter struct {
CreatedBefore ValidTime
CreatedAfter ValidTime
}
type ValidRole struct {
Value Role
Valid bool
}
type RegisterUserReq struct {
FirstName string
@ -54,6 +47,7 @@ type RegisterUserReq struct {
Otp string
ReferralCode string `json:"referral_code"`
OtpMedium OtpMedium
CompanyID ValidInt64
}
type CreateUserReq struct {
FirstName string

View File

@ -0,0 +1,245 @@
package domain
import (
"encoding/json"
"fmt"
"strconv"
"time"
"github.com/jackc/pgx/v5/pgtype"
)
// Valid Int64
type ValidInt64 struct {
Value int64
Valid bool
}
func (v ValidInt64) ToPG() pgtype.Int8 {
return pgtype.Int8{
Int64: v.Value,
Valid: v.Valid,
}
}
func (n *ValidInt64) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err == nil {
if s == "" {
n.Valid = false
return nil
}
v, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return err
}
n.Value, n.Valid = v, true
return nil
}
var v int64
if err := json.Unmarshal(data, &v); err == nil {
n.Value, n.Valid = v, true
return nil
}
return fmt.Errorf("invalid int64 value: %s", string(data))
}
func ConvertInt64Ptr(value *int64) ValidInt64 {
if value == nil {
return ValidInt64{}
}
return ValidInt64{
Value: *value,
Valid: true,
}
}
// Valid Int
type ValidInt struct {
Value int
Valid bool
}
func (v ValidInt) ToPG() pgtype.Int4 {
return pgtype.Int4{
Int32: int32(v.Value),
Valid: v.Valid,
}
}
func ConvertIntPtr(value *int) ValidInt {
if value == nil {
return ValidInt{}
}
return ValidInt{
Value: *value,
Valid: true,
}
}
// Valid Int32
type ValidInt32 struct {
Value int32
Valid bool
}
func (v ValidInt32) ToPG() pgtype.Int4 {
return pgtype.Int4{
Int32: v.Value,
Valid: v.Valid,
}
}
func ConvertInt32Ptr(value *int32) ValidInt32 {
if value == nil {
return ValidInt32{}
}
return ValidInt32{
Value: *value,
Valid: true,
}
}
// Valid Float32
type ValidFloat32 struct {
Value float32
Valid bool
}
func (v ValidFloat32) ToPG() pgtype.Float4 {
return pgtype.Float4{
Float32: v.Value,
Valid: v.Valid,
}
}
func ConvertFloat32Ptr(value *float32) ValidFloat32 {
if value == nil {
return ValidFloat32{}
}
return ValidFloat32{
Value: *value,
Valid: true,
}
}
// Valid String
type ValidString struct {
Value string
Valid bool
}
func (v ValidString) ToPG() pgtype.Text {
return pgtype.Text{
String: v.Value,
Valid: v.Valid,
}
}
func ConvertStringPtr(value *string) ValidString {
if value == nil {
return ValidString{}
}
return ValidString{
Value: *value,
Valid: true,
}
}
// Valid Time
type ValidTime struct {
Value time.Time
Valid bool
}
func (v ValidTime) ToPG() pgtype.Timestamp {
return pgtype.Timestamp{
Time: v.Value,
Valid: v.Valid,
}
}
// Valid Bool
type ValidBool struct {
Value bool
Valid bool
}
func (v ValidBool) ToPG() pgtype.Bool {
return pgtype.Bool{
Bool: v.Value,
Valid: v.Valid,
}
}
func ConvertBoolPtr(value *bool) ValidBool {
if value == nil {
return ValidBool{}
}
return ValidBool{
Value: *value,
Valid: true,
}
}
// Valid Currency
type ValidCurrency struct {
Value Currency
Valid bool
}
func (v ValidCurrency) ToPG() pgtype.Int8 {
return pgtype.Int8{
Int64: int64(v.Value),
Valid: v.Valid,
}
}
func ConvertCurrencyPtr(value *Currency) ValidCurrency {
if value == nil {
return ValidCurrency{}
}
return ValidCurrency{
Value: *value,
Valid: true,
}
}
func ConvertFloat32PtrToCurrency(value *float32) ValidCurrency {
if value == nil {
return ValidCurrency{}
}
converted := ToCurrency(*value)
return ValidCurrency{
Value: converted,
Valid: true,
}
}
// Valid Role
type ValidRole struct {
Value Role
Valid bool
}
func (v ValidRole) ToPG() pgtype.Text {
return pgtype.Text{
String: string(v.Value),
Valid: v.Valid,
}
}
func ConvertRolePtr(value *Role) ValidRole {
if value == nil {
return ValidRole{}
}
return ValidRole{
Value: *value,
Valid: true,
}
}

View File

@ -0,0 +1,42 @@
package helpers
import (
"regexp"
"strings"
"unicode"
)
var (
// keep letters, numbers, spaces, and hyphens
slugRegex = regexp.MustCompile(`[^a-z0-9\s-]`)
spaceRe = regexp.MustCompile(`\s+`)
dashRe = regexp.MustCompile(`-+`)
)
// GenerateSlug creates a URL-safe slug from a given string (e.g. company name).
func GenerateSlug(name string) string {
// lowercase
slug := strings.ToLower(name)
// normalize unicode accents (é -> e, ü -> u, etc.)
slug = strings.Map(func(r rune) rune {
if unicode.IsLetter(r) || unicode.IsDigit(r) || unicode.IsSpace(r) || r == '-' {
return r
}
return -1
}, slug)
// remove unwanted chars
slug = slugRegex.ReplaceAllString(slug, "")
// replace spaces with dash
slug = spaceRe.ReplaceAllString(slug, "-")
// collapse multiple dashes
slug = dashRe.ReplaceAllString(slug, "-")
// trim leading/trailing dash
slug = strings.Trim(slug, "-")
return slug
}

View File

@ -11,7 +11,7 @@ import (
"github.com/jackc/pgx/v5/pgtype"
)
func (s *Store) GetUserByEmailPhone(ctx context.Context, email, phone string) (domain.User, error) {
func (s *Store) GetUserByEmailPhone(ctx context.Context, email, phone string, companyID domain.ValidInt64) (domain.User, error) {
user, err := s.queries.GetUserByEmailPhone(ctx, dbgen.GetUserByEmailPhoneParams{
Email: pgtype.Text{
String: email,
@ -21,6 +21,7 @@ func (s *Store) GetUserByEmailPhone(ctx context.Context, email, phone string) (d
String: phone,
Valid: true,
},
CompanyID: companyID.ToPG(),
})
if err != nil {
if errors.Is(err, sql.ErrNoRows) {

View File

@ -19,115 +19,14 @@ var (
mongoLogger *zap.Logger
)
func convertDBBet(bet dbgen.Bet) domain.Bet {
return domain.Bet{
ID: bet.ID,
Amount: domain.Currency(bet.Amount),
TotalOdds: bet.TotalOdds,
Status: domain.OutcomeStatus(bet.Status),
UserID: bet.UserID,
IsShopBet: bet.IsShopBet,
CashedOut: bet.CashedOut,
FastCode: bet.FastCode,
CreatedAt: bet.CreatedAt.Time,
}
}
func convertDBBetOutcomes(outcome dbgen.BetOutcome) domain.BetOutcome {
return domain.BetOutcome{
ID: outcome.ID,
BetID: outcome.BetID,
SportID: outcome.SportID,
EventID: outcome.EventID,
OddID: outcome.OddID,
HomeTeamName: outcome.HomeTeamName,
AwayTeamName: outcome.AwayTeamName,
MarketID: outcome.MarketID,
MarketName: outcome.MarketName,
Odd: outcome.Odd,
OddName: outcome.OddName,
OddHeader: outcome.OddHeader,
OddHandicap: outcome.OddHandicap,
Status: domain.OutcomeStatus(outcome.Status),
Expires: outcome.Expires.Time,
}
}
func convertDBBetWithOutcomes(bet dbgen.BetWithOutcome) domain.GetBet {
var outcomes []domain.BetOutcome = make([]domain.BetOutcome, 0, len(bet.Outcomes))
for _, outcome := range bet.Outcomes {
outcomes = append(outcomes, convertDBBetOutcomes(outcome))
}
return domain.GetBet{
ID: bet.ID,
Amount: domain.Currency(bet.Amount),
TotalOdds: bet.TotalOdds,
Status: domain.OutcomeStatus(bet.Status),
FullName: bet.FullName.(string),
PhoneNumber: bet.PhoneNumber.String,
UserID: bet.UserID,
IsShopBet: bet.IsShopBet,
CashedOut: bet.CashedOut,
Outcomes: outcomes,
FastCode: bet.FastCode,
CreatedAt: bet.CreatedAt.Time,
}
}
func convertDBFlag(flag dbgen.Flag) domain.Flag {
return domain.Flag{
ID: flag.ID,
BetID: flag.BetID.Int64,
OddID: flag.OddID.Int64,
Reason: flag.Reason.String,
FlaggedAt: flag.FlaggedAt.Time,
Resolved: flag.Resolved.Bool,
}
}
func convertDBCreateBetOutcome(betOutcome domain.CreateBetOutcome) dbgen.CreateBetOutcomeParams {
return dbgen.CreateBetOutcomeParams{
BetID: betOutcome.BetID,
EventID: betOutcome.EventID,
SportID: betOutcome.SportID,
OddID: betOutcome.OddID,
HomeTeamName: betOutcome.HomeTeamName,
AwayTeamName: betOutcome.AwayTeamName,
MarketID: betOutcome.MarketID,
MarketName: betOutcome.MarketName,
Odd: betOutcome.Odd,
OddName: betOutcome.OddName,
OddHeader: betOutcome.OddHeader,
OddHandicap: betOutcome.OddHandicap,
Expires: pgtype.Timestamp{
Time: betOutcome.Expires,
Valid: true,
},
}
}
func convertCreateBet(bet domain.CreateBet) dbgen.CreateBetParams {
return dbgen.CreateBetParams{
Amount: int64(bet.Amount),
TotalOdds: bet.TotalOdds,
Status: int32(bet.Status),
UserID: bet.UserID,
IsShopBet: bet.IsShopBet,
OutcomesHash: bet.OutcomesHash,
FastCode: bet.FastCode,
}
}
func (s *Store) CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error) {
newBet, err := s.queries.CreateBet(ctx, convertCreateBet(bet))
newBet, err := s.queries.CreateBet(ctx, domain.ConvertCreateBet(bet))
if err != nil {
fmt.Println("We are here")
logger.Error("Failed to create bet", slog.String("error", err.Error()), slog.Any("bet", bet))
return domain.Bet{}, err
}
return convertDBBet(newBet), err
return domain.ConvertDBBet(newBet), err
}
@ -135,7 +34,7 @@ func (s *Store) CreateBetOutcome(ctx context.Context, outcomes []domain.CreateBe
var dbParams []dbgen.CreateBetOutcomeParams = make([]dbgen.CreateBetOutcomeParams, 0, len(outcomes))
for _, outcome := range outcomes {
dbParams = append(dbParams, convertDBCreateBetOutcome(outcome))
dbParams = append(dbParams, domain.ConvertDBCreateBetOutcome(outcome))
}
rows, err := s.queries.CreateBetOutcome(ctx, dbParams)
@ -157,7 +56,7 @@ func (s *Store) CreateFlag(ctx context.Context, flag domain.CreateFlagReq) (doma
Int64: flag.BetID,
Valid: flag.BetID != 0,
},
OddID: pgtype.Int8{
OddsMarketID: pgtype.Int8{
Int64: flag.OddID,
Valid: flag.OddID != 0,
},
@ -177,7 +76,7 @@ func (s *Store) CreateFlag(ctx context.Context, flag domain.CreateFlagReq) (doma
return domain.Flag{}, err
}
return convertDBFlag(f), nil
return domain.ConvertDBFlag(f), nil
}
func (s *Store) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error) {
@ -190,35 +89,18 @@ func (s *Store) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error)
return domain.GetBet{}, err
}
return convertDBBetWithOutcomes(bet), nil
return domain.ConvertDBBetWithOutcomes(bet), nil
}
func (s *Store) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]domain.GetBet, error) {
bets, err := s.queries.GetAllBets(ctx, dbgen.GetAllBetsParams{
UserID: pgtype.Int8{
Int64: filter.UserID.Value,
Valid: filter.UserID.Valid,
},
CashedOut: pgtype.Bool{
Bool: filter.CashedOut.Value,
Valid: filter.CashedOut.Valid,
},
IsShopBet: pgtype.Bool{
Bool: filter.IsShopBet.Value,
Valid: filter.IsShopBet.Valid,
},
Query: pgtype.Text{
String: filter.Query.Value,
Valid: filter.Query.Valid,
},
CreatedBefore: pgtype.Timestamp{
Time: filter.CreatedBefore.Value,
Valid: filter.CreatedBefore.Valid,
},
CreatedAfter: pgtype.Timestamp{
Time: filter.CreatedAfter.Value,
Valid: filter.CreatedAfter.Valid,
},
UserID: filter.UserID.ToPG(),
CompanyID: filter.CompanyID.ToPG(),
CashedOut: filter.CashedOut.ToPG(),
IsShopBet: filter.IsShopBet.ToPG(),
Query: filter.Query.ToPG(),
CreatedBefore: filter.CreatedBefore.ToPG(),
CreatedAfter: filter.CreatedAfter.ToPG(),
})
if err != nil {
domain.MongoDBLogger.Error("failed to get all bets",
@ -230,7 +112,7 @@ func (s *Store) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]doma
var result []domain.GetBet = make([]domain.GetBet, 0, len(bets))
for _, bet := range bets {
result = append(result, convertDBBetWithOutcomes(bet))
result = append(result, domain.ConvertDBBetWithOutcomes(bet))
}
return result, nil
@ -245,7 +127,7 @@ func (s *Store) GetBetByUserID(ctx context.Context, UserID int64) ([]domain.GetB
var result []domain.GetBet = make([]domain.GetBet, 0, len(bets))
for _, bet := range bets {
result = append(result, convertDBBetWithOutcomes(bet))
result = append(result, domain.ConvertDBBetWithOutcomes(bet))
}
return result, nil
@ -258,7 +140,7 @@ func (s *Store) GetBetByFastCode(ctx context.Context, fastcode string) (domain.G
return domain.GetBet{}, err
}
return convertDBBetWithOutcomes(bet), nil
return domain.ConvertDBBetWithOutcomes(bet), nil
}
func (s *Store) GetBetsForCashback(ctx context.Context) ([]domain.GetBet, error) {
@ -270,7 +152,7 @@ func (s *Store) GetBetsForCashback(ctx context.Context) ([]domain.GetBet, error)
}
for _, bet := range bets {
cashbackBet := convertDBBetWithOutcomes(bet)
cashbackBet := domain.ConvertDBBetWithOutcomes(bet)
res = append(res, cashbackBet)
}
@ -361,7 +243,7 @@ func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_fi
var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
for _, outcome := range outcomes {
result = append(result, convertDBBetOutcomes(outcome))
result = append(result, domain.ConvertDBBetOutcomes(outcome))
}
return result, nil
}
@ -378,7 +260,7 @@ func (s *Store) GetBetOutcomeByBetID(ctx context.Context, betID int64) ([]domain
var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
for _, outcome := range outcomes {
result = append(result, convertDBBetOutcomes(outcome))
result = append(result, domain.ConvertDBBetOutcomes(outcome))
}
return result, nil
}
@ -397,7 +279,7 @@ func (s *Store) UpdateBetOutcomeStatus(ctx context.Context, id int64, status dom
return domain.BetOutcome{}, err
}
res := convertDBBetOutcomes(update)
res := domain.ConvertDBBetOutcomes(update)
return res, nil
}
@ -415,7 +297,7 @@ func (s *Store) UpdateBetOutcomeStatusByBetID(ctx context.Context, id int64, sta
return domain.BetOutcome{}, err
}
res := convertDBBetOutcomes(update)
res := domain.ConvertDBBetOutcomes(update)
return res, nil
}
@ -436,7 +318,7 @@ func (s *Store) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int6
var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
for _, outcome := range outcomes {
result = append(result, convertDBBetOutcomes(outcome))
result = append(result, domain.ConvertDBBetOutcomes(outcome))
}
return result, nil
}

View File

@ -9,7 +9,6 @@ import (
"github.com/jackc/pgx/v5/pgtype"
)
func (s *Store) CreateBranch(ctx context.Context, branch domain.CreateBranch) (domain.Branch, error) {
dbBranch, err := s.queries.CreateBranch(ctx, domain.ConvertCreateBranch(branch))
@ -53,26 +52,11 @@ func (s *Store) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]do
func (s *Store) GetAllBranches(ctx context.Context, filter domain.BranchFilter) ([]domain.BranchDetail, error) {
dbBranches, err := s.queries.GetAllBranches(ctx, dbgen.GetAllBranchesParams{
CompanyID: pgtype.Int8{
Int64: filter.CompanyID.Value,
Valid: filter.CompanyID.Valid,
},
BranchManagerID: pgtype.Int8{
Int64: filter.BranchManagerID.Value,
Valid: filter.BranchManagerID.Valid,
},
Query: pgtype.Text{
String: filter.Query.Value,
Valid: filter.Query.Valid,
},
CreatedBefore: pgtype.Timestamp{
Time: filter.CreatedBefore.Value,
Valid: filter.CreatedBefore.Valid,
},
CreatedAfter: pgtype.Timestamp{
Time: filter.CreatedAfter.Value,
Valid: filter.CreatedAfter.Valid,
},
CompanyID: filter.CompanyID.ToPG(),
BranchManagerID: filter.BranchManagerID.ToPG(),
Query: filter.Query.ToPG(),
CreatedBefore: filter.CreatedBefore.ToPG(),
CreatedAfter: filter.CreatedAfter.ToPG(),
})
if err != nil {
return nil, err

View File

@ -2,14 +2,36 @@ package repository
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/pkgs/helpers"
"github.com/jackc/pgx/v5/pgtype"
)
func (s *Store) CreateCompany(ctx context.Context, company domain.CreateCompany) (domain.Company, error) {
dbCompany, err := s.queries.CreateCompany(ctx, domain.ConvertCreateCompany(company))
baseSlug := helpers.GenerateSlug(company.Name)
uniqueSlug := baseSlug
i := 1
for {
_, err := s.queries.GetCompanyIDUsingSlug(ctx, uniqueSlug)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
// slug is unique
break
} else {
// real DB error
return domain.Company{}, err
}
}
uniqueSlug = fmt.Sprintf("%s-%d", baseSlug, i)
i++
}
dbCompany, err := s.queries.CreateCompany(ctx, domain.ConvertCreateCompany(company, uniqueSlug))
if err != nil {
return domain.Company{}, err
}
@ -56,6 +78,15 @@ func (s *Store) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany
return domain.ConvertDBCompanyDetails(dbCompany), nil
}
func (s *Store) GetCompanyIDBySlug(ctx context.Context, slug string) (int64, error) {
dbCompanyID, err := s.queries.GetCompanyIDUsingSlug(ctx, slug)
if err != nil {
return 0, err
}
return dbCompanyID, nil
}
func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) {
dbCompany, err := s.queries.UpdateCompany(ctx, domain.ConvertUpdateCompany(company))

View File

@ -0,0 +1,105 @@
package repository
// import (
// "context"
// dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
// "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
// )
// func (s *Store) InsertCustomOdds(ctx context.Context, odd domain.CreateCustomOdd) (domain.CustomOdd, error) {
// convertedCustomOdd, err := domain.ConvertCreateCustomOdd(odd)
// if err != nil {
// return domain.CustomOdd{}, err
// }
// dbCustomOdd, err := s.queries.InsertCustomOdd(ctx, convertedCustomOdd)
// if err != nil {
// return domain.CustomOdd{}, err
// }
// convertDbCustomOdd, err := domain.ConvertDBCustomOdd(dbCustomOdd)
// if err != nil {
// return domain.CustomOdd{}, err
// }
// return convertDbCustomOdd, nil
// }
// func (s *Store) GetAllCustomOdds(ctx context.Context, filter domain.CustomOddFilter) ([]domain.CustomOdd, error) {
// dbCustomOdds, err := s.queries.GetAllCustomOdds(ctx, filter.CompanyID.ToPG())
// if err != nil {
// return nil, err
// }
// convertDbCustomOdds, err := domain.ConvertDbCustomOdds(dbCustomOdds)
// if err != nil {
// return nil, err
// }
// return convertDbCustomOdds, nil
// }
// func (s *Store) GetCustomOddByID(ctx context.Context, id int64) (domain.CustomOdd, error) {
// dbCustomOdd, err := s.queries.GetCustomOddByID(ctx, id)
// if err != nil {
// return domain.CustomOdd{}, nil
// }
// convertedDBCustomOdd, err := domain.ConvertDBCustomOdd(dbCustomOdd)
// if err != nil {
// return domain.CustomOdd{}, nil
// }
// return convertedDBCustomOdd, nil
// }
// func (s *Store) GetCustomOddByOddID(ctx context.Context, oddId int64, companyID int64) (domain.CustomOdd, error) {
// dbCustomOdd, err := s.queries.GetCustomOddByOddID(ctx, dbgen.GetCustomOddByOddIDParams{
// OddID: oddId,
// CompanyID: companyID,
// })
// if err != nil {
// return domain.CustomOdd{}, nil
// }
// convertedDBCustomOdd, err := domain.ConvertDBCustomOdd(dbCustomOdd)
// if err != nil {
// return domain.CustomOdd{}, nil
// }
// return convertedDBCustomOdd, nil
// }
// func (s *Store) DeleteCustomOddByID(ctx context.Context, id int64) error {
// err := s.queries.DeleteCustomOddsByID(ctx, id)
// if err != nil {
// return err
// }
// return nil
// }
// func (s *Store) DeleteCustomOddsByOddID(ctx context.Context, oddId int64, companyID int64) error {
// err := s.queries.DeleteCustomOddsByOddID(ctx, dbgen.DeleteCustomOddsByOddIDParams{
// OddID: oddId,
// CompanyID: companyID,
// })
// if err != nil {
// return err
// }
// return nil
// }
// func (s *Store) DeleteCustomOddByEventID(ctx context.Context, eventID string) error {
// err := s.queries.DeleteCustomOddByEventID(ctx, eventID)
// if err != nil {
// return err
// }
// return nil
// }

View File

@ -0,0 +1,68 @@
package repository
import (
"context"
"fmt"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)
func (s *Store) InsertDisabledOdd(ctx context.Context, odd domain.CreateDisabledOdd) (domain.DisabledOdd, error) {
dbDisabledOdd, err := s.queries.InsertDisabledOdds(ctx, domain.ConvertCreateDisabledOdd(odd))
if err != nil {
return domain.DisabledOdd{}, fmt.Errorf("InsertDisabledOdd failed: %w", err)
}
return domain.ConvertDBDisabledOdd(dbDisabledOdd), nil
}
func (s *Store) GetAllDisabledOdds(ctx context.Context) ([]domain.DisabledOdd, error) {
dbDisabledOdds, err := s.queries.GetAllDisabledOdds(ctx)
if err != nil {
return nil, fmt.Errorf("GetAllDisabledOdds failed: %w", err)
}
return domain.ConvertDisabledOdds(dbDisabledOdds), nil
}
func (s *Store) GetDisabledOddByRawOddID(ctx context.Context, rawOddID int64) (domain.DisabledOdd, error) {
dbDisabledOdd, err := s.queries.GetDisabledOddByRawOddID(ctx, rawOddID)
if err != nil {
return domain.DisabledOdd{}, fmt.Errorf("GetDisabledOddByRawOddID failed: %w", err)
}
return domain.ConvertDBDisabledOdd(dbDisabledOdd), nil
}
func (s *Store) GetDisabledOddByID(ctx context.Context, id int64) (domain.DisabledOdd, error) {
dbDisabledOdd, err := s.queries.GetDisabledOddByID(ctx, id)
if err != nil {
return domain.DisabledOdd{}, fmt.Errorf("GetDisabledOddByID failed: %w", err)
}
return domain.ConvertDBDisabledOdd(dbDisabledOdd), nil
}
func (s *Store) DeleteDisabledOddsByID(ctx context.Context, id int64) error {
err := s.queries.DeleteDisabledOddsByID(ctx, id)
if err != nil {
return fmt.Errorf("DeleteDisabledOddsByID failed: %w", err)
}
return nil
}
func (s *Store) DeleteDisabledOddsByRawOddID(ctx context.Context, id int64) error {
err := s.queries.DeleteDisabledOddsByRawOddID(ctx, id)
if err != nil {
return fmt.Errorf("DeleteDisabledOddsByRawOddID failed: %w", err)
}
return nil
}

View File

@ -4,7 +4,6 @@ import (
"context"
"fmt"
"math"
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
@ -13,90 +12,29 @@ import (
"github.com/jackc/pgx/v5/pgtype"
)
func (s *Store) SaveEvent(ctx context.Context, e domain.Event) error {
parsedTime, err := time.Parse(time.RFC3339, e.StartTime)
if err != nil {
return err
}
return s.queries.InsertEvent(ctx, dbgen.InsertEventParams{
ID: e.ID,
SportID: pgtype.Int4{Int32: e.SportID, Valid: true},
MatchName: pgtype.Text{String: e.MatchName, Valid: true},
HomeTeam: pgtype.Text{String: e.HomeTeam, Valid: true},
AwayTeam: pgtype.Text{String: e.AwayTeam, Valid: true},
HomeTeamID: pgtype.Int4{Int32: e.HomeTeamID, Valid: true},
AwayTeamID: pgtype.Int4{Int32: e.AwayTeamID, Valid: true},
HomeKitImage: pgtype.Text{String: e.HomeKitImage, Valid: true},
AwayKitImage: pgtype.Text{String: e.AwayKitImage, Valid: true},
LeagueID: pgtype.Int4{Int32: e.LeagueID, Valid: true},
LeagueName: pgtype.Text{String: e.LeagueName, Valid: true},
LeagueCc: pgtype.Text{String: e.LeagueCC, Valid: true},
StartTime: pgtype.Timestamp{Time: parsedTime, Valid: true},
Score: pgtype.Text{String: e.Score, Valid: true},
MatchMinute: pgtype.Int4{Int32: int32(e.MatchMinute), Valid: true},
TimerStatus: pgtype.Text{String: e.TimerStatus, Valid: true},
AddedTime: pgtype.Int4{Int32: int32(e.AddedTime), Valid: true},
MatchPeriod: pgtype.Int4{Int32: int32(e.MatchPeriod), Valid: true},
IsLive: pgtype.Bool{Bool: e.IsLive, Valid: true},
Status: pgtype.Text{String: e.Status, Valid: true},
Source: pgtype.Text{String: e.Source, Valid: true},
})
func (s *Store) SaveEvent(ctx context.Context, e domain.CreateEvent) error {
return s.queries.InsertEvent(ctx, domain.ConvertCreateEvent(e))
}
func (s *Store) SaveUpcomingEvent(ctx context.Context, e domain.UpcomingEvent) error {
return s.queries.InsertUpcomingEvent(ctx, dbgen.InsertUpcomingEventParams{
ID: e.ID,
SportID: pgtype.Int4{Int32: e.SportID, Valid: true},
MatchName: pgtype.Text{String: e.MatchName, Valid: true},
HomeTeam: pgtype.Text{String: e.HomeTeam, Valid: true},
AwayTeam: pgtype.Text{String: e.AwayTeam, Valid: true},
HomeTeamID: pgtype.Int4{Int32: e.HomeTeamID, Valid: true},
AwayTeamID: pgtype.Int4{Int32: e.AwayTeamID, Valid: true},
HomeKitImage: pgtype.Text{String: e.HomeKitImage, Valid: true},
AwayKitImage: pgtype.Text{String: e.AwayKitImage, Valid: true},
LeagueID: pgtype.Int4{Int32: e.LeagueID, Valid: true},
LeagueName: pgtype.Text{String: e.LeagueName, Valid: true},
LeagueCc: pgtype.Text{String: e.LeagueCC, Valid: true},
StartTime: pgtype.Timestamp{Time: e.StartTime, Valid: true},
Source: pgtype.Text{String: e.Source, Valid: true},
})
func (s *Store) InsertEventSettings(ctx context.Context, eventSetting domain.CreateEventSettings) error {
return s.queries.InsertEventSettings(ctx, domain.ConvertCreateEventSettings(eventSetting))
}
func (s *Store) GetLiveEventIDs(ctx context.Context) ([]string, error) {
return s.queries.ListLiveEvents(ctx)
}
func (s *Store) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error) {
func (s *Store) GetAllUpcomingEvents(ctx context.Context) ([]domain.BaseEvent, error) {
events, err := s.queries.GetAllUpcomingEvents(ctx)
if err != nil {
return nil, err
}
upcomingEvents := make([]domain.UpcomingEvent, len(events))
for i, e := range events {
upcomingEvents[i] = domain.UpcomingEvent{
ID: e.ID,
SportID: e.SportID.Int32,
MatchName: e.MatchName.String,
HomeTeam: e.HomeTeam.String,
AwayTeam: e.AwayTeam.String,
HomeTeamID: e.HomeTeamID.Int32,
AwayTeamID: e.AwayTeamID.Int32,
HomeKitImage: e.HomeKitImage.String,
AwayKitImage: e.AwayKitImage.String,
LeagueID: e.LeagueID.Int32,
LeagueName: e.LeagueName.String,
LeagueCC: e.LeagueCc.String,
StartTime: e.StartTime.Time.UTC(),
Source: e.Source.String,
Status: domain.EventStatus(e.Status.String),
IsFeatured: e.IsFeatured,
}
}
return upcomingEvents, nil
return domain.ConvertDBEvents(events), nil
}
func (s *Store) GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, error) {
events, err := s.queries.GetExpiredUpcomingEvents(ctx, pgtype.Text{
func (s *Store) GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.BaseEvent, error) {
events, err := s.queries.GetExpiredEvents(ctx, pgtype.Text{
String: filter.MatchStatus.Value,
Valid: filter.MatchStatus.Valid,
})
@ -104,163 +42,98 @@ func (s *Store) GetExpiredUpcomingEvents(ctx context.Context, filter domain.Even
return nil, err
}
upcomingEvents := make([]domain.UpcomingEvent, len(events))
for i, e := range events {
upcomingEvents[i] = domain.UpcomingEvent{
ID: e.ID,
SportID: e.SportID.Int32,
MatchName: e.MatchName.String,
HomeTeam: e.HomeTeam.String,
AwayTeam: e.AwayTeam.String,
HomeTeamID: e.HomeTeamID.Int32,
AwayTeamID: e.AwayTeamID.Int32,
HomeKitImage: e.HomeKitImage.String,
AwayKitImage: e.AwayKitImage.String,
LeagueID: e.LeagueID.Int32,
LeagueName: e.LeagueName.String,
LeagueCC: e.LeagueCc.String,
StartTime: e.StartTime.Time.UTC(),
Source: e.Source.String,
Status: domain.EventStatus(e.Status.String),
IsFeatured: e.IsFeatured,
IsActive: e.IsActive,
}
}
return upcomingEvents, nil
return domain.ConvertDBEvents(events), nil
}
func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, int64, error) {
func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.BaseEvent, int64, error) {
events, err := s.queries.GetPaginatedUpcomingEvents(ctx, dbgen.GetPaginatedUpcomingEventsParams{
LeagueID: pgtype.Int4{
Int32: int32(filter.LeagueID.Value),
Valid: filter.LeagueID.Valid,
},
SportID: pgtype.Int4{
Int32: int32(filter.SportID.Value),
Valid: filter.SportID.Valid,
},
Query: pgtype.Text{
String: filter.Query.Value,
Valid: filter.Query.Valid,
},
Limit: pgtype.Int4{
Int32: int32(filter.Limit.Value),
Valid: filter.Limit.Valid,
},
Offset: pgtype.Int4{
Int32: int32(filter.Offset.Value * filter.Limit.Value),
Valid: filter.Offset.Valid,
},
FirstStartTime: pgtype.Timestamp{
Time: filter.FirstStartTime.Value.UTC(),
Valid: filter.FirstStartTime.Valid,
},
LastStartTime: pgtype.Timestamp{
Time: filter.LastStartTime.Value.UTC(),
Valid: filter.LastStartTime.Valid,
},
CountryCode: pgtype.Text{
String: filter.CountryCode.Value,
Valid: filter.CountryCode.Valid,
},
IsFeatured: pgtype.Bool{
Bool: filter.Featured.Valid,
Valid: filter.Featured.Valid,
},
LeagueID: filter.LeagueID.ToPG(),
SportID: filter.SportID.ToPG(),
Query: filter.Query.ToPG(),
Limit: filter.Limit.ToPG(),
Offset: filter.Offset.ToPG(),
FirstStartTime: filter.FirstStartTime.ToPG(),
LastStartTime: filter.LastStartTime.ToPG(),
CountryCode: filter.CountryCode.ToPG(),
})
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.Int32,
MatchName: e.MatchName.String,
HomeTeam: e.HomeTeam.String,
AwayTeam: e.AwayTeam.String,
HomeTeamID: e.HomeTeamID.Int32,
AwayTeamID: e.AwayTeamID.Int32,
HomeKitImage: e.HomeKitImage.String,
AwayKitImage: e.AwayKitImage.String,
LeagueID: e.LeagueID.Int32,
LeagueName: e.LeagueName.String,
LeagueCC: e.LeagueCc.String,
StartTime: e.StartTime.Time.UTC(),
Source: e.Source.String,
Status: domain.EventStatus(e.Status.String),
IsFeatured: e.IsFeatured,
IsActive: e.IsActive,
}
}
totalCount, err := s.queries.GetTotalEvents(ctx, dbgen.GetTotalEventsParams{
LeagueID: pgtype.Int4{
Int32: int32(filter.LeagueID.Value),
Valid: filter.LeagueID.Valid,
},
SportID: pgtype.Int4{
Int32: int32(filter.SportID.Value),
Valid: filter.SportID.Valid,
},
Query: pgtype.Text{
String: filter.Query.Value,
Valid: filter.Query.Valid,
},
FirstStartTime: pgtype.Timestamp{
Time: filter.FirstStartTime.Value.UTC(),
Valid: filter.FirstStartTime.Valid,
},
LastStartTime: pgtype.Timestamp{
Time: filter.LastStartTime.Value.UTC(),
Valid: filter.LastStartTime.Valid,
},
CountryCode: pgtype.Text{
String: filter.CountryCode.Value,
Valid: filter.CountryCode.Valid,
},
IsFeatured: pgtype.Bool{
Bool: filter.Featured.Valid,
Valid: filter.Featured.Valid,
},
LeagueID: filter.LeagueID.ToPG(),
SportID: filter.SportID.ToPG(),
Query: filter.Query.ToPG(),
FirstStartTime: filter.FirstStartTime.ToPG(),
LastStartTime: filter.LastStartTime.ToPG(),
CountryCode: filter.CountryCode.ToPG(),
})
if err != nil {
return nil, 0, err
}
numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value))
return upcomingEvents, int64(numberOfPages), nil
return domain.ConvertDBEvents(events), int64(numberOfPages), nil
}
func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
event, err := s.queries.GetUpcomingByID(ctx, ID)
func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) {
events, err := s.queries.GetEventsWithSettings(ctx, dbgen.GetEventsWithSettingsParams{
CompanyID: companyID,
LeagueID: filter.LeagueID.ToPG(),
SportID: filter.SportID.ToPG(),
Query: filter.Query.ToPG(),
Limit: filter.Limit.ToPG(),
Offset: filter.Offset.ToPG(),
FirstStartTime: filter.FirstStartTime.ToPG(),
LastStartTime: filter.LastStartTime.ToPG(),
CountryCode: filter.CountryCode.ToPG(),
})
if err != nil {
return domain.UpcomingEvent{}, err
return nil, 0, err
}
return domain.UpcomingEvent{
ID: event.ID,
SportID: event.SportID.Int32,
MatchName: event.MatchName.String,
HomeTeam: event.HomeTeam.String,
AwayTeam: event.AwayTeam.String,
HomeTeamID: event.HomeTeamID.Int32,
AwayTeamID: event.AwayTeamID.Int32,
HomeKitImage: event.HomeKitImage.String,
AwayKitImage: event.AwayKitImage.String,
LeagueID: event.LeagueID.Int32,
LeagueName: event.LeagueName.String,
LeagueCC: event.LeagueCc.String,
StartTime: event.StartTime.Time.UTC(),
Source: event.Source.String,
Status: domain.EventStatus(event.Status.String),
IsFeatured: event.IsFeatured,
}, nil
totalCount, err := s.queries.GetTotalCompanyEvents(ctx, dbgen.GetTotalCompanyEventsParams{
CompanyID: companyID,
LeagueID: filter.LeagueID.ToPG(),
SportID: filter.SportID.ToPG(),
Query: filter.Query.ToPG(),
FirstStartTime: filter.FirstStartTime.ToPG(),
LastStartTime: filter.LastStartTime.ToPG(),
CountryCode: filter.CountryCode.ToPG(),
})
if err != nil {
return nil, 0, err
}
numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value))
return domain.ConvertDBEventWithSettings(events), int64(numberOfPages), nil
}
func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.BaseEvent, error) {
event, err := s.queries.GetUpcomingByID(ctx, ID)
if err != nil {
return domain.BaseEvent{}, err
}
return domain.ConvertDBEvent(event), nil
}
func (s *Store) GetEventWithSettingByID(ctx context.Context, ID string, companyID int64) (domain.EventWithSettings, error) {
event, err := s.queries.GetEventWithSettingByID(ctx, dbgen.GetEventWithSettingByIDParams{
ID: ID,
CompanyID: companyID,
})
if err != nil {
return domain.EventWithSettings{}, err
}
return domain.ConvertDBEventWithSetting(event), nil
}
func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore string, status domain.EventStatus) error {
params := dbgen.UpdateMatchResultParams{
Score: pgtype.Text{String: fullScore, Valid: true},
Status: pgtype.Text{String: string(status), Valid: true},
Status: string(status),
ID: eventID,
}
@ -274,11 +147,8 @@ func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore string,
func (s *Store) UpdateEventStatus(ctx context.Context, eventID string, status domain.EventStatus) error {
params := dbgen.UpdateMatchResultParams{
Status: pgtype.Text{
String: string(status),
Valid: true,
},
ID: eventID,
Status: string(status),
ID: eventID,
}
err := s.queries.UpdateMatchResult(ctx, params)
@ -290,13 +160,25 @@ func (s *Store) UpdateEventStatus(ctx context.Context, eventID string, status do
}
func (s *Store) UpdateFeatured(ctx context.Context, eventID string, isFeatured bool) error {
return s.queries.UpdateFeatured(ctx, dbgen.UpdateFeaturedParams{
ID: eventID,
IsFeatured: isFeatured,
func (s *Store) IsEventMonitored(ctx context.Context, eventID string) (bool, error) {
isMonitored, err := s.queries.IsEventMonitored(ctx, eventID)
if err != nil {
return false, err
}
return isMonitored, err
}
func (s *Store) UpdateEventMonitored(ctx context.Context, eventID string, IsMonitored bool) error {
return s.queries.UpdateEventMonitored(ctx, dbgen.UpdateEventMonitoredParams{
ID: eventID,
IsMonitored: IsMonitored,
})
}
func (s *Store) UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error {
return s.queries.UpdateEventSettings(ctx, domain.ConvertUpdateEventSettings(event))
}
func (s *Store) DeleteEvent(ctx context.Context, eventID string) error {
err := s.queries.DeleteEvent(ctx, eventID)
if err != nil {

View File

@ -0,0 +1,55 @@
package repository
import (
"context"
"fmt"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)
func (s *Store) InsertEventHistory(ctx context.Context, eventHistory domain.CreateEventHistory) (domain.EventHistory, error) {
dbEventHistory, err := s.queries.InsertEventHistory(ctx, domain.ConvertCreateEventHistory(eventHistory))
if err != nil {
return domain.EventHistory{}, fmt.Errorf("InsertEventHistory failed: %w", err)
}
return domain.ConvertDBEventHistory(dbEventHistory), nil
}
func convertEventHistory(list []dbgen.EventHistory) []domain.EventHistory {
result := make([]domain.EventHistory, 0, len(list))
for _, item := range list {
result = append(result, domain.ConvertDBEventHistory(item))
}
return result
}
func (s *Store) GetAllEventHistory(ctx context.Context, filter domain.EventHistoryFilter) ([]domain.EventHistory, error) {
dbEventHistories, err := s.queries.GetAllEventHistory(ctx, dbgen.GetAllEventHistoryParams{
EventID: filter.EventID.ToPG(),
CreatedAfter: filter.CreatedAfter.ToPG(),
CreatedBefore: filter.CreatedBefore.ToPG(),
})
if err != nil {
return nil, fmt.Errorf("GetAllEventHistory failed: %w", err)
}
return convertEventHistory(dbEventHistories), nil
}
func (s *Store) GetInitialEventPerDay(ctx context.Context, filter domain.EventHistoryFilter) ([]domain.EventHistory, error) {
dbEventHistories, err := s.queries.GetInitialEventPerDay(ctx, dbgen.GetInitialEventPerDayParams{
EventID: filter.EventID.ToPG(),
CreatedAfter: filter.CreatedAfter.ToPG(),
CreatedBefore: filter.CreatedBefore.ToPG(),
})
if err != nil {
return nil, fmt.Errorf("GetInitialEventPerDay failed: %w", err)
}
return convertEventHistory(dbEventHistories), nil
}

View File

@ -8,36 +8,18 @@ import (
"github.com/jackc/pgx/v5/pgtype"
)
func (s *Store) SaveLeague(ctx context.Context, l domain.League) error {
return s.queries.InsertLeague(ctx, dbgen.InsertLeagueParams{
ID: l.ID,
Name: l.Name,
CountryCode: pgtype.Text{String: l.CountryCode, Valid: true},
Bet365ID: pgtype.Int4{Int32: l.Bet365ID, Valid: true},
IsActive: pgtype.Bool{Bool: l.IsActive, Valid: true},
IsFeatured: pgtype.Bool{Bool: l.IsFeatured, Valid: true},
SportID: l.SportID,
})
func (s *Store) SaveLeague(ctx context.Context, league domain.CreateLeague) error {
return s.queries.InsertLeague(ctx, domain.ConvertCreateLeague(league))
}
func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.League, error) {
func (s *Store) SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error {
return s.queries.InsertLeagueSettings(ctx, domain.ConvertCreateLeagueSettings(leagueSettings))
}
func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) {
l, err := s.queries.GetAllLeagues(ctx, dbgen.GetAllLeaguesParams{
CountryCode: pgtype.Text{
String: filter.CountryCode.Value,
Valid: filter.CountryCode.Valid,
},
SportID: pgtype.Int4{
Int32: filter.SportID.Value,
Valid: filter.SportID.Valid,
},
IsActive: pgtype.Bool{
Bool: filter.IsActive.Value,
Valid: filter.IsActive.Valid,
},
IsFeatured: pgtype.Bool{
Bool: filter.IsFeatured.Value,
Valid: filter.IsFeatured.Valid,
},
CountryCode: filter.CountryCode.ToPG(),
SportID: filter.SportID.ToPG(),
Limit: pgtype.Int4{
Int32: int32(filter.Limit.Value),
Valid: filter.Limit.Valid,
@ -51,85 +33,38 @@ func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) (
return nil, err
}
leagues := make([]domain.League, len(l))
for i, league := range l {
leagues[i] = domain.League{
ID: league.ID,
Name: league.Name,
CountryCode: league.CountryCode.String,
Bet365ID: league.Bet365ID.Int32,
IsActive: league.IsActive.Bool,
IsFeatured: league.IsFeatured.Bool,
SportID: league.SportID,
}
}
return leagues, nil
return domain.ConvertDBBaseLeagues(l), nil
}
func (s *Store) GetFeaturedLeagues(ctx context.Context) ([]domain.League, error) {
l, err := s.queries.GetFeaturedLeagues(ctx)
func (s *Store) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, error) {
l, err := s.queries.GetAllLeaguesWithSettings(ctx, dbgen.GetAllLeaguesWithSettingsParams{
CompanyID: companyID,
CountryCode: filter.CountryCode.ToPG(),
SportID: filter.SportID.ToPG(),
Limit: pgtype.Int4{
Int32: int32(filter.Limit.Value),
Valid: filter.Limit.Valid,
},
Offset: pgtype.Int4{
Int32: int32(filter.Offset.Value * filter.Limit.Value),
Valid: filter.Offset.Valid,
},
})
if err != nil {
return nil, err
}
leagues := make([]domain.League, len(l))
for i, league := range l {
leagues[i] = domain.League{
ID: league.ID,
Name: league.Name,
CountryCode: league.CountryCode.String,
Bet365ID: league.Bet365ID.Int32,
IsActive: league.IsActive.Bool,
SportID: league.SportID,
}
}
return leagues, nil
return domain.ConvertDBLeagueWithSettings(l), nil
}
func (s *Store) CheckLeagueSupport(ctx context.Context, leagueID int64) (bool, error) {
return s.queries.CheckLeagueSupport(ctx, leagueID)
}
func (s *Store) SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) error {
return s.queries.SetLeagueActive(ctx, dbgen.SetLeagueActiveParams{
ID: leagueId,
IsActive: pgtype.Bool{
Bool: isActive,
Valid: true,
},
func (s *Store) CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error) {
return s.queries.CheckLeagueSupport(ctx, dbgen.CheckLeagueSupportParams{
LeagueID: leagueID,
CompanyID: companyID,
})
}
func (s *Store) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error {
err := s.queries.UpdateLeague(ctx, dbgen.UpdateLeagueParams{
ID: league.ID,
Name: pgtype.Text{
String: league.Name.Value,
Valid: league.Name.Valid,
},
CountryCode: pgtype.Text{
String: league.CountryCode.Value,
Valid: league.CountryCode.Valid,
},
Bet365ID: pgtype.Int4{
Int32: league.Bet365ID.Value,
Valid: league.Bet365ID.Valid,
},
IsActive: pgtype.Bool{
Bool: league.IsActive.Value,
Valid: league.IsActive.Valid,
},
IsFeatured: pgtype.Bool{
Bool: league.IsFeatured.Value,
Valid: league.IsFeatured.Valid,
},
SportID: pgtype.Int4{
Int32: league.SportID.Value,
Valid: league.SportID.Valid,
},
})
return err
return s.queries.UpdateLeague(ctx, domain.ConvertUpdateLeague(league))
}

View File

@ -0,0 +1,53 @@
package repository
import (
"context"
"fmt"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)
func (s *Store) InsertOddHistory(ctx context.Context, odd domain.CreateOddHistory) (domain.OddHistory, error) {
dbOddHistory, err := s.queries.InsertOddHistory(ctx, domain.ConvertCreateOddHistory(odd))
if err != nil {
return domain.OddHistory{}, fmt.Errorf("InsertOddHistory failed: %w", err)
}
return domain.ConvertDBOddHistory(dbOddHistory), nil
}
func (s *Store) GetAllOddHistory(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error) {
dbOddHistories, err := s.queries.GetAllOddHistory(ctx, dbgen.GetAllOddHistoryParams{
OddID: filter.OddID.ToPG(),
MarketID: filter.MarketID.ToPG(),
RawOddID: filter.RawOddID.ToPG(),
EventID: filter.EventID.ToPG(),
CreatedAfter: filter.CreatedAfter.ToPG(),
CreatedBefore: filter.CreatedBefore.ToPG(),
})
if err != nil {
return nil, fmt.Errorf("GetAllOddHistory failed: %w", err)
}
return domain.ConvertOddHistories(dbOddHistories), nil
}
func (s *Store) GetInitialOddPerDay(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error) {
dbOddHistories, err := s.queries.GetInitialOddPerDay(ctx, dbgen.GetInitialOddPerDayParams{
OddID: filter.OddID.ToPG(),
MarketID: filter.MarketID.ToPG(),
RawOddID: filter.RawOddID.ToPG(),
EventID: filter.EventID.ToPG(),
CreatedAfter: filter.CreatedAfter.ToPG(),
CreatedBefore: filter.CreatedBefore.ToPG(),
DateTrunc: "day",
})
if err != nil {
return nil, fmt.Errorf("GetInitialOddPerDay failed: %w", err)
}
return domain.ConvertOddHistories(dbOddHistories), nil
}

View File

@ -13,55 +13,26 @@ import (
"github.com/jackc/pgx/v5/pgtype"
)
func (s *Store) SaveNonLiveMarket(ctx context.Context, m domain.Market) error {
func (s *Store) SaveOddMarket(ctx context.Context, m domain.CreateOddMarket) error {
if len(m.Odds) == 0 {
return nil
}
for _, item := range m.Odds {
var name string
var oddsVal float64
params, err := domain.ConvertCreateOddMarket(m)
if m.Source == "bwin" {
nameValue := getMap(item["name"])
name = getString(nameValue["value"])
oddsVal = getFloat(item["odds"])
} else {
name = getString(item["name"])
oddsVal = getConvertedFloat(item["odds"])
}
handicap := getString(item["handicap"])
if err != nil {
return err
}
rawOddsBytes, _ := json.Marshal(m.Odds)
params := dbgen.InsertNonLiveOddParams{
EventID: pgtype.Text{String: m.EventID, Valid: m.EventID != ""},
Fi: pgtype.Text{String: m.FI, Valid: m.FI != ""},
MarketType: m.MarketType,
MarketName: pgtype.Text{String: m.MarketName, Valid: m.MarketName != ""},
MarketCategory: pgtype.Text{String: m.MarketCategory, Valid: m.MarketCategory != ""},
MarketID: pgtype.Text{String: m.MarketID, Valid: m.MarketID != ""},
Name: pgtype.Text{String: name, Valid: name != ""},
Handicap: pgtype.Text{String: handicap, Valid: handicap != ""},
OddsValue: pgtype.Float8{Float64: oddsVal, Valid: oddsVal != 0},
Section: m.MarketCategory,
Category: pgtype.Text{Valid: false},
RawOdds: rawOddsBytes,
IsActive: pgtype.Bool{Bool: true, Valid: true},
Source: pgtype.Text{String: m.Source, Valid: true},
FetchedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
}
err := s.queries.InsertNonLiveOdd(ctx, params)
if err != nil {
_ = writeFailedMarketLog(m, err)
continue
}
err = s.queries.InsertOddsMarket(ctx, params)
if err != nil {
_ = writeFailedMarketLog(m, err)
return err
}
return nil
}
func writeFailedMarketLog(m domain.Market, err error) error {
func writeFailedMarketLog(m domain.CreateOddMarket, err error) error {
logDir := "logs"
logFile := logDir + "/failed_markets.log"
@ -76,9 +47,9 @@ func writeFailedMarketLog(m domain.Market, err error) error {
defer f.Close()
entry := struct {
Time string `json:"time"`
Error string `json:"error"`
Record domain.Market `json:"record"`
Time string `json:"time"`
Error string `json:"error"`
Record domain.CreateOddMarket `json:"record"`
}{
Time: time.Now().Format(time.RFC3339),
Error: err.Error(),
@ -90,196 +61,130 @@ func writeFailedMarketLog(m domain.Market, err error) error {
return writeErr
}
func (s *Store) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
odds, err := s.queries.GetPrematchOdds(ctx)
func (s *Store) GetAllOdds(ctx context.Context, filter domain.OddMarketFilter) ([]domain.OddMarket, error) {
rows, err := s.queries.GetAllOdds(ctx, dbgen.GetAllOddsParams{
Offset: filter.Offset.ToPG(),
Limit: filter.Limit.ToPG(),
})
if err != nil {
return nil, err
}
domainOdds := make([]domain.Odd, len(odds))
for i, odd := range odds {
domainOdds[i] = domain.Odd{
EventID: odd.EventID.String,
Fi: odd.Fi.String,
MarketType: odd.MarketType,
MarketName: odd.MarketName.String,
MarketCategory: odd.MarketCategory.String,
MarketID: odd.MarketID.String,
Name: odd.Name.String,
Handicap: odd.Handicap.String,
OddsValue: odd.OddsValue.Float64,
Section: odd.Section,
Category: odd.Category.String,
RawOdds: func() []domain.RawMessage {
var rawOdds []domain.RawMessage
if err := json.Unmarshal(odd.RawOdds, &rawOdds); err != nil {
rawOdds = nil
}
return rawOdds
}(),
FetchedAt: odd.FetchedAt.Time,
Source: odd.Source.String,
IsActive: odd.IsActive.Bool,
}
domainOdds, err := domain.ConvertDBOddMarkets(rows)
if err != nil {
return nil, err
}
return domainOdds, nil
}
func (s *Store) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) {
rows, err := s.queries.GetALLPrematchOdds(ctx)
func (s *Store) GetAllOddsWithSettings(ctx context.Context, companyID int64, filter domain.OddMarketFilter) ([]domain.OddMarketWithSettings, error) {
odds, err := s.queries.GetAllOddsWithSettings(ctx, dbgen.GetAllOddsWithSettingsParams{
CompanyID: companyID,
Offset: filter.Offset.ToPG(),
Limit: filter.Limit.ToPG(),
})
if err != nil {
return nil, err
}
domainOdds := make([]domain.Odd, len(rows))
for i, row := range rows {
domainOdds[i] = domain.Odd{
// ID: int64(row.ID),
EventID: row.EventID.String,
Fi: row.Fi.String,
MarketType: row.MarketType,
MarketName: row.MarketName.String,
MarketCategory: row.MarketCategory.String,
MarketID: row.MarketID.String,
Name: row.Name.String,
Handicap: row.Handicap.String,
OddsValue: row.OddsValue.Float64,
Section: row.Section,
Category: row.Category.String,
RawOdds: func() []domain.RawMessage {
var rawOdds []domain.RawMessage
if err := json.Unmarshal(row.RawOdds, &rawOdds); err != nil {
rawOdds = nil
}
return rawOdds
}(),
FetchedAt: row.FetchedAt.Time,
Source: row.Source.String,
IsActive: row.IsActive.Bool,
}
domainOdds, err := domain.ConvertDBOddMarketWithSettings(odds)
if err != nil {
return nil, err
}
return domainOdds, nil
}
func (s *Store) GetRawOddsByMarketID(ctx context.Context, rawOddsID string, upcomingID string) (domain.RawOddsByMarketID, error) {
params := dbgen.GetRawOddsByMarketIDParams{
MarketID: pgtype.Text{String: rawOddsID, Valid: true},
Fi: pgtype.Text{String: upcomingID, Valid: true},
}
func (s *Store) GetOddsByMarketID(ctx context.Context, marketID string, eventID string) (domain.OddMarket, error) {
odds, err := s.queries.GetRawOddsByMarketID(ctx, params)
odds, err := s.queries.GetOddsByMarketID(ctx, dbgen.GetOddsByMarketIDParams{
MarketID: marketID,
EventID: eventID,
})
if err != nil {
return domain.RawOddsByMarketID{}, err
return domain.OddMarket{}, err
}
var rawOdds []json.RawMessage
if err := json.Unmarshal(odds.RawOdds, &rawOdds); err != nil {
return domain.RawOddsByMarketID{}, err
}
convertedOdd, err := domain.ConvertDBOddMarket(odds)
return domain.RawOddsByMarketID{
ID: int64(odds.ID),
MarketName: odds.MarketName.String,
Handicap: odds.Handicap.String,
RawOdds: func() []domain.RawMessage {
converted := make([]domain.RawMessage, len(rawOdds))
for i, r := range rawOdds {
converted[i] = domain.RawMessage(r)
}
return converted
}(),
FetchedAt: odds.FetchedAt.Time,
}, nil
if err != nil {
return domain.OddMarket{}, err
}
return convertedOdd, nil
}
func (s *Store) GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit domain.ValidInt64, offset domain.ValidInt64) ([]domain.Odd, error) {
odds, err := s.queries.GetPaginatedPrematchOddsByUpcomingID(ctx, dbgen.GetPaginatedPrematchOddsByUpcomingIDParams{
ID: upcomingID,
Limit: pgtype.Int4{
Int32: int32(limit.Value),
Valid: limit.Valid,
func (s *Store) GetOddsWithSettingsByMarketID(ctx context.Context, marketID string, eventID string, companyID int64) (domain.OddMarketWithSettings, error) {
odds, err := s.queries.GetOddsWithSettingsByMarketID(ctx, dbgen.GetOddsWithSettingsByMarketIDParams{
MarketID: marketID,
EventID: eventID,
CompanyID: companyID,
})
if err != nil {
return domain.OddMarketWithSettings{}, err
}
convertedOdd, err := domain.ConvertDBOddMarketWithSetting(odds)
if err != nil {
return domain.OddMarketWithSettings{}, err
}
return convertedOdd, nil
}
func (s *Store) GetOddsByEventID(ctx context.Context, upcomingID string, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) {
odds, err := s.queries.GetOddsByEventID(ctx, dbgen.GetOddsByEventIDParams{
EventID: upcomingID,
Limit: filter.Limit.ToPG(),
Offset: filter.Offset.ToPG(),
IsLive: pgtype.Bool{
Bool: false,
Valid: true,
},
Offset: pgtype.Int4{
Int32: int32(offset.Value),
Valid: offset.Valid,
Status: pgtype.Text{
String: string(domain.STATUS_PENDING),
Valid: true,
},
Source: pgtype.Text{},
})
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,
}
domainOdds, err := domain.ConvertDBOddMarkets(odds)
if err != nil {
return nil, err
}
return domainOdds, nil
}
func (s *Store) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string) ([]domain.Odd, error) {
func (s *Store) GetOddsWithSettingsByEventID(ctx context.Context, upcomingID string, companyID int64, filter domain.OddMarketFilter) ([]domain.OddMarketWithSettings, error) {
odds, err := s.queries.GetPrematchOddsByUpcomingID(ctx, upcomingID)
odds, err := s.queries.GetOddsWithSettingsByEventID(ctx, dbgen.GetOddsWithSettingsByEventIDParams{
EventID: upcomingID,
CompanyID: companyID,
Offset: filter.Offset.ToPG(),
Limit: filter.Limit.ToPG(),
})
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,
}
domainOdds, err := domain.ConvertDBOddMarketWithSettings(odds)
if err != nil {
return nil, err
}
return domainOdds, nil
}
func (s *Store) DeleteOddsForEvent(ctx context.Context, eventID string) error {
return s.queries.DeleteOddsForEvent(ctx, pgtype.Text{
String: eventID,
Valid: true,
})
return s.queries.DeleteOddsForEvent(ctx, eventID)
}
func getString(v interface{}) string {

View File

@ -8,93 +8,34 @@ import (
"github.com/jackc/pgx/v5/pgtype"
)
func convertDBResult(result dbgen.Result) domain.Result {
scores := make(map[string]domain.Score)
return domain.Result{
ID: result.ID,
BetOutcomeID: result.BetOutcomeID,
EventID: result.EventID,
OddID: result.OddID,
MarketID: result.MarketID,
Status: domain.OutcomeStatus(result.Status),
Score: result.Score.String,
FullTimeScore: result.FullTimeScore.String,
HalfTimeScore: result.HalfTimeScore.String,
SS: result.Ss.String,
Scores: scores,
CreatedAt: result.CreatedAt.Time,
UpdatedAt: result.UpdatedAt.Time,
}
}
func convertCreateResult(result domain.CreateResult) dbgen.CreateResultParams {
return dbgen.CreateResultParams{
BetOutcomeID: result.BetOutcomeID,
EventID: result.EventID,
OddID: result.OddID,
MarketID: result.MarketID,
Status: int32(result.Status),
Score: pgtype.Text{String: result.Score},
}
}
func convertResult(result domain.Result) dbgen.InsertResultParams {
return dbgen.InsertResultParams{
BetOutcomeID: result.BetOutcomeID,
EventID: result.EventID,
OddID: result.OddID,
MarketID: result.MarketID,
Status: int32(result.Status),
Score: pgtype.Text{String: result.Score},
FullTimeScore: pgtype.Text{String: result.FullTimeScore},
HalfTimeScore: pgtype.Text{String: result.HalfTimeScore},
Ss: pgtype.Text{String: result.SS},
}
}
func (s *Store) CreateResult(ctx context.Context, result domain.CreateResult) (domain.Result, error) {
dbResult, err := s.queries.CreateResult(ctx, convertCreateResult(result))
func (s *Store) CreateResultLog(ctx context.Context, result domain.CreateResultLog) (domain.ResultLog, error) {
dbResult, err := s.queries.CreateResultLog(ctx, domain.ConvertCreateResultLog(result))
if err != nil {
return domain.Result{}, err
return domain.ResultLog{}, err
}
return convertDBResult(dbResult), nil
return domain.ConvertDBResultLog(dbResult), nil
}
func (s *Store) InsertResult(ctx context.Context, result domain.Result) error {
return s.queries.InsertResult(ctx, convertResult(result))
}
func (s *Store) GetResultByBetOutcomeID(ctx context.Context, betOutcomeID int64) (domain.Result, error) {
dbResult, err := s.queries.GetResultByBetOutcomeID(ctx, betOutcomeID)
if err != nil {
return domain.Result{}, err
}
return convertDBResult(dbResult), nil
}
func (s *Store) GetPendingBetOutcomes(ctx context.Context) ([]domain.BetOutcome, error) {
dbOutcomes, err := s.queries.GetPendingBetOutcomes(ctx)
func (s *Store) GetAllResultLog(ctx context.Context, filter domain.ResultFilter) ([]domain.ResultLog, error) {
dbResultLogs, err := s.queries.GetAllResultLog(ctx, dbgen.GetAllResultLogParams{
CreatedBefore: pgtype.Timestamp{
Time: filter.CreatedBefore.Value,
Valid: filter.CreatedBefore.Valid,
},
CreatedAfter: pgtype.Timestamp{
Time: filter.CreatedAfter.Value,
Valid: filter.CreatedAfter.Valid,
},
})
if err != nil {
return nil, err
}
outcomes := make([]domain.BetOutcome, 0, len(dbOutcomes))
for _, dbOutcome := range dbOutcomes {
outcomes = append(outcomes, domain.BetOutcome{
ID: dbOutcome.ID,
BetID: dbOutcome.BetID,
EventID: dbOutcome.EventID,
OddID: dbOutcome.OddID,
HomeTeamName: dbOutcome.HomeTeamName,
AwayTeamName: dbOutcome.AwayTeamName,
MarketID: dbOutcome.MarketID,
MarketName: dbOutcome.MarketName,
Odd: dbOutcome.Odd,
OddName: dbOutcome.OddName,
OddHeader: dbOutcome.OddHeader,
OddHandicap: dbOutcome.OddHandicap,
Status: domain.OutcomeStatus(dbOutcome.Status),
Expires: dbOutcome.Expires.Time,
})
result := make([]domain.ResultLog, 0, len(dbResultLogs))
for _, dbResultLog := range dbResultLogs {
result = append(result, domain.ConvertDBResultLog(dbResultLog))
}
return outcomes, nil
return result, nil
}

View File

@ -2,116 +2,24 @@ package repository
import (
"context"
"fmt"
"strconv"
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"go.uber.org/zap"
)
func GetDBSettingList(settings []dbgen.Setting) (domain.SettingList, error) {
var dbSettingList domain.DBSettingList
var int64SettingsMap = domain.ConvertInt64SettingsMap(&dbSettingList)
var stringSettingsMap = domain.ConvertStringSettingsMap(&dbSettingList)
var boolSettingsMap = domain.ConvertBoolSettingsMap(&dbSettingList)
var float32SettingsMap = domain.ConvertFloat32SettingsMap(&dbSettingList)
var timeSettingsMap = domain.ConvertTimeSettingsMap(&dbSettingList)
for _, setting := range settings {
is_setting_unknown := true
for key, dbSetting := range int64SettingsMap {
if setting.Key == key {
value, err := strconv.ParseInt(setting.Value, 10, 64)
if err != nil {
return domain.SettingList{}, err
}
*dbSetting = domain.ValidInt64{
Value: value,
Valid: true,
}
is_setting_unknown = false
}
}
for key, dbSetting := range stringSettingsMap {
if setting.Key == key {
*dbSetting = domain.ValidString{
Value: setting.Value,
Valid: true,
}
is_setting_unknown = false
}
}
for key, dbSetting := range boolSettingsMap {
if setting.Key == key {
value, err := strconv.ParseBool(setting.Value)
if err != nil {
return domain.SettingList{}, err
}
*dbSetting = domain.ValidBool{
Value: value,
Valid: true,
}
is_setting_unknown = false
}
}
for key, dbSetting := range float32SettingsMap {
if setting.Key == key {
value, err := strconv.ParseFloat(setting.Value, 32)
if err != nil {
return domain.SettingList{}, err
}
*dbSetting = domain.ValidFloat32{
Value: float32(value),
Valid: true,
}
is_setting_unknown = false
}
}
for key, dbSetting := range timeSettingsMap {
if setting.Key == key {
value, err := time.Parse(time.RFC3339, setting.Value)
if err != nil {
return domain.SettingList{}, err
}
*dbSetting = domain.ValidTime{
Value: value,
Valid: true,
}
is_setting_unknown = false
}
}
if is_setting_unknown {
domain.MongoDBLogger.Warn("unknown setting found on database", zap.String("setting", setting.Key))
}
}
for key, dbSetting := range int64SettingsMap {
if !dbSetting.Valid {
fmt.Printf("setting value not found on database: %v \n", key)
domain.MongoDBLogger.Warn("setting value not found on database", zap.String("setting", key))
}
}
return domain.ConvertDBSetting(dbSettingList), nil
}
func (s *Store) GetSettingList(ctx context.Context) (domain.SettingList, error) {
settings, err := s.queries.GetSettings(ctx)
func (s *Store) GetGlobalSettingList(ctx context.Context) (domain.SettingList, error) {
settings, err := s.queries.GetGlobalSettings(ctx)
if err != nil {
domain.MongoDBLogger.Error("failed to get all settings", zap.Error(err))
return domain.SettingList{}, err
}
return GetDBSettingList(settings)
return domain.ConvertDBGlobalSettingList(settings)
}
func (s *Store) GetSettings(ctx context.Context) ([]domain.Setting, error) {
settings, err := s.queries.GetSettings(ctx)
func (s *Store) GetGlobalSettings(ctx context.Context) ([]domain.Setting, error) {
settings, err := s.queries.GetGlobalSettings(ctx)
if err != nil {
domain.MongoDBLogger.Error("failed to get all settings", zap.Error(err))
@ -129,8 +37,8 @@ func (s *Store) GetSettings(ctx context.Context) ([]domain.Setting, error) {
return result, nil
}
func (s *Store) GetSetting(ctx context.Context, key string) (domain.Setting, error) {
dbSetting, err := s.queries.GetSetting(ctx, key)
func (s *Store) GetGlobalSetting(ctx context.Context, key string) (domain.Setting, error) {
dbSetting, err := s.queries.GetGlobalSetting(ctx, key)
if err != nil {
domain.MongoDBLogger.Error("failed to get all settings", zap.Error(err))
@ -145,23 +53,121 @@ func (s *Store) GetSetting(ctx context.Context, key string) (domain.Setting, err
return result, nil
}
func (s *Store) SaveSetting(ctx context.Context, key, value string) (domain.Setting, error) {
dbSetting, err := s.queries.SaveSetting(ctx, dbgen.SaveSettingParams{
func (s *Store) UpdateGlobalSetting(ctx context.Context, key, value string) error {
err := s.queries.UpdateGlobalSetting(ctx, dbgen.UpdateGlobalSettingParams{
Key: key,
Value: value,
})
if err != nil {
domain.MongoDBLogger.Error("failed to update setting", zap.String("key", key), zap.String("value", value), zap.Error(err))
domain.MongoDBLogger.Error("failed to update setting",
zap.String("key", key),
zap.String("value", value),
zap.Error(err),
)
return domain.Setting{}, err
return err
}
setting := domain.Setting{
Key: dbSetting.Key,
Value: dbSetting.Value,
}
return setting, err
return err
}
func (s *Store) UpdateGlobalSettingList(ctx context.Context, settingList domain.ValidSettingList) error {
convertedSettings := settingList.ConvertAllSettings()
for _, setting := range convertedSettings {
err := s.UpdateGlobalSetting(ctx, setting.Key, setting.Value)
if err != nil {
domain.MongoDBLogger.Warn("failed to update setting list", zap.String("key", setting.Key), zap.Error(err))
return err
}
}
return nil
}
func (s *Store) InsertCompanySetting(ctx context.Context, key, value string, companyID int64) error {
err := s.queries.InsertCompanySetting(ctx, dbgen.InsertCompanySettingParams{
CompanyID: companyID,
Key: key,
Value: value,
})
if err != nil {
return err
}
return nil
}
func (s *Store) InsertCompanySettingList(ctx context.Context, settingList domain.ValidSettingList, companyID int64) error {
convertedSettings := settingList.ConvertAllSettings()
for _, setting := range convertedSettings {
err := s.InsertCompanySetting(ctx, setting.Key, setting.Value, companyID)
if err != nil {
domain.MongoDBLogger.Warn("failed to update setting list", zap.String("key", setting.Key), zap.Error(err))
return err
}
}
return nil
}
func (s *Store) GetAllCompanySettings(ctx context.Context) ([]domain.CompanySetting, error) {
settings, err := s.queries.GetAllCompanySettings(ctx)
if err != nil {
return nil, err
}
return domain.ConvertCompanySettings(settings), nil
}
func (s *Store) GetCompanySettingsByKey(ctx context.Context, key string) ([]domain.CompanySetting, error) {
settings, err := s.queries.GetCompanySettingsByKey(ctx, key)
if err != nil {
return nil, err
}
return domain.ConvertCompanySettings(settings), nil
}
func (s *Store) GetOverrideSettings(ctx context.Context, companyID int64) ([]domain.Setting, error) {
settings, err := s.queries.GetOverrideSettings(ctx, companyID)
if err != nil {
return nil, err
}
result := make([]domain.Setting, 0, len(settings))
for _, setting := range settings {
result = append(result, domain.Setting{
Key: setting.Key,
Value: setting.Value,
UpdatedAt: setting.UpdatedAt.Time,
})
}
return result, nil
}
func (s *Store) GetOverrideSettingsList(ctx context.Context, companyID int64) (domain.SettingList, error) {
settings, err := s.queries.GetOverrideSettings(ctx, companyID)
if err != nil {
return domain.SettingList{}, err
}
return domain.ConvertDBOverrideSettingList(settings)
}
func (s *Store) DeleteCompanySetting(ctx context.Context, companyID int64, key string) error {
return s.queries.DeleteCompanySetting(ctx, dbgen.DeleteCompanySettingParams{
CompanyID: companyID,
Key: key,
})
}
func (s *Store) DeleteAllCompanySetting(ctx context.Context, companyID int64,) error {
return s.queries.DeleteAllCompanySetting(ctx, companyID)
}

View File

@ -24,7 +24,7 @@ func convertDBShopBetDetail(bet dbgen.ShopBetDetail) domain.ShopBetDetail {
var outcomes []domain.BetOutcome = make([]domain.BetOutcome, 0, len(bet.Outcomes))
for _, outcome := range bet.Outcomes {
outcomes = append(outcomes, convertDBBetOutcomes(outcome))
outcomes = append(outcomes, domain.ConvertDBBetOutcomes(outcome))
}
return domain.ShopBetDetail{
ID: bet.ID,

View File

@ -13,6 +13,7 @@ func convertDBTicket(ticket dbgen.Ticket) domain.Ticket {
ID: ticket.ID,
Amount: domain.Currency(ticket.Amount),
TotalOdds: ticket.TotalOdds,
CompanyID: ticket.CompanyID,
}
}
@ -71,6 +72,7 @@ func convertCreateTicket(ticket domain.CreateTicket) dbgen.CreateTicketParams {
Amount: int64(ticket.Amount),
TotalOdds: ticket.TotalOdds,
Ip: ticket.IP,
CompanyID: ticket.CompanyID,
}
}
@ -110,8 +112,8 @@ func (s *Store) GetTicketByID(ctx context.Context, id int64) (domain.GetTicket,
return convertDBTicketOutcomes(ticket), nil
}
func (s *Store) GetAllTickets(ctx context.Context) ([]domain.GetTicket, error) {
tickets, err := s.queries.GetAllTickets(ctx)
func (s *Store) GetAllTickets(ctx context.Context, filter domain.TicketFilter) ([]domain.GetTicket, error) {
tickets, err := s.queries.GetAllTickets(ctx, filter.CompanyID.ToPG())
if err != nil {
return nil, err
}

View File

@ -46,6 +46,8 @@ func (s *Store) CreateUser(ctx context.Context, user domain.User, usedOtpId int6
Time: time.Now(),
Valid: true,
},
CompanyID: user.CompanyID.ToPG(),
Suspended: user.Suspended,
})
if err != nil {
return domain.User{}, err
@ -57,6 +59,15 @@ func (s *Store) CreateUser(ctx context.Context, user domain.User, usedOtpId int6
Email: userRes.Email.String,
PhoneNumber: userRes.PhoneNumber.String,
Role: domain.Role(userRes.Role),
CompanyID: domain.ValidInt64{
Value: userRes.CompanyID.Int64,
Valid: userRes.CompanyID.Valid,
},
EmailVerified: userRes.EmailVerified,
PhoneVerified: userRes.PhoneVerified,
CreatedAt: userRes.CreatedAt.Time,
UpdatedAt: userRes.UpdatedAt.Time,
Suspended: userRes.Suspended,
}, nil
}
func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error) {
@ -247,18 +258,14 @@ func (s *Store) GetCashiersByBranch(ctx context.Context, branchID int64) ([]doma
func (s *Store) SearchUserByNameOrPhone(ctx context.Context, searchString string, role *domain.Role, companyID domain.ValidInt64) ([]domain.User, error) {
query := dbgen.SearchUserByNameOrPhoneParams{
Column1: pgtype.Text{
CompanyID: companyID.ToPG(),
Column2: pgtype.Text{
String: searchString,
Valid: true,
},
CompanyID: pgtype.Int8{
Int64: companyID.Value,
Valid: companyID.Valid,
},
}
if role != nil {
query.Role = pgtype.Text{
String: string(*role),
Valid: true,
@ -340,7 +347,7 @@ func (s *Store) DeleteUser(ctx context.Context, id int64) error {
}
return nil
}
func (s *Store) CheckPhoneEmailExist(ctx context.Context, phoneNum, email string) (bool, bool, error) {
func (s *Store) CheckPhoneEmailExist(ctx context.Context, phoneNum, email string, companyID domain.ValidInt64) (bool, bool, error) {
row, err := s.queries.CheckPhoneEmailExist(ctx, dbgen.CheckPhoneEmailExistParams{
PhoneNumber: pgtype.Text{
@ -352,6 +359,7 @@ func (s *Store) CheckPhoneEmailExist(ctx context.Context, phoneNum, email string
Valid: email != "",
},
CompanyID: companyID.ToPG(),
})
if err != nil {
@ -360,10 +368,13 @@ func (s *Store) CheckPhoneEmailExist(ctx context.Context, phoneNum, email string
return row.EmailExists, row.PhoneExists, nil
}
func (s *Store) GetUserByEmail(ctx context.Context, email string) (domain.User, error) {
user, err := s.queries.GetUserByEmail(ctx, pgtype.Text{
String: email,
Valid: true,
func (s *Store) GetUserByEmail(ctx context.Context, email string, companyID domain.ValidInt64) (domain.User, error) {
user, err := s.queries.GetUserByEmail(ctx, dbgen.GetUserByEmailParams{
Email: pgtype.Text{
String: email,
Valid: true,
},
CompanyID: companyID.ToPG(),
})
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
@ -386,10 +397,13 @@ func (s *Store) GetUserByEmail(ctx context.Context, email string) (domain.User,
SuspendedAt: user.SuspendedAt.Time,
}, nil
}
func (s *Store) GetUserByPhone(ctx context.Context, phoneNum string) (domain.User, error) {
user, err := s.queries.GetUserByPhone(ctx, pgtype.Text{
String: phoneNum,
Valid: true,
func (s *Store) GetUserByPhone(ctx context.Context, phoneNum string, companyID domain.ValidInt64) (domain.User, error) {
user, err := s.queries.GetUserByPhone(ctx, dbgen.GetUserByPhoneParams{
PhoneNumber: pgtype.Text{
String: phoneNum,
Valid: true,
},
CompanyID: companyID.ToPG(),
})
if err != nil {
if errors.Is(err, sql.ErrNoRows) {

View File

@ -26,8 +26,8 @@ type LoginSuccess struct {
CompanyID domain.ValidInt64
}
func (s *Service) Login(ctx context.Context, email, phone string, password string) (LoginSuccess, error) {
user, err := s.userStore.GetUserByEmailPhone(ctx, email, phone)
func (s *Service) Login(ctx context.Context, email, phone string, password string, companyID domain.ValidInt64) (LoginSuccess, error) {
user, err := s.userStore.GetUserByEmailPhone(ctx, email, phone, companyID)
if err != nil {
return LoginSuccess{}, err
}

View File

@ -7,7 +7,7 @@ import (
)
type UserStore interface {
GetUserByEmailPhone(ctx context.Context, email, phone string) (domain.User, error)
GetUserByEmailPhone(ctx context.Context, email, phone string, companyID domain.ValidInt64) (domain.User, error)
}
type TokenStore interface {
CreateRefreshToken(ctx context.Context, rt domain.RefreshToken) error

View File

@ -133,7 +133,7 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI
return domain.CreateBetOutcome{}, ErrEventHasNotEnded
}
odds, err := s.prematchSvc.GetRawOddsByMarketID(ctx, marketIDStr, eventIDStr)
odds, err := s.prematchSvc.GetOddsByMarketID(ctx, marketIDStr, eventIDStr)
if err != nil {
s.mongoLogger.Error("failed to get raw odds by market ID",
zap.Int64("event_id", eventID),
@ -215,8 +215,8 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI
return newOutcome, nil
}
func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID int64, role domain.Role, companyID domain.ValidInt64) (domain.CreateBetRes, error) {
settingsList, err := s.settingSvc.GetSettingList(ctx)
func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID int64, role domain.Role, companyID int64) (domain.CreateBetRes, error) {
settingsList, err := s.settingSvc.GetOverrideSettingsList(ctx, companyID)
if err != nil {
return domain.CreateBetRes{}, err
@ -297,6 +297,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
OutcomesHash: outcomesHash,
FastCode: fastCode,
UserID: userID,
CompanyID: companyID,
}
switch role {
@ -347,7 +348,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
return domain.CreateBetRes{}, err
}
if companyID.Valid && branch.CompanyID == companyID.Value {
if branch.CompanyID == companyID {
s.mongoLogger.Warn("unauthorized company",
zap.Int64("branch_id", *req.BranchID),
zap.Error(err),
@ -375,6 +376,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
)
return domain.CreateBetRes{}, err
}
//
default:
s.mongoLogger.Error("unknown role type",
zap.String("role", string(role)),
@ -477,7 +479,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
}
}
res := domain.ConvertCreateBet(bet, rows)
res := domain.ConvertCreateBetRes(bet, rows)
return res, nil
}
@ -581,7 +583,7 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
var newOdds []domain.CreateBetOutcome
var totalOdds float32 = 1
markets, err := s.prematchSvc.GetPrematchOddsByUpcomingID(ctx, eventID)
markets, err := s.prematchSvc.GetOddsByEventID(ctx, eventID, domain.OddMarketWithEventFilter{})
if err != nil {
s.logger.Error("failed to get odds for event", "event id", eventID, "error", err)
s.mongoLogger.Error("failed to get odds for event",
@ -603,7 +605,7 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
return nil, 0, fmt.Errorf("empty odds or event %v", eventID)
}
var selectedMarkets []domain.Odd
var selectedMarkets []domain.OddMarket
numMarkets = min(numMarkets, len(markets))
for i := 0; i < numMarkets; i++ {
randomIndex := random.Intn(len(markets))
@ -714,7 +716,7 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
return newOdds, totalOdds, nil
}
func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, leagueID, sportID domain.ValidInt32, firstStartTime, lastStartTime domain.ValidTime) (domain.CreateBetRes, error) {
func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID, companyID int64, leagueID domain.ValidInt64, sportID domain.ValidInt32, firstStartTime, lastStartTime domain.ValidTime) (domain.CreateBetRes, error) {
// Get a unexpired event id
@ -742,7 +744,7 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
}
// TODO: Add the option of passing number of created events
var selectedUpcomingEvents []domain.UpcomingEvent
var selectedUpcomingEvents []domain.BaseEvent
numEventsPerBet := min(random.Intn(4)+1, len(events)) //Eliminate the option of 0
for i := 0; i < int(numEventsPerBet); i++ {
@ -816,6 +818,7 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
TotalOdds: totalOdds,
Status: domain.OUTCOME_STATUS_PENDING,
UserID: userID,
CompanyID: companyID,
IsShopBet: true,
FastCode: fastCode,
}
@ -842,7 +845,7 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
return domain.CreateBetRes{}, err
}
res := domain.ConvertCreateBet(bet, rows)
res := domain.ConvertCreateBetRes(bet, rows)
s.mongoLogger.Info("Random bets placed successfully",
zap.Int64("userID", userID),
@ -987,6 +990,8 @@ func (s *Service) SendWinningStatusNotification(ctx context.Context, status doma
betNotification := &domain.Notification{
RecipientID: userID,
DeliveryStatus: domain.DeliveryStatusPending,
IsRead: false,
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
Level: domain.NotificationLevelSuccess,
Reciever: domain.NotificationRecieverSideCustomer,
@ -1028,6 +1033,8 @@ func (s *Service) SendLosingStatusNotification(ctx context.Context, status domai
betNotification := &domain.Notification{
RecipientID: userID,
DeliveryStatus: domain.DeliveryStatusPending,
IsRead: false,
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
Level: domain.NotificationLevelSuccess,
Reciever: domain.NotificationRecieverSideCustomer,
@ -1070,6 +1077,8 @@ func (s *Service) SendErrorStatusNotification(ctx context.Context, status domain
betNotification := &domain.Notification{
RecipientID: userID,
DeliveryStatus: domain.DeliveryStatusPending,
IsRead: false,
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
Level: domain.NotificationLevelSuccess,
Reciever: domain.NotificationRecieverSideCustomer,
@ -1104,11 +1113,15 @@ func (s *Service) SendAdminErrorAlertNotification(ctx context.Context, status do
switch status {
case domain.OUTCOME_STATUS_ERROR, domain.OUTCOME_STATUS_PENDING:
headline = "There was an error with your bet"
message = "We have encounter an error with your bet. We will fix it as soon as we can"
headline = "There was an error processing bet"
message = "We have encounter an error with bet. We will fix it as soon as we can"
}
errorSeverity := domain.NotificationErrorSeverityHigh
betNotification := &domain.Notification{
ErrorSeverity: &errorSeverity,
DeliveryStatus: domain.DeliveryStatusPending,
IsRead: false,
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
Level: domain.NotificationLevelSuccess,
Reciever: domain.NotificationRecieverSideCustomer,
@ -1300,7 +1313,7 @@ func (s *Service) SetBetToRemoved(ctx context.Context, id int64) error {
}
func (s *Service) ProcessBetCashback(ctx context.Context) error {
settingsList, err := s.settingSvc.GetSettingList(ctx)
bets, err := s.betStore.GetBetsForCashback(ctx)
if err != nil {
s.mongoLogger.Error("failed to fetch bets",
@ -1309,6 +1322,7 @@ func (s *Service) ProcessBetCashback(ctx context.Context) error {
return err
}
for _, bet := range bets {
shouldProcess := true
loseCount := 0
@ -1349,6 +1363,8 @@ func (s *Service) ProcessBetCashback(ctx context.Context) error {
)
continue
}
settingsList, err := s.settingSvc.GetOverrideSettingsList(ctx, bet.CompanyID)
cashbackAmount := math.Min(float64(settingsList.CashbackAmountCap.Float32()), float64(calculateCashbackAmount(bet.Amount.Float32(), bet.TotalOdds)))
_, err = s.walletSvc.AddToWallet(ctx, wallets.StaticID, domain.ToCurrency(float32(cashbackAmount)), domain.ValidInt64{}, domain.TRANSFER_DIRECT,

View File

@ -11,6 +11,7 @@ type CompanyStore interface {
GetAllCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.GetCompany, error)
SearchCompanyByName(ctx context.Context, name string) ([]domain.GetCompany, error)
GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany, error)
GetCompanyIDBySlug(ctx context.Context, slug string) (int64, error)
UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error)
DeleteCompany(ctx context.Context, id int64) error

View File

@ -26,6 +26,9 @@ func (s *Service) GetAllCompanies(ctx context.Context, filter domain.CompanyFilt
func (s *Service) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany, error) {
return s.companyStore.GetCompanyByID(ctx, id)
}
func (s *Service) GetCompanyIDBySlug(ctx context.Context, slug string) (int64, error){
return s.companyStore.GetCompanyIDBySlug(ctx, slug)
}
func (s *Service) SearchCompanyByName(ctx context.Context, name string) ([]domain.GetCompany, error) {
return s.companyStore.SearchCompanyByName(ctx, name)

View File

@ -7,14 +7,18 @@ import (
)
type Service interface {
FetchLiveEvents(ctx context.Context) error
// FetchLiveEvents(ctx context.Context) error
FetchUpcomingEvents(ctx context.Context) error
GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, error)
GetPaginatedUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, int64, error)
GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error)
GetAllUpcomingEvents(ctx context.Context) ([]domain.BaseEvent, error)
GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.BaseEvent, error)
GetPaginatedUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.BaseEvent, int64, error)
GetUpcomingEventByID(ctx context.Context, ID string) (domain.BaseEvent, error)
// GetAndStoreMatchResult(ctx context.Context, eventID string) error
UpdateFinalScore(ctx context.Context, eventID, fullScore string, status domain.EventStatus) error
UpdateEventStatus(ctx context.Context, eventID string, status domain.EventStatus) error
UpdateFeatured(ctx context.Context, eventID string, flagged bool) error
IsEventMonitored(ctx context.Context, eventID string) (bool, error)
UpdateEventMonitored(ctx context.Context, eventID string, IsMonitored bool) error
GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error)
GetEventWithSettingByID(ctx context.Context, ID string, companyID int64) (domain.EventWithSettings, error)
UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error
}

View File

@ -32,162 +32,162 @@ func New(token string, store *repository.Store, mongoLogger *zap.Logger) Service
}
}
func (s *service) FetchLiveEvents(ctx context.Context) error {
var wg sync.WaitGroup
urls := []struct {
name string
source string
}{
{"https://api.b365api.com/v1/bet365/inplay?sport_id=%d&token=%s", "bet365"},
{"https://api.b365api.com/v1/betfair/sb/inplay?sport_id=%d&token=%s", "betfair"},
{"https://api.b365api.com/v1/1xbet/inplay?sport_id=%d&token=%s", "1xbet"},
}
// func (s *service) FetchLiveEvents(ctx context.Context) error {
// var wg sync.WaitGroup
// urls := []struct {
// name string
// source string
// }{
// {"https://api.b365api.com/v1/bet365/inplay?sport_id=%d&token=%s", "bet365"},
// {"https://api.b365api.com/v1/betfair/sb/inplay?sport_id=%d&token=%s", "betfair"},
// {"https://api.b365api.com/v1/1xbet/inplay?sport_id=%d&token=%s", "1xbet"},
// }
for _, url := range urls {
wg.Add(1)
// for _, url := range urls {
// wg.Add(1)
go func() {
defer wg.Done()
s.fetchLiveEvents(ctx, url.name, url.source)
}()
}
wg.Wait()
return nil
}
// go func() {
// defer wg.Done()
// s.fetchLiveEvents(ctx, url.name, url.source)
// }()
// }
// wg.Wait()
// return nil
// }
func (s *service) fetchLiveEvents(ctx context.Context, url, source string) 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}
// func (s *service) fetchLiveEvents(ctx context.Context, url, source string) 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}
var wg sync.WaitGroup
// var wg sync.WaitGroup
for _, sportID := range sportIDs {
wg.Add(1)
go func(sportID int) {
defer wg.Done()
// for _, sportID := range sportIDs {
// wg.Add(1)
// go func(sportID int) {
// defer wg.Done()
url := fmt.Sprintf(url, sportID, s.token)
resp, err := http.Get(url)
if err != nil {
fmt.Printf(" Failed request for sport_id=%d: %v\n", sportID, err)
return
}
defer resp.Body.Close()
// url := fmt.Sprintf(url, sportID, s.token)
// resp, err := http.Get(url)
// if err != nil {
// fmt.Printf(" Failed request for sport_id=%d: %v\n", sportID, err)
// return
// }
// defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
// body, _ := io.ReadAll(resp.Body)
events := []domain.Event{}
switch source {
case "bet365":
events = handleBet365prematch(body, sportID, source)
case "betfair":
events = handleBetfairprematch(body, sportID, source)
case "1xbet":
// betfair and 1xbet have the same result structure
events = handleBetfairprematch(body, sportID, source)
}
// events := []domain.Event{}
// switch source {
// case "bet365":
// events = handleBet365prematch(body, sportID, source)
// case "betfair":
// events = handleBetfairprematch(body, sportID, source)
// case "1xbet":
// // betfair and 1xbet have the same result structure
// events = handleBetfairprematch(body, sportID, source)
// }
for _, event := range events {
if err := s.store.SaveEvent(ctx, event); err != nil {
fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err)
}
}
}(sportID)
}
// for _, event := range events {
// if err := s.store.SaveEvent(ctx, event); err != nil {
// fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err)
// }
// }
// }(sportID)
// }
wg.Wait()
fmt.Println("All live events fetched and stored.")
return nil
// wg.Wait()
// fmt.Println("All live events fetched and stored.")
// return nil
}
// }
func handleBet365prematch(body []byte, sportID int, source string) []domain.Event {
var data struct {
Success int `json:"success"`
Results [][]map[string]interface{} `json:"results"`
}
// func handleBet365prematch(body []byte, sportID int, source string) []domain.Event {
// var data struct {
// Success int `json:"success"`
// Results [][]map[string]interface{} `json:"results"`
// }
events := []domain.Event{}
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
fmt.Printf("%s: Decode failed for sport_id=%d\nRaw: %s\n", source, sportID, string(body))
return events
}
// events := []domain.Event{}
// if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
// fmt.Printf("%s: Decode failed for sport_id=%d\nRaw: %s\n", source, sportID, string(body))
// return events
// }
for _, group := range data.Results {
for _, ev := range group {
if getString(ev["type"]) != "EV" {
continue
}
// for _, group := range data.Results {
// for _, ev := range group {
// if getString(ev["type"]) != "EV" {
// continue
// }
event := domain.Event{
ID: getString(ev["ID"]),
SportID: int32(sportID),
MatchName: getString(ev["NA"]),
Score: getString(ev["SS"]),
MatchMinute: getInt(ev["TM"]),
TimerStatus: getString(ev["TT"]),
HomeTeamID: getInt32(ev["HT"]),
AwayTeamID: getInt32(ev["AT"]),
HomeKitImage: getString(ev["K1"]),
AwayKitImage: getString(ev["K2"]),
LeagueName: getString(ev["CT"]),
LeagueID: getInt32(ev["C2"]),
LeagueCC: getString(ev["CB"]),
StartTime: time.Now().UTC().Format(time.RFC3339),
IsLive: true,
Status: "live",
MatchPeriod: getInt(ev["MD"]),
AddedTime: getInt(ev["TA"]),
Source: source,
}
// event := domain.Event{
// ID: getString(ev["ID"]),
// SportID: int32(sportID),
// MatchName: getString(ev["NA"]),
// Score: getString(ev["SS"]),
// MatchMinute: getInt(ev["TM"]),
// TimerStatus: getString(ev["TT"]),
// HomeTeamID: getInt32(ev["HT"]),
// AwayTeamID: getInt32(ev["AT"]),
// HomeKitImage: getString(ev["K1"]),
// AwayKitImage: getString(ev["K2"]),
// LeagueName: getString(ev["CT"]),
// LeagueID: getInt32(ev["C2"]),
// LeagueCC: getString(ev["CB"]),
// StartTime: time.Now().UTC().Format(time.RFC3339),
// IsLive: true,
// Status: "live",
// MatchPeriod: getInt(ev["MD"]),
// AddedTime: getInt(ev["TA"]),
// Source: source,
// }
events = append(events, event)
}
}
// events = append(events, event)
// }
// }
return events
}
// return events
// }
func handleBetfairprematch(body []byte, sportID int, source string) []domain.Event {
var data struct {
Success int `json:"success"`
Results []map[string]interface{} `json:"results"`
}
// func handleBetfairprematch(body []byte, sportID int, source string) []domain.Event {
// var data struct {
// Success int `json:"success"`
// Results []map[string]interface{} `json:"results"`
// }
events := []domain.Event{}
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
fmt.Printf("%s: Decode failed for sport_id=%d\nRaw: %s\n", source, sportID, string(body))
return events
}
// events := []domain.Event{}
// if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
// fmt.Printf("%s: Decode failed for sport_id=%d\nRaw: %s\n", source, sportID, string(body))
// return events
// }
for _, ev := range data.Results {
homeRaw, _ := ev["home"].(map[string]interface{})
awayRaw, _ := ev["home"].(map[string]interface{})
// for _, ev := range data.Results {
// homeRaw, _ := ev["home"].(map[string]interface{})
// awayRaw, _ := ev["home"].(map[string]interface{})
event := domain.Event{
ID: getString(ev["id"]),
SportID: int32(sportID),
TimerStatus: getString(ev["time_status"]),
HomeTeamID: getInt32(homeRaw["id"]),
AwayTeamID: getInt32(awayRaw["id"]),
StartTime: time.Now().UTC().Format(time.RFC3339),
IsLive: true,
Status: "live",
Source: source,
}
// event := domain.Event{
// ID: getString(ev["id"]),
// SportID: int32(sportID),
// TimerStatus: getString(ev["time_status"]),
// HomeTeamID: getInt32(homeRaw["id"]),
// AwayTeamID: getInt32(awayRaw["id"]),
// StartTime: time.Now().UTC().Format(time.RFC3339),
// IsLive: true,
// Status: "live",
// Source: source,
// }
events = append(events, event)
}
// events = append(events, event)
// }
return events
}
// return events
// }
func (s *service) FetchUpcomingEvents(ctx context.Context) error {
var wg sync.WaitGroup
urls := []struct {
name string
source string
source domain.EventSource
}{
{"https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s&page=%d", "bet365"},
{"https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s&page=%d", domain.EVENT_SOURCE_BET365},
// {"https://api.b365api.com/v1/betfair/sb/upcoming?sport_id=%d&token=%s&page=%d", "betfair"},
// {"https://api.b365api.com/v1/1xbet/upcoming?sport_id=%d&token=%s&page=%d", "1xbet"},
}
@ -205,83 +205,70 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error {
return nil
}
func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_url, source string) {
func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_url string, source domain.EventSource) {
const pageLimit int = 200
sportIDs := []int{1, 18, 17, 3, 83, 15, 12, 19, 8, 16, 91}
// sportIDs := []int{1}
// TODO: Add the league skipping again when we have dynamic leagues
// b, err := os.OpenFile("logs/skipped_leagues.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
// if err != nil {
// log.Printf("❌ Failed to open leagues file %v", err)
// return
// }
for sportIndex, sportID := range sportIDs {
var totalPages int = 1
var page int = 0
var limit int = 200
var count int = 0
var skippedLeague []string
var totalEvents = 0
logger := s.mongoLogger.With(
zap.String("source", string(source)),
zap.Int("sport_id", sportID),
zap.String("sport_name", domain.Sport(sportID).String()),
zap.Int("count", count),
zap.Int("totalEvents", totalEvents),
zap.Int("Skipped leagues", len(skippedLeague)),
)
for page <= totalPages {
page = page + 1
url := fmt.Sprintf(source_url, sportID, s.token, page)
log.Printf("📡 Fetching data from %s - sport %d (%d/%d), for event data page (%d/%d)",
source, sportID, sportIndex+1, len(sportIDs), page, totalPages)
eventLogger := logger.With(
zap.Int("page", page),
zap.Int("total_pages", totalPages),
)
resp, err := http.Get(url)
if err != nil {
s.mongoLogger.Error(
"Failed to fetch event data for page",
zap.String("source", source),
zap.Int("sport_id", sportID),
zap.Int("page", page),
zap.Int("total_pages", totalPages),
zap.Error(err),
)
eventLogger.Error("Failed to fetch event data for page", zap.Error(err))
continue
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var data domain.BetResult
body, err := io.ReadAll(resp.Body)
if err != nil {
eventLogger.Error("Failed to read event response body", zap.Error(err))
continue
}
var data domain.B365UpcomingRes
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
s.mongoLogger.Error(
"Failed to parse event json data",
zap.String("source", source),
zap.Int("sport_id", sportID),
zap.Int("page", page),
zap.Int("total_pages", totalPages),
zap.Error(err),
)
eventLogger.Error("Failed to parse event json data", zap.Error(err))
continue
}
for _, ev := range data.Results {
startUnix, err := strconv.ParseInt(ev.Time, 10, 64)
dataLogger := eventLogger.With(
zap.String("time", ev.Time),
zap.String("leagueID", ev.League.ID),
zap.String("leagueName", ev.League.Name),
)
if err != nil {
s.mongoLogger.Error(
"Invalid time",
zap.String("time", ev.Time),
zap.String("source", source),
zap.Int("sport_id", sportID),
zap.Int("page", page),
zap.Int("total_pages", totalPages),
zap.Error(err),
)
dataLogger.Error("Invalid time", zap.Error(err))
continue
}
leagueID, err := strconv.ParseInt(ev.League.ID, 10, 64)
if err != nil {
s.mongoLogger.Error(
"Invalid league id",
zap.String("leagueID", ev.League.ID),
zap.String("source", source),
zap.Int("sport_id", sportID),
zap.Int("page", page),
zap.Int("total_pages", totalPages),
zap.Error(err),
)
dataLogger.Error("Invalid league id", zap.Error(err))
continue
}
@ -289,74 +276,67 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_ur
// no this its fine to keep it here
// but change the league id to bet365 id later
//Automatically feature the league if its in the list
err = s.store.SaveLeague(ctx, domain.League{
ID: leagueID,
Name: ev.League.Name,
IsActive: true,
IsFeatured: slices.Contains(domain.FeaturedLeagues, leagueID),
SportID: convertInt32(ev.SportID),
err = s.store.SaveLeague(ctx, domain.CreateLeague{
ID: leagueID,
Name: ev.League.Name,
DefaultIsActive: true,
DefaultIsFeatured: slices.Contains(domain.FeaturedLeagues, leagueID),
SportID: convertInt32(ev.SportID),
})
if err != nil {
s.mongoLogger.Error(
"error while saving league",
zap.String("leagueID", ev.League.ID),
zap.String("leagueName", ev.League.Name),
zap.String("source", source),
zap.Int("sport_id", sportID),
zap.Int("page", page),
zap.Int("total_pages", totalPages),
zap.Error(err),
)
dataLogger.Error("error while saving league", zap.Error(err))
continue
}
if supported, err := s.store.CheckLeagueSupport(ctx, leagueID); !supported || err != nil {
s.mongoLogger.Warn(
"Skipping league",
zap.String("league", ev.League.Name),
zap.Bool("is_supported", supported),
zap.Error(err),
)
skippedLeague = append(skippedLeague, ev.League.Name)
continue
}
// Since the system is multi-vendor now, no events are going to be skipped
// if supported, err := s.store.CheckLeagueSupport(ctx, leagueID); !supported || err != nil {
// dataLogger.Warn(
// "Skipping league",
// zap.Bool("is_supported", supported),
// zap.Error(err),
// )
// skippedLeague = append(skippedLeague, ev.League.Name)
// continue
// }
event := domain.UpcomingEvent{
ID: ev.ID,
SportID: convertInt32(ev.SportID),
MatchName: "",
HomeTeam: ev.Home.Name,
AwayTeam: "", // handle nil safely
HomeTeamID: convertInt32(ev.Home.ID),
AwayTeamID: 0,
HomeKitImage: "",
AwayKitImage: "",
LeagueID: convertInt32(ev.League.ID),
LeagueName: ev.League.Name,
LeagueCC: "",
StartTime: time.Unix(startUnix, 0).UTC(),
Source: source,
event := domain.CreateEvent{
ID: ev.ID,
SportID: convertInt32(ev.SportID),
MatchName: "",
HomeTeam: ev.Home.Name,
AwayTeam: "", // handle nil safely
HomeTeamID: convertInt64(ev.Home.ID),
AwayTeamID: 0,
HomeTeamImage: "",
AwayTeamImage: "",
LeagueID: convertInt64(ev.League.ID),
LeagueName: ev.League.Name,
StartTime: time.Unix(startUnix, 0).UTC(),
Source: source,
IsLive: false,
Status: domain.STATUS_PENDING,
}
if ev.Away != nil {
dataLogger.Info("event away is empty")
event.AwayTeam = ev.Away.Name
event.AwayTeamID = convertInt32(ev.Away.ID)
event.AwayTeamID = convertInt64(ev.Away.ID)
event.MatchName = ev.Home.Name + " vs " + ev.Away.Name
}
ok, err := s.CheckAndInsertEventHistory(ctx, event)
err = s.store.SaveUpcomingEvent(ctx, event)
if err != nil {
s.mongoLogger.Error(
"failed to save upcoming event",
zap.String("leagueID", ev.League.ID),
zap.String("leagueName", ev.League.Name),
zap.String("source", source),
zap.Int("sport_id", sportID),
zap.Int("page", page),
zap.Int("total_pages", totalPages),
zap.Error(err),
)
dataLogger.Error("failed to check and insert event history", zap.Error(err))
}
if ok {
dataLogger.Info("event history has been recorded")
}
err = s.store.SaveEvent(ctx, event)
if err != nil {
dataLogger.Error("failed to save upcoming event", zap.Error(err))
}
totalEvents += 1
}
@ -366,7 +346,7 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_ur
totalPages = data.Pager.Total / data.Pager.PerPage
if count >= limit {
if count >= pageLimit {
break
}
if page > totalPages {
@ -376,7 +356,7 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_ur
}
s.mongoLogger.Info(
"Successfully fetched upcoming events",
zap.String("source", source),
zap.String("source", string(source)),
zap.Int("totalEvents", totalEvents),
zap.Int("sport_id", sportID),
zap.String("sport_name", domain.Sport(sportID).String()),
@ -388,6 +368,49 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_ur
}
}
func (s *service) CheckAndInsertEventHistory(ctx context.Context, event domain.CreateEvent) (bool, error) {
isEventMonitored, err := s.store.IsEventMonitored(ctx, event.ID)
eventLogger := s.mongoLogger.With(
zap.String("eventID", event.ID),
zap.Int64("leagueID", event.LeagueID),
zap.String("leagueName", event.LeagueName),
zap.Int32("sport_id", event.SportID),
)
if err != nil {
eventLogger.Error("failed to get event is_monitored", zap.Error(err))
return false, err
}
if !isEventMonitored {
return false, nil
}
oldEvent, err := s.GetUpcomingEventByID(ctx, event.ID)
if err != nil {
eventLogger.Error("failed to get event by id", zap.Error(err))
return false, err
}
if oldEvent.Status != event.Status {
_, err := s.store.InsertEventHistory(ctx, domain.CreateEventHistory{
EventID: event.ID,
Status: string(event.Status),
})
if err != nil {
eventLogger.Error("failed to get event by id", zap.Error(err))
return false, err
}
return true, nil
}
return false, nil
}
func getString(v interface{}) string {
if str, ok := v.(string); ok {
return str
@ -415,19 +438,25 @@ func convertInt32(num string) int32 {
}
return 0
}
func (s *service) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error) {
func convertInt64(num string) int64 {
if n, err := strconv.Atoi(num); err == nil {
return int64(n)
}
return 0
}
func (s *service) GetAllUpcomingEvents(ctx context.Context) ([]domain.BaseEvent, error) {
return s.store.GetAllUpcomingEvents(ctx)
}
func (s *service) GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, error) {
func (s *service) GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.BaseEvent, error) {
return s.store.GetExpiredUpcomingEvents(ctx, filter)
}
func (s *service) GetPaginatedUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, int64, error) {
func (s *service) GetPaginatedUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.BaseEvent, int64, error) {
return s.store.GetPaginatedUpcomingEvents(ctx, filter)
}
func (s *service) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
func (s *service) GetUpcomingEventByID(ctx context.Context, ID string) (domain.BaseEvent, error) {
return s.store.GetUpcomingEventByID(ctx, ID)
}
@ -438,41 +467,20 @@ func (s *service) UpdateEventStatus(ctx context.Context, eventID string, status
return s.store.UpdateEventStatus(ctx, eventID, status)
}
func (s *service) UpdateFeatured(ctx context.Context, eventID string, flagged bool) error {
return s.store.UpdateFeatured(ctx, eventID, flagged)
func (s *service) IsEventMonitored(ctx context.Context, eventID string) (bool, error) {
return s.store.IsEventMonitored(ctx, eventID)
}
func (s *service) UpdateEventMonitored(ctx context.Context, eventID string, IsMonitored bool) error {
return s.store.UpdateEventMonitored(ctx, eventID, IsMonitored)
}
// func (s *service) GetAndStoreMatchResult(ctx context.Context, eventID string) error {
// url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%s", s.token, eventID)
func (s *service) GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) {
return s.store.GetEventsWithSettings(ctx, companyID, filter)
}
// resp, err := http.Get(url)
// if err != nil {
// return fmt.Errorf("failed to fetch result: %w", err)
// }
// defer resp.Body.Close()
// body, _ := io.ReadAll(resp.Body)
// // Parse the API response
// var apiResp struct {
// Results []struct {
// ID string `json:"id"`
// Ss string `json:"ss"` // Full-time score
// Status string `json:"time_status"`
// } `json:"results"`
// }
// err = json.Unmarshal(body, &apiResp)
// if err != nil || len(apiResp.Results) == 0 {
// return fmt.Errorf("invalid response or no results found")
// }
// result := apiResp.Results[0]
// err = s.store.UpdateFinalScore(ctx, result.ID, result.Ss, result.Status)
// if err != nil {
// return fmt.Errorf("failed to update final score in database: %w", err)
// }
// return nil
// }
func (s *service) GetEventWithSettingByID(ctx context.Context, ID string, companyID int64) (domain.EventWithSettings, error) {
return s.store.GetEventWithSettingByID(ctx, ID, companyID)
}
func (s *service) UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error {
return s.store.UpdateEventSettings(ctx, event)
}

View File

@ -7,9 +7,10 @@ import (
)
type Service interface {
SaveLeague(ctx context.Context, l domain.League) error
GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.League, error)
GetFeaturedLeagues(ctx context.Context) ([]domain.League, error)
SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) error
SaveLeague(ctx context.Context, league domain.CreateLeague) error
SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error
GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error)
GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, error)
CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error)
UpdateLeague(ctx context.Context, league domain.UpdateLeague) error
}

View File

@ -17,20 +17,24 @@ func New(store *repository.Store) Service {
}
}
func (s *service) SaveLeague(ctx context.Context, l domain.League) error {
return s.store.SaveLeague(ctx, l)
func (s *service) SaveLeague(ctx context.Context, league domain.CreateLeague) error {
return s.store.SaveLeague(ctx, league)
}
func (s *service) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.League, error) {
func (s *service) SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error {
return s.store.SaveLeagueSettings(ctx, leagueSettings)
}
func (s *service) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) {
return s.store.GetAllLeagues(ctx, filter)
}
func (s *service) GetFeaturedLeagues(ctx context.Context) ([]domain.League, error) {
return s.store.GetFeaturedLeagues(ctx)
func (s *service) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, error) {
return s.store.GetAllLeaguesByCompany(ctx, companyID, filter)
}
func (s *service) SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) error {
return s.store.SetLeagueActive(ctx, leagueId, isActive)
func (s *service) CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error) {
return s.store.CheckLeagueSupport(ctx, leagueID, companyID)
}
func (s *service) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error {

View File

@ -15,12 +15,24 @@ var (
ErrSMSProviderNotFound = errors.New("SMS Provider Not Found")
)
func (s *Service) SendSMS(ctx context.Context, receiverPhone, message string) error {
// If the company id is valid, it is a company based notification else its a global notification (by the super admin)
func (s *Service) SendSMS(ctx context.Context, receiverPhone, message string, companyID domain.ValidInt64) error {
settingsList, err := s.settingSvc.GetSettingList(ctx)
var settingsList domain.SettingList
var err error
if err != nil {
return err
if companyID.Valid {
settingsList, err = s.settingSvc.GetOverrideSettingsList(ctx, companyID.Value)
if err != nil {
// TODO: Send a log about the error
return err
}
} else {
settingsList, err = s.settingSvc.GetGlobalSettingList(ctx)
if err != nil {
// TODO: Send a log about the error
return err
}
}
switch settingsList.SMSProvider {

View File

@ -340,7 +340,7 @@ func (s *Service) SendNotificationSMS(ctx context.Context, recipientID int64, me
if user.PhoneNumber == "" {
return fmt.Errorf("Phone Number is invalid")
}
err = s.messengerSvc.SendSMS(ctx, user.PhoneNumber, message)
err = s.messengerSvc.SendSMS(ctx, user.PhoneNumber, message, user.CompanyID)
if err != nil {
return err
}

View File

@ -0,0 +1,29 @@
package odds
// import (
// "context"
// "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
// )
// func (s *ServiceImpl) InsertCustomOdds(ctx context.Context, odd domain.CreateCustomOdd) (domain.CustomOdd, error) {
// return s.store.InsertCustomOdds(ctx, odd)
// }
// func (s *ServiceImpl) GetAllCustomOdds(ctx context.Context, filter domain.CustomOddFilter) ([]domain.CustomOdd, error){
// return s.store.GetAllCustomOdds(ctx, filter)
// }
// func (s *ServiceImpl) GetCustomOddByID(ctx context.Context, id int64) (domain.CustomOdd, error){
// return s.store.GetCustomOddByID(ctx, id)
// }
// func (s *ServiceImpl) GetCustomOddByOddID(ctx context.Context, oddId int64, companyID int64) (domain.CustomOdd, error){
// return s.store.GetCustomOddByOddID(ctx, oddId, companyID)
// }
// func (s *ServiceImpl) DeleteCustomOddByID(ctx context.Context, id int64) error{
// return s.store.DeleteCustomOddByID(ctx, id)
// }
// func (s *ServiceImpl) DeleteCustomOddsByOddID(ctx context.Context, oddId int64, companyID int64) error{
// return s.store.DeleteCustomOddsByOddID(ctx, oddId, companyID)
// }
// func (s *ServiceImpl) DeleteCustomOddByEventID(ctx context.Context, eventID string) error{
// return s.store.DeleteCustomOddByEventID(ctx, eventID)
// }

View File

@ -0,0 +1,28 @@
package odds
import (
"context"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)
func (s *ServiceImpl) InsertDisabledOdd(ctx context.Context, odd domain.CreateDisabledOdd) (domain.DisabledOdd, error) {
return s.store.InsertDisabledOdd(ctx, odd)
}
func (s *ServiceImpl) GetAllDisabledOdds(ctx context.Context) ([]domain.DisabledOdd, error) {
return s.store.GetAllDisabledOdds(ctx)
}
func (s *ServiceImpl) GetDisabledOddByRawOddID(ctx context.Context, rawOddID int64) (domain.DisabledOdd, error) {
return s.store.GetDisabledOddByRawOddID(ctx, rawOddID)
}
func (s *ServiceImpl) GetDisabledOddByID(ctx context.Context, id int64) (domain.DisabledOdd, error) {
return s.store.GetDisabledOddByID(ctx, id)
}
func (s *ServiceImpl) DeleteDisabledOddsByID(ctx context.Context, id int64) error {
return s.store.DeleteDisabledOddsByID(ctx, id)
}
func (s *ServiceImpl) DeleteDisabledOddsByRawOddID(ctx context.Context, id int64) error {
return s.store.DeleteDisabledOddsByRawOddID(ctx, id)
}

View File

@ -0,0 +1,15 @@
package odds
import (
"context"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)
func (s *ServiceImpl) GetAllOddHistory(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error) {
return s.store.GetAllOddHistory(ctx, filter)
}
func (s *ServiceImpl) GetInitialOddPerDay(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error) {
return s.store.GetInitialOddPerDay(ctx, filter)
}

View File

@ -11,10 +11,32 @@ type Service interface {
FetchNonLiveOdds(ctx context.Context) error
FetchNonLiveOddsByEventID(ctx context.Context, eventIDStr string) (domain.BaseNonLiveOddResponse, error)
ParseOddSections(ctx context.Context, res json.RawMessage, sportID int64) (domain.ParseOddSectionsRes, error)
GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error)
GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string) ([]domain.Odd, error)
GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit domain.ValidInt64, offset domain.ValidInt64) ([]domain.Odd, error)
GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error)
GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.RawOddsByMarketID, error)
GetPrematchOdds(ctx context.Context, eventID string) ([]domain.OddMarket, error)
GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string) ([]domain.OddMarket, error)
GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit domain.ValidInt64, offset domain.ValidInt64) ([]domain.OddMarket, error)
GetALLPrematchOdds(ctx context.Context) ([]domain.OddMarket, error)
// GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.OddMarket, error)
DeleteOddsForEvent(ctx context.Context, eventID string) error
// Odd History
InsertOddHistory(ctx context.Context, odd domain.CreateOddHistory) (domain.OddHistory, error)
GetAllOddHistory(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error)
GetInitialOddPerDay(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error)
// Disabling Odds
InsertDisabledOdd(ctx context.Context, odd domain.CreateDisabledOdd) (domain.DisabledOdd, error)
GetAllDisabledOdds(ctx context.Context) ([]domain.DisabledOdd, error)
GetDisabledOddByRawOddID(ctx context.Context, rawOddID int64) (domain.DisabledOdd, error)
GetDisabledOddByID(ctx context.Context, id int64) (domain.DisabledOdd, error)
DeleteDisabledOddsByID(ctx context.Context, id int64) error
DeleteDisabledOddsByRawOddID(ctx context.Context, id int64) error
// Custom Odds
// InsertCustomOdds(ctx context.Context, odd domain.CreateCustomOdd) (domain.CustomOdd, error)
// GetAllCustomOdds(ctx context.Context, filter domain.CustomOddFilter) ([]domain.CustomOdd, error)
// GetCustomOddByID(ctx context.Context, id int64) (domain.CustomOdd, error)
// GetCustomOddByOddID(ctx context.Context, oddId int64, companyID int64) (domain.CustomOdd, error)
// DeleteCustomOddByID(ctx context.Context, id int64) error
// DeleteCustomOddsByOddID(ctx context.Context, oddId int64, companyID int64) error
// DeleteCustomOddByEventID(ctx context.Context, eventID string) error
}

View File

@ -16,21 +16,24 @@ import (
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
"go.uber.org/zap"
)
type ServiceImpl struct {
store *repository.Store
config *config.Config
eventSvc event.Service
logger *slog.Logger
mongoLogger *zap.Logger
client *http.Client
}
func New(store *repository.Store, cfg *config.Config, logger *slog.Logger, mongoLogger *zap.Logger) *ServiceImpl {
func New(store *repository.Store, cfg *config.Config, eventSvc event.Service, logger *slog.Logger, mongoLogger *zap.Logger) *ServiceImpl {
return &ServiceImpl{
store: store,
config: cfg,
eventSvc: eventSvc,
logger: logger,
mongoLogger: mongoLogger,
client: &http.Client{Timeout: 10 * time.Second},
@ -76,7 +79,7 @@ func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
}
func (s *ServiceImpl) fetchBet365Odds(ctx context.Context) error {
eventIDs, err := s.store.GetAllUpcomingEvents(ctx)
eventIDs, err := s.eventSvc.GetAllUpcomingEvents(ctx)
if err != nil {
s.mongoLogger.Error(
"Failed to fetch upcoming event IDs",
@ -161,115 +164,117 @@ func (s *ServiceImpl) fetchBet365Odds(ctx context.Context) error {
return nil
}
func (s *ServiceImpl) fetchBwinOdds(ctx context.Context) error {
// getting odds for a specific event is not possible for bwin, most specific we can get is fetch odds on a single sport
// so instead of having event and odds fetched separetly event will also be fetched along with the odds
sportIds := []int{4, 12, 7}
for _, sportId := range sportIds {
url := fmt.Sprintf("https://api.b365api.com/v1/bwin/prematch?sport_id=%d&token=%s", sportId, s.config.Bet365Token)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
s.mongoLogger.Error(
"Failed to create request for sportId",
zap.Int("sportID", sportId),
zap.Error(err),
)
continue
}
// func (s *ServiceImpl) fetchBwinOdds(ctx context.Context) error {
// // getting odds for a specific event is not possible for bwin, most specific we can get is fetch odds on a single sport
// // so instead of having event and odds fetched separetly event will also be fetched along with the odds
// sportIds := []int{4, 12, 7}
// for _, sportId := range sportIds {
// url := fmt.Sprintf("https://api.b365api.com/v1/bwin/prematch?sport_id=%d&token=%s", sportId, s.config.Bet365Token)
// req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
// if err != nil {
// s.mongoLogger.Error(
// "Failed to create request for sportId",
// zap.Int("sportID", sportId),
// zap.Error(err),
// )
// continue
// }
resp, err := s.client.Do(req)
if err != nil {
s.mongoLogger.Error(
"Failed to fetch request for sportId",
zap.Int("sportID", sportId),
zap.Error(err),
)
continue
}
defer resp.Body.Close()
// resp, err := s.client.Do(req)
// if err != nil {
// s.mongoLogger.Error(
// "Failed to fetch request for sportId",
// zap.Int("sportID", sportId),
// zap.Error(err),
// )
// continue
// }
// defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
s.mongoLogger.Error(
"Failed to read response body for sportId",
zap.Int("sportID", sportId),
zap.Error(err),
)
continue
}
// body, err := io.ReadAll(resp.Body)
// if err != nil {
// s.mongoLogger.Error(
// "Failed to read response body for sportId",
// zap.Int("sportID", sportId),
// zap.Error(err),
// )
// continue
// }
var data struct {
Success int `json:"success"`
Results []map[string]interface{} `json:"results"`
}
// var data struct {
// Success int `json:"success"`
// Results []map[string]interface{} `json:"results"`
// }
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
fmt.Printf("Decode failed for sport_id=%d\nRaw: %s\n", sportId, string(body))
s.mongoLogger.Error(
"Failed to decode BWin response body",
zap.Int("sportID", sportId),
zap.Error(err),
)
continue
}
// if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
// fmt.Printf("Decode failed for sport_id=%d\nRaw: %s\n", sportId, string(body))
// s.mongoLogger.Error(
// "Failed to decode BWin response body",
// zap.Int("sportID", sportId),
// zap.Error(err),
// )
// continue
// }
for _, res := range data.Results {
if getInt(res["Id"]) == -1 {
continue
}
// for _, res := range data.Results {
// if getInt(res["Id"]) == -1 {
// continue
// }
event := domain.Event{
ID: strconv.Itoa(getInt(res["Id"])),
SportID: int32(getInt(res["SportId"])),
LeagueID: int32(getInt(res["LeagueId"])),
LeagueName: getString(res["Leaguename"]),
HomeTeam: getString(res["HomeTeam"]),
HomeTeamID: int32(getInt(res["HomeTeamId"])),
AwayTeam: getString(res["AwayTeam"]),
AwayTeamID: int32(getInt(res["AwayTeamId"])),
StartTime: time.Now().UTC().Format(time.RFC3339),
TimerStatus: "1",
IsLive: true,
Status: "live",
Source: "bwin",
}
// event := domain.CreateEvent{
// ID: strconv.Itoa(getInt(res["Id"])),
// SportID: int32(getInt(res["SportId"])),
// LeagueID: int64(getInt(res["LeagueId"])),
// LeagueName: getString(res["Leaguename"]),
// HomeTeam: getString(res["HomeTeam"]),
// HomeTeamID: int64(getInt(res["HomeTeamId"])),
// AwayTeam: getString(res["AwayTeam"]),
// AwayTeamID: int64(getInt(res["AwayTeamId"])),
// StartTime: time.Now().UTC(),
// IsLive: true,
// Status: domain.STATUS_IN_PLAY,
// Source: domain.EVENT_SOURCE_BWIN,
// MatchName: "",
// HomeTeamImage: "",
// AwayTeamImage: "",
// }
if err := s.store.SaveEvent(ctx, event); err != nil {
fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err)
s.mongoLogger.Error(
"Could not store live event",
zap.Int("sportID", sportId),
zap.String("eventID", event.ID),
zap.Error(err),
)
continue
}
// if err := s.store.SaveEvent(ctx, event); err != nil {
// fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err)
// s.mongoLogger.Error(
// "Could not store live event",
// zap.Int("sportID", sportId),
// zap.String("eventID", event.ID),
// zap.Error(err),
// )
// continue
// }
for _, market := range []string{"Markets, optionMarkets"} {
for _, m := range getMapArray(res[market]) {
name := getMap(m["name"])
marketName := getString(name["value"])
// for _, market := range []string{"Markets, optionMarkets"} {
// for _, m := range getMapArray(res[market]) {
// name := getMap(m["name"])
// marketName := getString(name["value"])
market := domain.Market{
EventID: event.ID,
MarketID: getString(m["id"]),
MarketCategory: getString(m["category"]),
MarketName: marketName,
Source: "bwin",
}
// market := domain.CreateOddMarket{
// EventID: event.ID,
// MarketID: getString(m["id"]),
// MarketCategory: getString(m["category"]),
// MarketName: marketName,
results := getMapArray(m["results"])
market.Odds = results
// }
s.store.SaveNonLiveMarket(ctx, market)
// results := getMapArray(m["results"])
// market.Odds = results
}
}
}
// s.store.SaveOddMarket(ctx, market)
}
return nil
}
// }
// }
// }
// }
// return nil
// }
func (s *ServiceImpl) FetchNonLiveOddsByEventID(ctx context.Context, eventIDStr string) (domain.BaseNonLiveOddResponse, error) {
@ -542,7 +547,7 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
}
// Check if the market id is a string
marketIDint := market.ID.Int64
marketIDint := market.ID.Value
// if err != nil {
// s.mongoLogger.Error(
// "Invalid market id",
@ -576,9 +581,8 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
continue
}
marketRecord := domain.Market{
marketRecord := domain.CreateOddMarket{
EventID: eventID,
FI: fi,
MarketCategory: sectionName,
MarketType: marketType,
MarketName: market.Name,
@ -586,10 +590,20 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
UpdatedAt: updatedAt,
Odds: marketOdds,
// bwin won't reach this code so bet365 is hardcoded for now
Source: "bet365",
}
err = s.store.SaveNonLiveMarket(ctx, marketRecord)
if err := s.CheckAndInsertOddHistory(ctx, marketRecord); err != nil {
s.mongoLogger.Error(
"failed to check and insert odd history",
zap.String("market_id", marketIDstr),
zap.String("market_name", market.Name),
zap.String("eventID", eventID),
zap.Error(err),
)
continue
}
err = s.store.SaveOddMarket(ctx, marketRecord)
if err != nil {
s.mongoLogger.Error(
"failed to save market",
@ -598,7 +612,7 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
zap.String("eventID", eventID),
zap.Error(err),
)
errs = append(errs, fmt.Errorf("market %s: %w", market.ID, err))
errs = append(errs, fmt.Errorf("market %v: %w", market.ID, err))
continue
}
}
@ -609,29 +623,111 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
return nil
}
func (s *ServiceImpl) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
return s.store.GetPrematchOdds(ctx, eventID)
}
func (s *ServiceImpl) CheckAndInsertOddHistory(ctx context.Context, market domain.CreateOddMarket) error {
isEventMonitored, err := s.eventSvc.IsEventMonitored(ctx, market.EventID)
func (s *ServiceImpl) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) {
return s.store.GetALLPrematchOdds(ctx)
}
func (s *ServiceImpl) GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.RawOddsByMarketID, error) {
rows, err := s.store.GetRawOddsByMarketID(ctx, marketID, upcomingID)
marketLogger := s.mongoLogger.With(
zap.String("market_id", market.MarketID),
zap.String("market_name", market.MarketName),
zap.String("eventID", market.EventID),
)
if err != nil {
return domain.RawOddsByMarketID{}, err
marketLogger.Error("failed to get is_monitored", zap.Error(err))
}
if !isEventMonitored {
return nil
}
oldOdds, err := s.store.GetOddsByMarketID(ctx, market.MarketID, market.EventID)
if err != nil {
marketLogger.Error("failed to get raw odds by market id", zap.Error(err))
return err
}
if len(oldOdds.RawOdds) != len(market.Odds) {
marketLogger.Error("new odds data does not match old odds data", zap.Error(err))
return fmt.Errorf("new odds data does not match old odds data")
}
oldRawOdds, err := convertRawMessage(oldOdds.RawOdds)
if err != nil {
marketLogger.Error("failed to convert raw odds to map", zap.Error(err))
return err
}
for _, oddData := range market.Odds {
newRawOddID := getInt(oddData["id"])
newOddsVal := getFloat(oddData["odds"])
isFound := false
for _, oldOddData := range oldRawOdds {
oldRawOddID := getInt(oldOddData["id"])
oldOddsVal := getFloat(oldOddData["odds"])
if newRawOddID == oldRawOddID {
if newOddsVal != oldOddsVal {
_, err := s.store.InsertOddHistory(ctx, domain.CreateOddHistory{
OddID: oldOdds.ID,
MarketID: market.MarketID,
RawOddID: int64(newRawOddID),
EventID: market.EventID,
OddValue: newOddsVal,
})
if err != nil {
s.mongoLogger.Error(
"failed to insert odd history",
zap.String("market_id", market.MarketID),
zap.String("market_name", market.MarketName),
zap.String("eventID", market.EventID),
zap.Int64("odd_id", oldOdds.ID),
zap.Int("raw_odd_id", newRawOddID),
zap.Error(err),
)
}
}
isFound = true
}
}
if !isFound {
fmt.Printf("raw odd id %d not found", newRawOddID)
}
}
return nil
}
func (s *ServiceImpl) GetAllOdds(ctx context.Context, filter domain.OddMarketFilter) ([]domain.OddMarket, error) {
return s.store.GetAllOdds(ctx, filter)
}
func (s *ServiceImpl) GetAllOddsWithSettings(ctx context.Context, companyID int64, filter domain.OddMarketFilter) ([]domain.OddMarketWithSettings, error) {
return s.store.GetAllOddsWithSettings(ctx, companyID, filter)
}
func (s *ServiceImpl) GetOddsByMarketID(ctx context.Context, marketID string, eventID string) (domain.OddMarket, error) {
rows, err := s.store.GetOddsByMarketID(ctx, marketID, eventID)
if err != nil {
return domain.OddMarket{}, err
}
return rows, nil
}
func (s *ServiceImpl) GetOddsWithSettingsByMarketID(ctx context.Context, marketID string, eventID string, companyID int64) (domain.OddMarketWithSettings, error) {
rows, err := s.store.GetOddsWithSettingsByMarketID(ctx, marketID, eventID, companyID)
if err != nil {
return domain.OddMarketWithSettings{}, err
}
return rows, nil
}
func (s *ServiceImpl) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string) ([]domain.Odd, error) {
return s.store.GetPrematchOddsByUpcomingID(ctx, upcomingID)
func (s *ServiceImpl) GetOddsByEventID(ctx context.Context, upcomingID string, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) {
return s.store.GetOddsByEventID(ctx, upcomingID, filter)
}
func (s *ServiceImpl) GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset domain.ValidInt64) ([]domain.Odd, error) {
return s.store.GetPaginatedPrematchOddsByUpcomingID(ctx, upcomingID, limit, offset)
func (s *ServiceImpl) GetOddsWithSettingsByEventID(ctx context.Context, upcomingID string, companyID int64, filter domain.OddMarketFilter) ([]domain.OddMarketWithSettings, error) {
return s.store.GetOddsWithSettingsByEventID(ctx, upcomingID, companyID, filter)
}
func (s *ServiceImpl) DeleteOddsForEvent(ctx context.Context, eventID string) error {
@ -651,6 +747,12 @@ func getInt(v interface{}) int {
}
return -1
}
func getFloat(v interface{}) float64 {
if n, ok := v.(float64); ok {
return n
}
return 0
}
func getMap(v interface{}) map[string]interface{} {
if m, ok := v.(map[string]interface{}); ok {

View File

@ -9,7 +9,7 @@ import (
type ReferralStore interface {
GenerateReferralCode() (string, error)
CreateReferral(ctx context.Context, userID int64) error
ProcessReferral(ctx context.Context, referredID, referralCode string) error
ProcessReferral(ctx context.Context, referredPhone, referralCode string, companyID int64) error
ProcessDepositBonus(ctx context.Context, userID string, amount float64) error
GetReferralStats(ctx context.Context, userID string) (*domain.ReferralStats, error)
CreateReferralSettings(ctx context.Context, req domain.ReferralSettingsReq) error

View File

@ -107,7 +107,7 @@ func (s *Service) CreateReferral(ctx context.Context, userID int64) error {
return nil
}
func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCode string) error {
func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCode string, companyID int64) error {
s.logger.Info("Processing referral", "referredPhone", referredPhone, "referralCode", referralCode)
referral, err := s.repo.GetReferralByCode(ctx, referralCode)
@ -121,7 +121,10 @@ func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCo
return ErrInvalidReferral
}
user, err := s.store.GetUserByPhone(ctx, referredPhone)
user, err := s.store.GetUserByPhone(ctx, referredPhone, domain.ValidInt64{
Value: companyID,
Valid: true,
})
if err != nil {
if errors.Is(err, domain.ErrUserNotFound) {
s.logger.Warn("User not found for referral", "referredPhone", referredPhone)

View File

@ -2,9 +2,16 @@ package result
import (
"context"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)
type ResultService interface {
FetchAndProcessResults(ctx context.Context) error
FetchAndStoreResult(ctx context.Context, eventID string) error
}
type ResultLogStore interface {
CreateResultLog(ctx context.Context, result domain.CreateResultLog) (domain.ResultLog, error)
GetAllResultLog(ctx context.Context, filter domain.ResultFilter) ([]domain.ResultLog, error)
}

Some files were not shown because too many files have changed in this diff Show More