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/ app_logs/
backup/ backup/
reports/ reports/
exports/

View File

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

View File

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

View File

@ -1,59 +1,222 @@
BEGIN; BEGIN;
CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Users -- Users
INSERT INTO users ( INSERT INTO users (
id, first_name, last_name, email, phone_number, password, role, id,
email_verified, phone_verified, created_at, updated_at, suspended, company_id first_name,
) VALUES last_name,
(1, 'John', 'Doe', 'john.doe@example.com', NULL, email,
crypt('password123', gen_salt('bf'))::bytea, 'customer', phone_number,
TRUE, FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL), password,
role,
(2, 'Test', 'Admin', 'test.admin@gmail.com', '0988554466', email_verified,
crypt('password123', gen_salt('bf'))::bytea, 'admin', phone_verified,
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, 1), created_at,
updated_at,
(3, 'Samuel', 'Tariku', 'cybersamt@gmail.com', '0911111111', suspended,
crypt('password@123', gen_salt('bf'))::bytea, 'super_admin', company_id
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL), )
VALUES (
(4, 'Kirubel', 'Kibru', 'kirubel.jkl679@gmail.com', '0911554486', 1,
crypt('password@123', gen_salt('bf'))::bytea, 'super_admin', 'John',
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL); '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 -- Supported Operations
INSERT INTO supported_operations (id, name, description) VALUES INSERT INTO supported_operations (id, name, description)
(1, 'SportBook', 'Sportbook operations'), VALUES (1, 'SportBook', 'Sportbook operations'),
(2, 'Virtual', 'Virtual operations'); (2, 'Virtual', 'Virtual operations');
-- Wallets -- Wallets
INSERT INTO wallets ( INSERT INTO wallets (
id, balance, is_withdraw, is_bettable, is_transferable, user_id, id,
type, currency, is_active, created_at, updated_at balance,
) VALUES is_withdraw,
(1, 10000, TRUE, TRUE, TRUE, 1, 'regular', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), is_bettable,
(2, 5000, FALSE, TRUE, TRUE, 1, 'static', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), is_transferable,
(3, 20000, TRUE, TRUE, TRUE, 2, 'company_main', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), user_id,
(4, 15000, TRUE, TRUE, TRUE, 2, 'branch_main', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); 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 -- 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); VALUES (1, 1, 1, 2);
-- Company -- Company
INSERT INTO companies ( INSERT INTO companies (
id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at id,
) VALUES name,
(1, 'Test Company', 2, 3, 0.10, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); 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 -- Branch
INSERT INTO branches ( INSERT INTO branches (
id, name, location, wallet_id, branch_manager_id, company_id, id,
is_self_owned, profit_percent, is_active, created_at, updated_at name,
) VALUES location,
(1, 'Test Branch', 'addis_ababa', 4, 2, 1, TRUE, 0.10, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); wallet_id,
branch_manager_id,
COMMIT; 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 ( CHECK (
email IS NOT NULL email IS NOT NULL
OR phone_number 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 ( 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, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ updated_at TIMESTAMPTZ
); );
CREATE TABLE IF NOT EXISTS wallets ( CREATE TABLE IF NOT EXISTS wallets (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
balance BIGINT NOT NULL DEFAULT 0, balance BIGINT NOT NULL DEFAULT 0,
currency VARCHAR(3) NOT NULL DEFAULT 'ETB',
is_withdraw BOOLEAN NOT NULL, is_withdraw BOOLEAN NOT NULL,
is_bettable BOOLEAN NOT NULL, is_bettable BOOLEAN NOT NULL,
is_transferable BOOLEAN NOT NULL, is_transferable BOOLEAN NOT NULL,
@ -43,7 +45,6 @@ CREATE TABLE IF NOT EXISTS wallets (
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
); );
CREATE TABLE refresh_tokens ( CREATE TABLE refresh_tokens (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL, user_id BIGINT NOT NULL,
@ -53,26 +54,6 @@ CREATE TABLE refresh_tokens (
revoked BOOLEAN DEFAULT FALSE NOT NULL, revoked BOOLEAN DEFAULT FALSE NOT NULL,
CONSTRAINT unique_token UNIQUE (token) 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 ( CREATE TABLE otps (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
@ -87,6 +68,7 @@ CREATE TABLE otps (
); );
CREATE TABLE IF NOT EXISTS bets ( CREATE TABLE IF NOT EXISTS bets (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
company_id BIGINT NOT NULL,
amount BIGINT NOT NULL, amount BIGINT NOT NULL,
total_odds REAL NOT NULL, total_odds REAL NOT NULL,
status INT NOT NULL, status INT NOT NULL,
@ -101,6 +83,7 @@ CREATE TABLE IF NOT EXISTS bets (
); );
CREATE TABLE IF NOT EXISTS tickets ( CREATE TABLE IF NOT EXISTS tickets (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
company_id BIGINT NOT NULL,
amount BIGINT NOT NULL, amount BIGINT NOT NULL,
total_odds REAL NOT NULL, total_odds REAL NOT NULL,
IP VARCHAR(255) NOT NULL, IP VARCHAR(255) NOT NULL,
@ -122,14 +105,14 @@ CREATE TABLE IF NOT EXISTS bet_outcomes (
sport_id BIGINT NOT NULL, sport_id BIGINT NOT NULL,
event_id BIGINT NOT null, event_id BIGINT NOT null,
odd_id BIGINT NOT NULL, odd_id BIGINT NOT NULL,
home_team_name VARCHAR(255) NOT NULL, home_team_name TEXT NOT NULL,
away_team_name VARCHAR(255) NOT NULL, away_team_name TEXT NOT NULL,
market_id BIGINT NOT NULL, market_id BIGINT NOT NULL,
market_name VARCHAR(255) NOT NULL, market_name TEXT NOT NULL,
odd REAL NOT NULL, odd REAL NOT NULL,
odd_name VARCHAR(255) NOT NULL, odd_name TEXT NOT NULL,
odd_header VARCHAR(255) NOT NULL, odd_header TEXT NOT NULL,
odd_handicap VARCHAR(255) NOT NULL, odd_handicap TEXT NOT NULL,
status INT NOT NULL DEFAULT 0, status INT NOT NULL DEFAULT 0,
expires TIMESTAMP NOT NULL expires TIMESTAMP NOT NULL
); );
@ -138,14 +121,14 @@ CREATE TABLE IF NOT EXISTS ticket_outcomes (
ticket_id BIGINT NOT NULL, ticket_id BIGINT NOT NULL,
event_id BIGINT NOT null, event_id BIGINT NOT null,
odd_id BIGINT NOT NULL, odd_id BIGINT NOT NULL,
home_team_name VARCHAR(255) NOT NULL, home_team_name TEXT NOT NULL,
away_team_name VARCHAR(255) NOT NULL, away_team_name TEXT NOT NULL,
market_id BIGINT NOT NULL, market_id BIGINT NOT NULL,
market_name VARCHAR(255) NOT NULL, market_name TEXT NOT NULL,
odd REAL NOT NULL, odd REAL NOT NULL,
odd_name VARCHAR(255) NOT NULL, odd_name TEXT NOT NULL,
odd_header VARCHAR(255) NOT NULL, odd_header TEXT NOT NULL,
odd_handicap VARCHAR(255) NOT NULL, odd_handicap TEXT NOT NULL,
status INT NOT NULL DEFAULT 0, status INT NOT NULL DEFAULT 0,
expires TIMESTAMP NOT NULL expires TIMESTAMP NOT NULL
); );
@ -194,7 +177,7 @@ CREATE TABLE IF NOT EXISTS customer_wallets (
CREATE TABLE IF NOT EXISTS wallet_transfer ( CREATE TABLE IF NOT EXISTS wallet_transfer (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
amount BIGINT, amount BIGINT,
message VARCHAR(255) NOT NULL, message TEXT NOT NULL,
type VARCHAR(255), type VARCHAR(255),
receiver_wallet_id BIGINT, receiver_wallet_id BIGINT,
sender_wallet_id BIGINT, sender_wallet_id BIGINT,
@ -288,54 +271,115 @@ CREATE TABLE IF NOT EXISTS branch_locations (
); );
CREATE TABLE events ( CREATE TABLE events (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
sport_id INT, sport_id INT NOT NULL,
match_name TEXT, match_name TEXT NOT NULL,
home_team TEXT, home_team TEXT NOT NULL,
away_team TEXT, away_team TEXT NOT NULL,
home_team_id INT, home_team_id BIGINT NOT NULL,
away_team_id INT, away_team_id BIGINT NOT NULL,
home_kit_image TEXT, home_kit_image TEXT NOT NULL,
away_kit_image TEXT, away_kit_image TEXT NOT NULL,
league_id INT, league_id BIGINT NOT NULL,
league_name TEXT, league_name TEXT NOT NULL,
league_cc TEXT, start_time TIMESTAMP NOT NULL,
start_time TIMESTAMP,
score TEXT, score TEXT,
match_minute INT, match_minute INT,
timer_status TEXT, timer_status TEXT,
added_time INT, added_time INT,
match_period INT, match_period INT,
is_live BOOLEAN, is_live BOOLEAN NOT NULL DEFAULT false,
status TEXT, status TEXT NOT NULL,
fetched_at TIMESTAMP DEFAULT now(), fetched_at TIMESTAMP DEFAULT now(),
source TEXT DEFAULT 'b365api', source TEXT NOT NULL DEFAULT 'b365api' CHECK (
is_featured BOOLEAN NOT NULL DEFAULT FALSE, source IN (
is_active BOOLEAN NOT NULL DEFAULT TRUE '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 ( CREATE TABLE event_history (
id SERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
event_id TEXT, event_id TEXT NOT NULL,
fi TEXT, 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_type TEXT NOT NULL,
market_name TEXT, market_name TEXT NOT NULL,
market_category TEXT, market_category TEXT NOT NULL,
market_id TEXT, market_id TEXT NOT NULL,
name TEXT, raw_odds JSONB NOT NULL,
handicap TEXT, default_is_active BOOLEAN NOT NULL DEFAULT true,
odds_value DOUBLE PRECISION,
section TEXT NOT NULL,
category TEXT,
raw_odds JSONB,
fetched_at TIMESTAMP DEFAULT now(), fetched_at TIMESTAMP DEFAULT now(),
source TEXT DEFAULT 'b365api', expires_at TIMESTAMP NOT NULL,
is_active BOOLEAN DEFAULT true,
UNIQUE (market_id, name, handicap),
UNIQUE (event_id, market_id, name, handicap),
UNIQUE (event_id, market_id) 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 ( CREATE TABLE companies (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL, name TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
admin_id BIGINT NOT NULL, admin_id BIGINT NOT NULL,
wallet_id BIGINT NOT NULL, wallet_id BIGINT NOT NULL,
deducted_percentage REAL NOT NULL, deducted_percentage REAL NOT NULL,
@ -350,35 +394,53 @@ CREATE TABLE companies (
CREATE TABLE leagues ( CREATE TABLE leagues (
id BIGINT PRIMARY KEY, id BIGINT PRIMARY KEY,
name TEXT NOT NULL, name TEXT NOT NULL,
img TEXT, img_url TEXT,
country_code TEXT, country_code TEXT,
bet365_id INT, bet365_id INT,
sport_id INT NOT NULL, sport_id INT NOT NULL,
is_active BOOLEAN DEFAULT true, default_is_active BOOLEAN NOT NULL DEFAULT true,
is_featured BOOLEAN DEFAULT false 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 ( CREATE TABLE teams (
id TEXT PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
team_name TEXT NOT NULL, team_name TEXT NOT NULL,
country TEXT, country_code TEXT NOT NULL,
bet365_id INT, bet365_id BIGINT,
logo_url TEXT img_url TEXT
); );
CREATE TABLE IF NOT EXISTS settings ( CREATE TABLE IF NOT EXISTS global_settings (
key TEXT PRIMARY KEY, key TEXT PRIMARY KEY,
value TEXT NOT NULL, value TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_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 ( CREATE TABLE bonus (
id BIGSERIAL PRIMARY KEY,
multiplier REAL NOT NULL, multiplier REAL NOT NULL,
id BIGSERIAL PRIMARY KEY,
balance_cap BIGINT NOT NULL DEFAULT 0 balance_cap BIGINT NOT NULL DEFAULT 0
); );
CREATE TABLE flags ( CREATE TABLE flags (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
bet_id BIGINT REFERENCES bets(id) ON DELETE CASCADE, 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, reason TEXT,
flagged_at TIMESTAMP DEFAULT NOW(), flagged_at TIMESTAMP DEFAULT NOW(),
resolved BOOLEAN DEFAULT FALSE, resolved BOOLEAN DEFAULT FALSE,
@ -386,14 +448,30 @@ CREATE TABLE flags (
CHECK ( CHECK (
( (
bet_id IS NOT NULL bet_id IS NOT NULL
AND odd_id IS NULL AND odds_market_id IS NULL
) )
OR ( OR (
bet_id IS NULL 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 -- Views
CREATE VIEW companies_details AS CREATE VIEW companies_details AS
SELECT companies.*, SELECT companies.*,
@ -512,17 +590,64 @@ SELECT sd.*,
st.verified AS transaction_verified st.verified AS transaction_verified
FROM shop_deposits AS sd FROM shop_deposits AS sd
JOIN shop_transactions st ON st.id = sd.shop_transaction_id; 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 -- Foreign Keys
ALTER TABLE users
ADD CONSTRAINT unique_email UNIQUE (email),
ADD CONSTRAINT unique_phone_number UNIQUE (phone_number);
ALTER TABLE refresh_tokens ALTER TABLE refresh_tokens
ADD CONSTRAINT fk_refresh_tokens_users FOREIGN KEY (user_id) REFERENCES users(id); ADD CONSTRAINT fk_refresh_tokens_users FOREIGN KEY (user_id) REFERENCES users(id);
ALTER TABLE bets ALTER TABLE bets
ADD CONSTRAINT fk_bets_users FOREIGN KEY (user_id) REFERENCES users(id); ADD CONSTRAINT fk_bets_users FOREIGN KEY (user_id) REFERENCES users(id);
ALTER TABLE wallets ALTER TABLE wallets
ADD CONSTRAINT fk_wallets_users FOREIGN KEY (user_id) REFERENCES users(id), ADD CONSTRAINT fk_wallets_users FOREIGN KEY (user_id) REFERENCES users(id);
ADD COLUMN currency VARCHAR(3) NOT NULL DEFAULT 'ETB';
ALTER TABLE customer_wallets ALTER TABLE customer_wallets
ADD CONSTRAINT fk_customer_wallets_customers FOREIGN KEY (customer_id) REFERENCES users(id), 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), ADD CONSTRAINT fk_customer_wallets_regular_wallet FOREIGN KEY (regular_wallet_id) REFERENCES wallets(id),
@ -552,4 +677,13 @@ ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(i
ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE; ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE;
ALTER TABLE companies ALTER TABLE companies
ADD CONSTRAINT fk_companies_admin FOREIGN KEY (admin_id) REFERENCES users(id), 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; 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 -- Settings Initial Data
INSERT INTO settings (key, value) INSERT INTO global_settings (key, value)
VALUES ('sms_provider', '30'), VALUES ('sms_provider', 'afro_message'),
('max_number_of_outcomes', '30'), ('max_number_of_outcomes', '30'),
('bet_amount_limit', '10000000'), ('bet_amount_limit', '10000000'),
('daily_ticket_limit', '50'), ('daily_ticket_limit', '50'),

View File

@ -1,58 +1,218 @@
CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Users -- Users
INSERT INTO users ( INSERT INTO users (
id, first_name, last_name, email, phone_number, password, role, id,
email_verified, phone_verified, created_at, updated_at, suspended, company_id first_name,
) VALUES last_name,
(1, 'John', 'Doe', 'john.doe@example.com', NULL, email,
crypt('password123', gen_salt('bf'))::bytea, 'customer', phone_number,
TRUE, FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL), password,
role,
(2, 'Test', 'Admin', 'test.admin@gmail.com', '0988554466', email_verified,
crypt('password123', gen_salt('bf'))::bytea, 'admin', phone_verified,
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, 1), created_at,
updated_at,
(3, 'Samuel', 'Tariku', 'cybersamt@gmail.com', '0911111111', suspended,
crypt('password@123', gen_salt('bf'))::bytea, 'super_admin', company_id
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL), )
VALUES (
(4, 'Kirubel', 'Kibru', 'kirubel.jkl679@gmail.com', '0911554486', 1,
crypt('password@123', gen_salt('bf'))::bytea, 'super_admin', 'John',
TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, FALSE, NULL); '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 -- Supported Operations
INSERT INTO supported_operations (id, name, description) VALUES INSERT INTO supported_operations (id, name, description)
(1, 'SportBook', 'Sportbook operations'), VALUES (1, 'SportBook', 'Sportbook operations'),
(2, 'Virtual', 'Virtual operations'); (2, 'Virtual', 'Virtual operations');
-- Wallets -- Wallets
INSERT INTO wallets ( INSERT INTO wallets (
id, balance, is_withdraw, is_bettable, is_transferable, user_id, id,
type, currency, is_active, created_at, updated_at balance,
) VALUES is_withdraw,
(1, 10000, TRUE, TRUE, TRUE, 1, 'regular', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), is_bettable,
(2, 5000, FALSE, TRUE, TRUE, 1, 'static', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), is_transferable,
(3, 20000, TRUE, TRUE, TRUE, 2, 'company_main', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), user_id,
(4, 15000, TRUE, TRUE, TRUE, 2, 'branch_main', 'ETB', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); 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 -- 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); VALUES (1, 1, 1, 2);
-- Company -- Company
INSERT INTO companies ( INSERT INTO companies (
id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at id,
) VALUES name,
(1, 'Test Company', 2, 3, 0.10, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); 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 -- Branch
INSERT INTO branches ( INSERT INTO branches (
id, name, location, wallet_id, branch_manager_id, company_id, id,
is_self_owned, profit_percent, is_active, created_at, updated_at name,
) VALUES location,
(1, 'Test Branch', 'addis_ababa', 4, 2, 1, TRUE, 0.10, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); 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 -- name: GetUserByEmailPhone :one
SELECT * SELECT *
FROM users FROM users
WHERE email = $1 WHERE (
OR phone_number = $2; email = $1
OR phone_number = $2
)
AND (
company_id = sqlc.narg('company_id')
OR sqlc.narg('company_id') IS NULL
);
-- name: CreateRefreshToken :exec -- name: CreateRefreshToken :exec
INSERT INTO refresh_tokens (user_id, token, expires_at, created_at, revoked) INSERT INTO refresh_tokens (user_id, token, expires_at, created_at, revoked)
VALUES ($1, $2, $3, $4, $5); VALUES ($1, $2, $3, $4, $5);
-- name: GetRefreshToken :one -- name: GetRefreshToken :one
SELECT * SELECT *
FROM refresh_tokens FROM refresh_tokens

View File

@ -6,9 +6,10 @@ INSERT INTO bets (
user_id, user_id,
is_shop_bet, is_shop_bet,
outcomes_hash, 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 *; RETURNING *;
-- name: CreateBetOutcome :copyfrom -- name: CreateBetOutcome :copyfrom
INSERT INTO bet_outcomes ( INSERT INTO bet_outcomes (
@ -52,6 +53,10 @@ wHERE (
is_shop_bet = sqlc.narg('is_shop_bet') is_shop_bet = sqlc.narg('is_shop_bet')
OR sqlc.narg('is_shop_bet') IS NULL OR sqlc.narg('is_shop_bet') IS NULL
) )
AND (
company_id = sqlc.narg('company_id')
OR sqlc.narg('company_id') IS NULL
)
AND ( AND (
cashed_out = sqlc.narg('cashed_out') cashed_out = sqlc.narg('cashed_out')
OR sqlc.narg('cashed_out') IS NULL OR sqlc.narg('cashed_out') IS NULL
@ -148,4 +153,4 @@ DELETE FROM bets
WHERE id = $1; WHERE id = $1;
-- name: DeleteBetOutcome :exec -- name: DeleteBetOutcome :exec
DELETE FROM bet_outcomes DELETE FROM bet_outcomes
WHERE bet_id = $1; WHERE bet_id = $1;

View File

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

View File

@ -4,16 +4,55 @@ SELECT DATE_TRUNC('month', start_time) AS month,
FROM events FROM events
JOIN leagues ON leagues.id = events.league_id JOIN leagues ON leagues.id = events.league_id
WHERE ( 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') events.league_id = sqlc.narg('league_id')
OR sqlc.narg('league_id') IS NULL OR sqlc.narg('league_id') IS NULL
) )
GROUP BY month GROUP BY month
ORDER 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 -- name: CreateFlag :one
INSERT INTO flags ( INSERT INTO flags (
bet_id, bet_id,
odd_id, odds_market_id,
reason reason
) VALUES ( ) VALUES (
$1, $2, $3 $1, $2, $3

View File

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

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 -- name: InsertOddsMarket :exec
INSERT INTO odds ( INSERT INTO odds_market (
event_id, event_id,
fi,
market_type, market_type,
market_name, market_name,
market_category, market_category,
market_id, market_id,
name,
handicap,
odds_value,
section,
category,
raw_odds, raw_odds,
is_active, fetched_at,
source, expires_at
fetched_at
) )
VALUES ( VALUES (
$1, $1,
@ -24,95 +17,69 @@ VALUES (
$5, $5,
$6, $6,
$7, $7,
$8, $8
$9,
$10,
$11,
$12,
$13,
$14,
$15
) ON CONFLICT (event_id, market_id) DO ) ON CONFLICT (event_id, market_id) DO
UPDATE UPDATE
SET odds_value = EXCLUDED.odds_value, SET market_type = EXCLUDED.market_type,
raw_odds = EXCLUDED.raw_odds,
market_type = EXCLUDED.market_type,
market_name = EXCLUDED.market_name, market_name = EXCLUDED.market_name,
market_category = EXCLUDED.market_category, market_category = EXCLUDED.market_category,
name = EXCLUDED.name, raw_odds = EXCLUDED.raw_odds,
handicap = EXCLUDED.handicap,
fetched_at = EXCLUDED.fetched_at, fetched_at = EXCLUDED.fetched_at,
is_active = EXCLUDED.is_active, expires_at = EXCLUDED.expires_at;
source = EXCLUDED.source, -- name: InsertOddSettings :exec
fi = EXCLUDED.fi; INSERT INTO company_odd_settings (
-- name: GetPrematchOdds :many company_id,
SELECT event_id, odds_market_id,
fi, is_active,
market_type, custom_raw_odds
market_name, )
market_category, VALUES ($1, $2, $3, $4) ON CONFLICT (company_id, odds_market_id) DO
market_id, UPDATE
name, SET is_active = EXCLUDED.is_active,
handicap, custom_raw_odds = EXCLUDED.custom_raw_odds;
odds_value, -- name: GetAllOdds :many
section, SELECT *
category, FROM odds_market_with_event
raw_odds, LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
fetched_at, -- name: GetAllOddsWithSettings :many
source, SELECT *
is_active FROM odds_market_with_settings
FROM odds WHERE company_id = $1
WHERE is_active = true LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
AND source = 'bet365'; -- name: GetOddsByMarketID :one
-- name: GetALLPrematchOdds :many SELECT *
SELECT event_id, FROM odds_market_with_event
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
WHERE market_id = $1 WHERE market_id = $1
AND fi = $2 AND event_id = $2;
AND is_active = true -- name: GetOddsWithSettingsByMarketID :one
AND source = 'bet365'; SELECT *
-- name: GetPrematchOddsByUpcomingID :many FROM odds_market_with_settings
SELECT o.* WHERE market_id = $1
FROM odds o AND event_id = $2
JOIN events e ON o.fi = e.id AND company_id = $3;
WHERE e.id = $1 -- name: GetOddsByEventID :many
AND e.is_live = false SELECT *
AND e.status = 'upcoming' FROM odds_market_with_event
AND o.is_active = true WHERE event_id = $1
AND o.source = 'bet365'; AND (
-- name: GetPaginatedPrematchOddsByUpcomingID :many is_live = sqlc.narg('is_live')
SELECT o.* OR sqlc.narg('is_live') IS NULL
FROM odds o )
JOIN events e ON o.fi = e.id AND (
WHERE e.id = $1 status = sqlc.narg('status')
AND e.is_live = false OR sqlc.narg('status') IS NULL
AND e.status = 'upcoming' )
AND o.is_active = true AND (
AND o.source = 'bet365' 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'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: DeleteOddsForEvent :exec -- name: DeleteOddsForEvent :exec
DELETE FROM odds DELETE FROM odds_market
Where fi = $1; 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 * SELECT *
FROM settings; FROM global_settings;
-- name: GetSetting :one -- name: GetGlobalSetting :one
SELECT * SELECT *
FROM settings FROM global_settings
WHERE key = $1; WHERE key = $1;
-- name: SaveSetting :one -- name: UpdateGlobalSetting :exec
INSERT INTO settings (key, value, updated_at) UPDATE global_settings
VALUES ($1, $2, CURRENT_TIMESTAMP) ON CONFLICT (key) DO 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 UPDATE
SET value = EXCLUDED.value SET value = EXCLUDED.value;
RETURNING *; -- 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 -- name: CreateTicket :one
INSERT INTO tickets (amount, total_odds, ip) INSERT INTO tickets (amount, total_odds, ip, company_id)
VALUES ($1, $2, $3) VALUES ($1, $2, $3, $4)
RETURNING *; RETURNING *;
-- name: CreateTicketOutcome :copyfrom -- name: CreateTicketOutcome :copyfrom
INSERT INTO ticket_outcomes ( INSERT INTO ticket_outcomes (
@ -33,7 +33,11 @@ VALUES (
); );
-- name: GetAllTickets :many -- name: GetAllTickets :many
SELECT * 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 -- name: GetTicketByID :one
SELECT * SELECT *
FROM ticket_with_outcomes FROM ticket_with_outcomes
@ -60,6 +64,7 @@ where created_at < now() - interval '1 day';
Delete from ticket_outcomes Delete from ticket_outcomes
where ticket_id = $1; where ticket_id = $1;
-- name: GetAllTicketsInRange :one -- 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 FROM tickets
WHERE created_at BETWEEN $1 AND $2; WHERE created_at BETWEEN $1 AND $2;

View File

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

View File

@ -18,6 +18,7 @@ services:
retries: 5 retries: 5
volumes: volumes:
- postgres_data:/var/lib/postgresql/data - postgres_data:/var/lib/postgresql/data
- ./exports:/exports
mongo: mongo:
container_name: fortunebet-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 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 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 FROM users
WHERE email = $1 WHERE (
OR phone_number = $2 email = $1
OR phone_number = $2
)
AND (
company_id = $3
OR $3 IS NULL
)
` `
type GetUserByEmailPhoneParams struct { type GetUserByEmailPhoneParams struct {
Email pgtype.Text `json:"email"` Email pgtype.Text `json:"email"`
PhoneNumber pgtype.Text `json:"phone_number"` PhoneNumber pgtype.Text `json:"phone_number"`
CompanyID pgtype.Int8 `json:"company_id"`
} }
func (q *Queries) GetUserByEmailPhone(ctx context.Context, arg GetUserByEmailPhoneParams) (User, error) { 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 var i User
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,

View File

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

View File

@ -14,16 +14,18 @@ import (
const CreateCompany = `-- name: CreateCompany :one const CreateCompany = `-- name: CreateCompany :one
INSERT INTO companies ( INSERT INTO companies (
name, name,
slug,
admin_id, admin_id,
wallet_id, wallet_id,
deducted_percentage deducted_percentage
) )
VALUES ($1, $2, $3, $4) VALUES ($1, $2, $3, $4, $5)
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 CreateCompanyParams struct { type CreateCompanyParams struct {
Name string `json:"name"` Name string `json:"name"`
Slug string `json:"slug"`
AdminID int64 `json:"admin_id"` AdminID int64 `json:"admin_id"`
WalletID int64 `json:"wallet_id"` WalletID int64 `json:"wallet_id"`
DeductedPercentage float32 `json:"deducted_percentage"` DeductedPercentage float32 `json:"deducted_percentage"`
@ -32,6 +34,7 @@ type CreateCompanyParams struct {
func (q *Queries) CreateCompany(ctx context.Context, arg CreateCompanyParams) (Company, error) { func (q *Queries) CreateCompany(ctx context.Context, arg CreateCompanyParams) (Company, error) {
row := q.db.QueryRow(ctx, CreateCompany, row := q.db.QueryRow(ctx, CreateCompany,
arg.Name, arg.Name,
arg.Slug,
arg.AdminID, arg.AdminID,
arg.WalletID, arg.WalletID,
arg.DeductedPercentage, arg.DeductedPercentage,
@ -40,6 +43,7 @@ func (q *Queries) CreateCompany(ctx context.Context, arg CreateCompanyParams) (C
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.Name, &i.Name,
&i.Slug,
&i.AdminID, &i.AdminID,
&i.WalletID, &i.WalletID,
&i.DeductedPercentage, &i.DeductedPercentage,
@ -61,7 +65,7 @@ func (q *Queries) DeleteCompany(ctx context.Context, id int64) error {
} }
const GetAllCompanies = `-- name: GetAllCompanies :many 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 FROM companies_details
WHERE ( WHERE (
name ILIKE '%' || $1 || '%' name ILIKE '%' || $1 || '%'
@ -98,6 +102,7 @@ func (q *Queries) GetAllCompanies(ctx context.Context, arg GetAllCompaniesParams
if err := rows.Scan( if err := rows.Scan(
&i.ID, &i.ID,
&i.Name, &i.Name,
&i.Slug,
&i.AdminID, &i.AdminID,
&i.WalletID, &i.WalletID,
&i.DeductedPercentage, &i.DeductedPercentage,
@ -121,7 +126,7 @@ func (q *Queries) GetAllCompanies(ctx context.Context, arg GetAllCompaniesParams
} }
const GetCompanyByID = `-- name: GetCompanyByID :one 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 FROM companies_details
WHERE id = $1 WHERE id = $1
` `
@ -132,6 +137,7 @@ func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (CompaniesDetail
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.Name, &i.Name,
&i.Slug,
&i.AdminID, &i.AdminID,
&i.WalletID, &i.WalletID,
&i.DeductedPercentage, &i.DeductedPercentage,
@ -147,8 +153,21 @@ func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (CompaniesDetail
return i, err 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 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 FROM companies_details
WHERE name ILIKE '%' || $1 || '%' WHERE name ILIKE '%' || $1 || '%'
` `
@ -165,6 +184,7 @@ func (q *Queries) SearchCompanyByName(ctx context.Context, dollar_1 pgtype.Text)
if err := rows.Scan( if err := rows.Scan(
&i.ID, &i.ID,
&i.Name, &i.Name,
&i.Slug,
&i.AdminID, &i.AdminID,
&i.WalletID, &i.WalletID,
&i.DeductedPercentage, &i.DeductedPercentage,
@ -198,7 +218,7 @@ SET name = COALESCE($2, name),
), ),
updated_at = CURRENT_TIMESTAMP updated_at = CURRENT_TIMESTAMP
WHERE id = $1 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 { type UpdateCompanyParams struct {
@ -221,6 +241,7 @@ func (q *Queries) UpdateCompany(ctx context.Context, arg UpdateCompanyParams) (C
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.Name, &i.Name,
&i.Slug,
&i.AdminID, &i.AdminID,
&i.WalletID, &i.WalletID,
&i.DeductedPercentage, &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" "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 const GetTotalMontlyEventStat = `-- name: GetTotalMontlyEventStat :many
SELECT DATE_TRUNC('month', start_time) AS month, SELECT DATE_TRUNC('month', start_time) AS month,
COUNT(*) AS event_count COUNT(*) AS event_count
FROM events FROM events
JOIN leagues ON leagues.id = events.league_id JOIN leagues ON leagues.id = events.league_id
WHERE ( WHERE (
events.is_featured = $1 events.league_id = $1
OR $1 IS NULL 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 GROUP BY month
ORDER 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 { type GetTotalMontlyEventStatRow struct {
Month pgtype.Interval `json:"month"` Month pgtype.Interval `json:"month"`
EventCount int64 `json:"event_count"` EventCount int64 `json:"event_count"`
} }
func (q *Queries) GetTotalMontlyEventStat(ctx context.Context, arg GetTotalMontlyEventStatParams) ([]GetTotalMontlyEventStatRow, error) { func (q *Queries) GetTotalMontlyEventStat(ctx context.Context, leagueID pgtype.Int8) ([]GetTotalMontlyEventStatRow, error) {
rows, err := q.db.Query(ctx, GetTotalMontlyEventStat, arg.IsEventFeatured, arg.IsLeagueFeatured, arg.LeagueID) rows, err := q.db.Query(ctx, GetTotalMontlyEventStat, leagueID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

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

View File

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

View File

@ -75,6 +75,7 @@ type Bank struct {
type Bet struct { type Bet struct {
ID int64 `json:"id"` ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
Amount int64 `json:"amount"` Amount int64 `json:"amount"`
TotalOdds float32 `json:"total_odds"` TotalOdds float32 `json:"total_odds"`
Status int32 `json:"status"` Status int32 `json:"status"`
@ -108,6 +109,7 @@ type BetOutcome struct {
type BetWithOutcome struct { type BetWithOutcome struct {
ID int64 `json:"id"` ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
Amount int64 `json:"amount"` Amount int64 `json:"amount"`
TotalOdds float32 `json:"total_odds"` TotalOdds float32 `json:"total_odds"`
Status int32 `json:"status"` Status int32 `json:"status"`
@ -125,8 +127,8 @@ type BetWithOutcome struct {
} }
type Bonu struct { type Bonu struct {
ID int64 `json:"id"`
Multiplier float32 `json:"multiplier"` Multiplier float32 `json:"multiplier"`
ID int64 `json:"id"`
BalanceCap int64 `json:"balance_cap"` BalanceCap int64 `json:"balance_cap"`
} }
@ -184,6 +186,7 @@ type BranchOperation struct {
type CompaniesDetail struct { type CompaniesDetail struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Slug string `json:"slug"`
AdminID int64 `json:"admin_id"` AdminID int64 `json:"admin_id"`
WalletID int64 `json:"wallet_id"` WalletID int64 `json:"wallet_id"`
DeductedPercentage float32 `json:"deducted_percentage"` DeductedPercentage float32 `json:"deducted_percentage"`
@ -200,6 +203,7 @@ type CompaniesDetail struct {
type Company struct { type Company struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Slug string `json:"slug"`
AdminID int64 `json:"admin_id"` AdminID int64 `json:"admin_id"`
WalletID int64 `json:"wallet_id"` WalletID int64 `json:"wallet_id"`
DeductedPercentage float32 `json:"deducted_percentage"` DeductedPercentage float32 `json:"deducted_percentage"`
@ -208,6 +212,42 @@ type Company struct {
UpdatedAt pgtype.Timestamp `json:"updated_at"` 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 { type CustomerWallet struct {
ID int64 `json:"id"` ID int64 `json:"id"`
CustomerID int64 `json:"customer_id"` CustomerID int64 `json:"customer_id"`
@ -248,31 +288,111 @@ type DirectDeposit struct {
VerifiedAt pgtype.Timestamp `json:"verified_at"` 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 { type Event struct {
ID string `json:"id"` ID string `json:"id"`
SportID pgtype.Int4 `json:"sport_id"` SportID int32 `json:"sport_id"`
MatchName pgtype.Text `json:"match_name"` MatchName string `json:"match_name"`
HomeTeam pgtype.Text `json:"home_team"` HomeTeam string `json:"home_team"`
AwayTeam pgtype.Text `json:"away_team"` AwayTeam string `json:"away_team"`
HomeTeamID pgtype.Int4 `json:"home_team_id"` HomeTeamID int64 `json:"home_team_id"`
AwayTeamID pgtype.Int4 `json:"away_team_id"` AwayTeamID int64 `json:"away_team_id"`
HomeKitImage pgtype.Text `json:"home_kit_image"` HomeKitImage string `json:"home_kit_image"`
AwayKitImage pgtype.Text `json:"away_kit_image"` AwayKitImage string `json:"away_kit_image"`
LeagueID pgtype.Int4 `json:"league_id"` LeagueID int64 `json:"league_id"`
LeagueName pgtype.Text `json:"league_name"` LeagueName string `json:"league_name"`
LeagueCc pgtype.Text `json:"league_cc"` StartTime pgtype.Timestamp `json:"start_time"`
StartTime pgtype.Timestamp `json:"start_time"` Score pgtype.Text `json:"score"`
Score pgtype.Text `json:"score"` MatchMinute pgtype.Int4 `json:"match_minute"`
MatchMinute pgtype.Int4 `json:"match_minute"` TimerStatus pgtype.Text `json:"timer_status"`
TimerStatus pgtype.Text `json:"timer_status"` AddedTime pgtype.Int4 `json:"added_time"`
AddedTime pgtype.Int4 `json:"added_time"` MatchPeriod pgtype.Int4 `json:"match_period"`
MatchPeriod pgtype.Int4 `json:"match_period"` IsLive bool `json:"is_live"`
IsLive pgtype.Bool `json:"is_live"` Status string `json:"status"`
Status pgtype.Text `json:"status"` FetchedAt pgtype.Timestamp `json:"fetched_at"`
FetchedAt pgtype.Timestamp `json:"fetched_at"` Source string `json:"source"`
Source pgtype.Text `json:"source"` DefaultIsActive bool `json:"default_is_active"`
IsFeatured bool `json:"is_featured"` DefaultIsFeatured bool `json:"default_is_featured"`
IsActive bool `json:"is_active"` 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 { type ExchangeRate struct {
@ -292,23 +412,45 @@ type FavoriteGame struct {
} }
type Flag struct { type Flag struct {
ID int64 `json:"id"` ID int64 `json:"id"`
BetID pgtype.Int8 `json:"bet_id"` BetID pgtype.Int8 `json:"bet_id"`
OddID pgtype.Int8 `json:"odd_id"` OddsMarketID pgtype.Int8 `json:"odds_market_id"`
Reason pgtype.Text `json:"reason"` Reason pgtype.Text `json:"reason"`
FlaggedAt pgtype.Timestamp `json:"flagged_at"` FlaggedAt pgtype.Timestamp `json:"flagged_at"`
Resolved pgtype.Bool `json:"resolved"` 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 { type League struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Img pgtype.Text `json:"img"` ImgUrl pgtype.Text `json:"img_url"`
CountryCode pgtype.Text `json:"country_code"` CountryCode pgtype.Text `json:"country_code"`
Bet365ID pgtype.Int4 `json:"bet365_id"` Bet365ID pgtype.Int4 `json:"bet365_id"`
SportID int32 `json:"sport_id"` SportID int32 `json:"sport_id"`
IsActive pgtype.Bool `json:"is_active"` DefaultIsActive bool `json:"default_is_active"`
IsFeatured pgtype.Bool `json:"is_featured"` 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 { type Notification struct {
@ -328,23 +470,60 @@ type Notification struct {
Metadata []byte `json:"metadata"` Metadata []byte `json:"metadata"`
} }
type Odd struct { type OddHistory struct {
ID int32 `json:"id"` ID int64 `json:"id"`
EventID pgtype.Text `json:"event_id"` OddsMarketID int64 `json:"odds_market_id"`
Fi pgtype.Text `json:"fi"` RawOddID int64 `json:"raw_odd_id"`
MarketType string `json:"market_type"` MarketID string `json:"market_id"`
MarketName pgtype.Text `json:"market_name"` EventID string `json:"event_id"`
MarketCategory pgtype.Text `json:"market_category"` OddValue float64 `json:"odd_value"`
MarketID pgtype.Text `json:"market_id"` CreatedAt pgtype.Timestamp `json:"created_at"`
Name pgtype.Text `json:"name"` }
Handicap pgtype.Text `json:"handicap"`
OddsValue pgtype.Float8 `json:"odds_value"` type OddsMarket struct {
Section string `json:"section"` ID int64 `json:"id"`
Category pgtype.Text `json:"category"` EventID string `json:"event_id"`
RawOdds []byte `json:"raw_odds"` MarketType string `json:"market_type"`
FetchedAt pgtype.Timestamp `json:"fetched_at"` MarketName string `json:"market_name"`
Source pgtype.Text `json:"source"` MarketCategory string `json:"market_category"`
IsActive pgtype.Bool `json:"is_active"` 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 { type Otp struct {
@ -422,11 +601,21 @@ type Result struct {
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
} }
type Setting struct { type ResultLog struct {
Key string `json:"key"` ID int64 `json:"id"`
Value string `json:"value"` StatusNotFinishedCount int32 `json:"status_not_finished_count"`
CreatedAt pgtype.Timestamp `json:"created_at"` StatusNotFinishedBets int32 `json:"status_not_finished_bets"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` 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 { type ShopBet struct {
@ -545,15 +734,16 @@ type SupportedOperation struct {
} }
type Team struct { type Team struct {
ID string `json:"id"` ID int64 `json:"id"`
TeamName string `json:"team_name"` TeamName string `json:"team_name"`
Country pgtype.Text `json:"country"` CountryCode string `json:"country_code"`
Bet365ID pgtype.Int4 `json:"bet365_id"` Bet365ID pgtype.Int8 `json:"bet365_id"`
LogoUrl pgtype.Text `json:"logo_url"` ImgUrl pgtype.Text `json:"img_url"`
} }
type Ticket struct { type Ticket struct {
ID int64 `json:"id"` ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
Amount int64 `json:"amount"` Amount int64 `json:"amount"`
TotalOdds float32 `json:"total_odds"` TotalOdds float32 `json:"total_odds"`
Ip string `json:"ip"` Ip string `json:"ip"`
@ -580,6 +770,7 @@ type TicketOutcome struct {
type TicketWithOutcome struct { type TicketWithOutcome struct {
ID int64 `json:"id"` ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
Amount int64 `json:"amount"` Amount int64 `json:"amount"`
TotalOdds float32 `json:"total_odds"` TotalOdds float32 `json:"total_odds"`
Ip string `json:"ip"` Ip string `json:"ip"`
@ -695,6 +886,7 @@ type VirtualGameTransaction struct {
type Wallet struct { type Wallet struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Balance int64 `json:"balance"` Balance int64 `json:"balance"`
Currency string `json:"currency"`
IsWithdraw bool `json:"is_withdraw"` IsWithdraw bool `json:"is_withdraw"`
IsBettable bool `json:"is_bettable"` IsBettable bool `json:"is_bettable"`
IsTransferable bool `json:"is_transferable"` IsTransferable bool `json:"is_transferable"`
@ -703,7 +895,6 @@ type Wallet struct {
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
CreatedAt pgtype.Timestamp `json:"created_at"` CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
Currency string `json:"currency"`
BonusBalance pgtype.Numeric `json:"bonus_balance"` BonusBalance pgtype.Numeric `json:"bonus_balance"`
CashBalance pgtype.Numeric `json:"cash_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 const DeleteOddsForEvent = `-- name: DeleteOddsForEvent :exec
DELETE FROM odds DELETE FROM odds_market
Where fi = $1 Where event_id = $1
` `
func (q *Queries) DeleteOddsForEvent(ctx context.Context, fi pgtype.Text) error { func (q *Queries) DeleteOddsForEvent(ctx context.Context, eventID string) error {
_, err := q.db.Exec(ctx, DeleteOddsForEvent, fi) _, err := q.db.Exec(ctx, DeleteOddsForEvent, eventID)
return err return err
} }
const GetALLPrematchOdds = `-- name: GetALLPrematchOdds :many const GetAllOdds = `-- name: GetAllOdds :many
SELECT event_id, 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
fi, FROM odds_market_with_event
market_type, LIMIT $2 OFFSET $1
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'
` `
type GetALLPrematchOddsRow struct { type GetAllOddsParams 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"`
Offset pgtype.Int4 `json:"offset"` Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"` Limit pgtype.Int4 `json:"limit"`
} }
func (q *Queries) GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, arg GetPaginatedPrematchOddsByUpcomingIDParams) ([]Odd, error) { func (q *Queries) GetAllOdds(ctx context.Context, arg GetAllOddsParams) ([]OddsMarketWithEvent, error) {
rows, err := q.db.Query(ctx, GetPaginatedPrematchOddsByUpcomingID, arg.ID, arg.Offset, arg.Limit) rows, err := q.db.Query(ctx, GetAllOdds, arg.Offset, arg.Limit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
var items []Odd var items []OddsMarketWithEvent
for rows.Next() { for rows.Next() {
var i Odd var i OddsMarketWithEvent
if err := rows.Scan( if err := rows.Scan(
&i.ID, &i.ID,
&i.EventID, &i.EventID,
&i.Fi,
&i.MarketType, &i.MarketType,
&i.MarketName, &i.MarketName,
&i.MarketCategory, &i.MarketCategory,
&i.MarketID, &i.MarketID,
&i.Name,
&i.Handicap,
&i.OddsValue,
&i.Section,
&i.Category,
&i.RawOdds, &i.RawOdds,
&i.DefaultIsActive,
&i.FetchedAt, &i.FetchedAt,
&i.ExpiresAt,
&i.IsMonitored,
&i.IsLive,
&i.Status,
&i.Source, &i.Source,
&i.IsActive,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@ -151,118 +67,42 @@ func (q *Queries) GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, arg
return items, nil return items, nil
} }
const GetPrematchOdds = `-- name: GetPrematchOdds :many const GetAllOddsWithSettings = `-- name: GetAllOddsWithSettings :many
SELECT event_id, 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
fi, FROM odds_market_with_settings
market_type, WHERE company_id = $1
market_name, LIMIT $3 OFFSET $2
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'
` `
type GetPrematchOddsRow struct { type GetAllOddsWithSettingsParams struct {
EventID pgtype.Text `json:"event_id"` CompanyID int64 `json:"company_id"`
Fi pgtype.Text `json:"fi"` Offset pgtype.Int4 `json:"offset"`
MarketType string `json:"market_type"` Limit pgtype.Int4 `json:"limit"`
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) GetPrematchOdds(ctx context.Context) ([]GetPrematchOddsRow, error) { func (q *Queries) GetAllOddsWithSettings(ctx context.Context, arg GetAllOddsWithSettingsParams) ([]OddsMarketWithSetting, error) {
rows, err := q.db.Query(ctx, GetPrematchOdds) rows, err := q.db.Query(ctx, GetAllOddsWithSettings, arg.CompanyID, arg.Offset, arg.Limit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
var items []GetPrematchOddsRow var items []OddsMarketWithSetting
for rows.Next() { for rows.Next() {
var i GetPrematchOddsRow var i OddsMarketWithSetting
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
if err := rows.Scan( if err := rows.Scan(
&i.ID, &i.ID,
&i.EventID, &i.EventID,
&i.Fi,
&i.MarketType, &i.MarketType,
&i.MarketName, &i.MarketName,
&i.MarketCategory, &i.MarketCategory,
&i.MarketID, &i.MarketID,
&i.Name, &i.DefaultIsActive,
&i.Handicap,
&i.OddsValue,
&i.Section,
&i.Category,
&i.RawOdds,
&i.FetchedAt, &i.FetchedAt,
&i.Source, &i.ExpiresAt,
&i.CompanyID,
&i.IsActive, &i.IsActive,
&i.RawOdds,
&i.UpdatedAt,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@ -274,62 +114,239 @@ func (q *Queries) GetPrematchOddsByUpcomingID(ctx context.Context, id string) ([
return items, nil return items, nil
} }
const GetRawOddsByMarketID = `-- name: GetRawOddsByMarketID :one const GetOddsByEventID = `-- name: GetOddsByEventID :many
SELECT id, 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
market_name, FROM odds_market_with_event
handicap, WHERE event_id = $1
raw_odds, AND (
fetched_at is_live = $2
FROM odds 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 WHERE market_id = $1
AND fi = $2 AND event_id = $2
AND is_active = true
AND source = 'bet365'
` `
type GetRawOddsByMarketIDParams struct { type GetOddsByMarketIDParams struct {
MarketID pgtype.Text `json:"market_id"` MarketID string `json:"market_id"`
Fi pgtype.Text `json:"fi"` EventID string `json:"event_id"`
} }
type GetRawOddsByMarketIDRow struct { func (q *Queries) GetOddsByMarketID(ctx context.Context, arg GetOddsByMarketIDParams) (OddsMarketWithEvent, error) {
ID int32 `json:"id"` row := q.db.QueryRow(ctx, GetOddsByMarketID, arg.MarketID, arg.EventID)
MarketName pgtype.Text `json:"market_name"` var i OddsMarketWithEvent
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
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.EventID,
&i.MarketType,
&i.MarketName, &i.MarketName,
&i.Handicap, &i.MarketCategory,
&i.MarketID,
&i.RawOdds, &i.RawOdds,
&i.DefaultIsActive,
&i.FetchedAt, &i.FetchedAt,
&i.ExpiresAt,
&i.IsMonitored,
&i.IsLive,
&i.Status,
&i.Source,
) )
return i, err return i, err
} }
const InsertNonLiveOdd = `-- name: InsertNonLiveOdd :exec const GetOddsWithSettingsByEventID = `-- name: GetOddsWithSettingsByEventID :many
INSERT INTO odds ( 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, event_id,
fi,
market_type, market_type,
market_name, market_name,
market_category, market_category,
market_id, market_id,
name,
handicap,
odds_value,
section,
category,
raw_odds, raw_odds,
is_active, fetched_at,
source, expires_at
fetched_at
) )
VALUES ( VALUES (
$1, $1,
@ -339,64 +356,38 @@ VALUES (
$5, $5,
$6, $6,
$7, $7,
$8, $8
$9,
$10,
$11,
$12,
$13,
$14,
$15
) ON CONFLICT (event_id, market_id) DO ) ON CONFLICT (event_id, market_id) DO
UPDATE UPDATE
SET odds_value = EXCLUDED.odds_value, SET market_type = EXCLUDED.market_type,
raw_odds = EXCLUDED.raw_odds,
market_type = EXCLUDED.market_type,
market_name = EXCLUDED.market_name, market_name = EXCLUDED.market_name,
market_category = EXCLUDED.market_category, market_category = EXCLUDED.market_category,
name = EXCLUDED.name, raw_odds = EXCLUDED.raw_odds,
handicap = EXCLUDED.handicap,
fetched_at = EXCLUDED.fetched_at, fetched_at = EXCLUDED.fetched_at,
is_active = EXCLUDED.is_active, expires_at = EXCLUDED.expires_at
source = EXCLUDED.source,
fi = EXCLUDED.fi
` `
type InsertNonLiveOddParams struct { type InsertOddsMarketParams struct {
EventID pgtype.Text `json:"event_id"` EventID string `json:"event_id"`
Fi pgtype.Text `json:"fi"`
MarketType string `json:"market_type"` MarketType string `json:"market_type"`
MarketName pgtype.Text `json:"market_name"` MarketName string `json:"market_name"`
MarketCategory pgtype.Text `json:"market_category"` MarketCategory string `json:"market_category"`
MarketID pgtype.Text `json:"market_id"` MarketID string `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"` RawOdds []byte `json:"raw_odds"`
IsActive pgtype.Bool `json:"is_active"`
Source pgtype.Text `json:"source"`
FetchedAt pgtype.Timestamp `json:"fetched_at"` FetchedAt pgtype.Timestamp `json:"fetched_at"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
} }
func (q *Queries) InsertNonLiveOdd(ctx context.Context, arg InsertNonLiveOddParams) error { func (q *Queries) InsertOddsMarket(ctx context.Context, arg InsertOddsMarketParams) error {
_, err := q.db.Exec(ctx, InsertNonLiveOdd, _, err := q.db.Exec(ctx, InsertOddsMarket,
arg.EventID, arg.EventID,
arg.Fi,
arg.MarketType, arg.MarketType,
arg.MarketName, arg.MarketName,
arg.MarketCategory, arg.MarketCategory,
arg.MarketID, arg.MarketID,
arg.Name,
arg.Handicap,
arg.OddsValue,
arg.Section,
arg.Category,
arg.RawOdds, arg.RawOdds,
arg.IsActive,
arg.Source,
arg.FetchedAt, arg.FetchedAt,
arg.ExpiresAt,
) )
return err 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 ( import (
"context" "context"
"github.com/jackc/pgx/v5/pgtype"
) )
const GetSetting = `-- name: GetSetting :one const DeleteAllCompanySetting = `-- name: DeleteAllCompanySetting :exec
SELECT key, value, created_at, updated_at DELETE FROM company_settings
FROM 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 WHERE key = $1
` `
func (q *Queries) GetSetting(ctx context.Context, key string) (Setting, error) { func (q *Queries) GetCompanySettingsByKey(ctx context.Context, key string) ([]CompanySetting, error) {
row := q.db.QueryRow(ctx, GetSetting, key) rows, err := q.db.Query(ctx, GetCompanySettingsByKey, key)
var i Setting 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( err := row.Scan(
&i.Key, &i.Key,
&i.Value, &i.Value,
@ -27,20 +150,20 @@ func (q *Queries) GetSetting(ctx context.Context, key string) (Setting, error) {
return i, err return i, err
} }
const GetSettings = `-- name: GetSettings :many const GetGlobalSettings = `-- name: GetGlobalSettings :many
SELECT key, value, created_at, updated_at SELECT key, value, created_at, updated_at
FROM settings FROM global_settings
` `
func (q *Queries) GetSettings(ctx context.Context) ([]Setting, error) { func (q *Queries) GetGlobalSettings(ctx context.Context) ([]GlobalSetting, error) {
rows, err := q.db.Query(ctx, GetSettings) rows, err := q.db.Query(ctx, GetGlobalSettings)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
var items []Setting var items []GlobalSetting
for rows.Next() { for rows.Next() {
var i Setting var i GlobalSetting
if err := rows.Scan( if err := rows.Scan(
&i.Key, &i.Key,
&i.Value, &i.Value,
@ -57,27 +180,79 @@ func (q *Queries) GetSettings(ctx context.Context) ([]Setting, error) {
return items, nil return items, nil
} }
const SaveSetting = `-- name: SaveSetting :one const GetOverrideSettings = `-- name: GetOverrideSettings :many
INSERT INTO settings (key, value, updated_at) SELECT gs.key, gs.value, gs.created_at, gs.updated_at,
VALUES ($1, $2, CURRENT_TIMESTAMP) ON CONFLICT (key) DO COALESCE(cs.value, gs.value) AS value
UPDATE FROM global_settings gs
SET value = EXCLUDED.value LEFT JOIN company_settings cs ON cs.key = gs.key
RETURNING key, value, created_at, updated_at 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"` Key string `json:"key"`
Value string `json:"value"` Value string `json:"value"`
} }
func (q *Queries) SaveSetting(ctx context.Context, arg SaveSettingParams) (Setting, error) { func (q *Queries) UpdateGlobalSetting(ctx context.Context, arg UpdateGlobalSettingParams) error {
row := q.db.QueryRow(ctx, SaveSetting, arg.Key, arg.Value) _, err := q.db.Exec(ctx, UpdateGlobalSetting, arg.Key, arg.Value)
var i Setting return err
err := row.Scan(
&i.Key,
&i.Value,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
} }

View File

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

View File

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

View File

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

View File

@ -2,8 +2,14 @@ package domain
import ( import (
"time" "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 { type BetOutcome struct {
ID int64 `json:"id" example:"1"` ID int64 `json:"id" example:"1"`
BetID int64 `json:"bet_id" example:"1"` BetID int64 `json:"bet_id" example:"1"`
@ -46,6 +52,7 @@ type Bet struct {
TotalOdds float32 TotalOdds float32
Status OutcomeStatus Status OutcomeStatus
UserID int64 UserID int64
CompanyID int64
IsShopBet bool IsShopBet bool
CashedOut bool CashedOut bool
FastCode string FastCode string
@ -54,6 +61,7 @@ type Bet struct {
type BetFilter struct { type BetFilter struct {
UserID ValidInt64 UserID ValidInt64
CompanyID ValidInt64
CashedOut ValidBool CashedOut ValidBool
IsShopBet ValidBool IsShopBet ValidBool
Query ValidString Query ValidString
@ -78,6 +86,7 @@ type GetBet struct {
FullName string FullName string
PhoneNumber string PhoneNumber string
UserID int64 UserID int64
CompanyID int64
IsShopBet bool IsShopBet bool
CashedOut bool CashedOut bool
Outcomes []BetOutcome Outcomes []BetOutcome
@ -90,6 +99,7 @@ type CreateBet struct {
TotalOdds float32 TotalOdds float32
Status OutcomeStatus Status OutcomeStatus
UserID int64 UserID int64
CompanyID int64
IsShopBet bool IsShopBet bool
OutcomesHash string OutcomesHash string
FastCode string FastCode string
@ -130,6 +140,7 @@ type CreateBetRes struct {
TotalOdds float32 `json:"total_odds" example:"4.22"` TotalOdds float32 `json:"total_odds" example:"4.22"`
Status OutcomeStatus `json:"status" example:"1"` Status OutcomeStatus `json:"status" example:"1"`
UserID int64 `json:"user_id" example:"2"` UserID int64 `json:"user_id" example:"2"`
CompanyID int64 `json:"company_id" example:"1"`
IsShopBet bool `json:"is_shop_bet" example:"false"` IsShopBet bool `json:"is_shop_bet" example:"false"`
CreatedNumber int64 `json:"created_number" example:"2"` CreatedNumber int64 `json:"created_number" example:"2"`
FastCode string `json:"fast_code"` FastCode string `json:"fast_code"`
@ -142,19 +153,21 @@ type BetRes struct {
Status OutcomeStatus `json:"status" example:"1"` Status OutcomeStatus `json:"status" example:"1"`
Fullname string `json:"full_name" example:"John Smith"` Fullname string `json:"full_name" example:"John Smith"`
UserID int64 `json:"user_id" example:"2"` UserID int64 `json:"user_id" example:"2"`
CompanyID int64 `json:"company_id" example:"1"`
IsShopBet bool `json:"is_shop_bet" example:"false"` IsShopBet bool `json:"is_shop_bet" example:"false"`
CashedOut bool `json:"cashed_out" example:"false"` CashedOut bool `json:"cashed_out" example:"false"`
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"` CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
FastCode string `json:"fast_code"` FastCode string `json:"fast_code"`
} }
func ConvertCreateBet(bet Bet, createdNumber int64) CreateBetRes { func ConvertCreateBetRes(bet Bet, createdNumber int64) CreateBetRes {
return CreateBetRes{ return CreateBetRes{
ID: bet.ID, ID: bet.ID,
Amount: bet.Amount.Float32(), Amount: bet.Amount.Float32(),
TotalOdds: bet.TotalOdds, TotalOdds: bet.TotalOdds,
Status: bet.Status, Status: bet.Status,
UserID: bet.UserID, UserID: bet.UserID,
CompanyID: bet.CompanyID,
CreatedNumber: createdNumber, CreatedNumber: createdNumber,
IsShopBet: bet.IsShopBet, IsShopBet: bet.IsShopBet,
FastCode: bet.FastCode, FastCode: bet.FastCode,
@ -169,6 +182,7 @@ func ConvertBet(bet GetBet) BetRes {
Status: bet.Status, Status: bet.Status,
Fullname: bet.FullName, Fullname: bet.FullName,
UserID: bet.UserID, UserID: bet.UserID,
CompanyID: bet.CompanyID,
Outcomes: bet.Outcomes, Outcomes: bet.Outcomes,
IsShopBet: bet.IsShopBet, IsShopBet: bet.IsShopBet,
CashedOut: bet.CashedOut, CashedOut: bet.CashedOut,
@ -176,3 +190,106 @@ func ConvertBet(bet GetBet) BetRes {
FastCode: bet.FastCode, 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 package domain
import ( import (
"encoding/json"
"fmt"
"strconv"
"time"
"go.uber.org/zap" "go.uber.org/zap"
) )
var MongoDBLogger *zap.Logger 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 { type ResponseWDataFactory[T any] struct {
Data T `json:"data"` Data T `json:"data"`
Response Response
@ -95,73 +38,3 @@ type Pagination struct {
func PtrFloat64(v float64) *float64 { return &v } func PtrFloat64(v float64) *float64 { return &v }
func PtrInt64(v int64) *int64 { 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 { type Company struct {
ID int64 ID int64
Name string Name string
Slug string
AdminID int64 AdminID int64
WalletID int64 WalletID int64
DeductedPercentage float32 DeductedPercentage float32
@ -27,6 +28,7 @@ type CompanyFilter struct {
type GetCompany struct { type GetCompany struct {
ID int64 ID int64
Name string Name string
Slug string
AdminID int64 AdminID int64
AdminFirstName string AdminFirstName string
AdminLastName string AdminLastName string
@ -68,6 +70,7 @@ type UpdateCompanyReq struct {
type CompanyRes struct { type CompanyRes struct {
ID int64 `json:"id" example:"1"` ID int64 `json:"id" example:"1"`
Name string `json:"name" example:"CompanyName"` Name string `json:"name" example:"CompanyName"`
Slug string `json:"slug" example:"slug"`
AdminID int64 `json:"admin_id" example:"1"` AdminID int64 `json:"admin_id" example:"1"`
WalletID int64 `json:"wallet_id" example:"1"` WalletID int64 `json:"wallet_id" example:"1"`
DeductedPercentage float32 `json:"deducted_percentage" example:"0.1"` DeductedPercentage float32 `json:"deducted_percentage" example:"0.1"`
@ -77,6 +80,7 @@ type CompanyRes struct {
type GetCompanyRes struct { type GetCompanyRes struct {
ID int64 `json:"id" example:"1"` ID int64 `json:"id" example:"1"`
Name string `json:"name" example:"CompanyName"` Name string `json:"name" example:"CompanyName"`
Slug string `json:"slug" example:"slug"`
AdminID int64 `json:"admin_id" example:"1"` AdminID int64 `json:"admin_id" example:"1"`
WalletID int64 `json:"wallet_id" example:"1"` WalletID int64 `json:"wallet_id" example:"1"`
WalletBalance float32 `json:"balance" example:"1"` WalletBalance float32 `json:"balance" example:"1"`
@ -89,20 +93,14 @@ type GetCompanyRes struct {
} }
func ConvertCompany(company Company) CompanyRes { func ConvertCompany(company Company) CompanyRes {
return CompanyRes{ return CompanyRes(company)
ID: company.ID,
Name: company.Name,
AdminID: company.AdminID,
WalletID: company.WalletID,
IsActive: company.IsActive,
DeductedPercentage: company.DeductedPercentage,
}
} }
func ConvertGetCompany(company GetCompany) GetCompanyRes { func ConvertGetCompany(company GetCompany) GetCompanyRes {
return GetCompanyRes{ return GetCompanyRes{
ID: company.ID, ID: company.ID,
Name: company.Name, Name: company.Name,
Slug: company.Slug,
AdminID: company.AdminID, AdminID: company.AdminID,
WalletID: company.WalletID, WalletID: company.WalletID,
WalletBalance: company.WalletBalance.Float32(), WalletBalance: company.WalletBalance.Float32(),
@ -112,13 +110,13 @@ func ConvertGetCompany(company GetCompany) GetCompanyRes {
AdminFirstName: company.AdminFirstName, AdminFirstName: company.AdminFirstName,
AdminLastName: company.AdminLastName, AdminLastName: company.AdminLastName,
AdminPhoneNumber: company.AdminPhoneNumber, AdminPhoneNumber: company.AdminPhoneNumber,
} }
} }
func ConvertCreateCompany(company CreateCompany) dbgen.CreateCompanyParams { func ConvertCreateCompany(company CreateCompany, uniqueSlug string) dbgen.CreateCompanyParams {
return dbgen.CreateCompanyParams{ return dbgen.CreateCompanyParams{
Name: company.Name, Name: company.Name,
Slug: uniqueSlug,
AdminID: company.AdminID, AdminID: company.AdminID,
WalletID: company.WalletID, WalletID: company.WalletID,
DeductedPercentage: company.DeductedPercentage, DeductedPercentage: company.DeductedPercentage,
@ -129,6 +127,7 @@ func ConvertDBCompany(dbCompany dbgen.Company) Company {
return Company{ return Company{
ID: dbCompany.ID, ID: dbCompany.ID,
Name: dbCompany.Name, Name: dbCompany.Name,
Slug: dbCompany.Slug,
AdminID: dbCompany.AdminID, AdminID: dbCompany.AdminID,
WalletID: dbCompany.WalletID, WalletID: dbCompany.WalletID,
DeductedPercentage: dbCompany.DeductedPercentage, DeductedPercentage: dbCompany.DeductedPercentage,
@ -140,6 +139,7 @@ func ConvertDBCompanyDetails(dbCompany dbgen.CompaniesDetail) GetCompany {
return GetCompany{ return GetCompany{
ID: dbCompany.ID, ID: dbCompany.ID,
Name: dbCompany.Name, Name: dbCompany.Name,
Slug: dbCompany.Slug,
AdminID: dbCompany.AdminID, AdminID: dbCompany.AdminID,
WalletID: dbCompany.WalletID, WalletID: dbCompany.WalletID,
WalletBalance: Currency(dbCompany.Balance), WalletBalance: Currency(dbCompany.Balance),

View File

@ -3,9 +3,28 @@ package domain
import ( import (
"errors" "errors"
"fmt" "fmt"
"math"
"time" "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 type IntCurrency string
const ( 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 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 // TODO: turn status into an enum
// Status represents the status of an event. // Status represents the status of an event.
@ -35,100 +40,408 @@ const (
STATUS_REMOVED EventStatus = "removed" STATUS_REMOVED EventStatus = "removed"
) )
type Event struct { type EventSource string
ID string
SportID int32 const (
MatchName string EVENT_SOURCE_BET365 EventSource = "b365api"
HomeTeam string EVENT_SOURCE_BWIN EventSource = "bwin"
AwayTeam string EVENT_SOURCE_BETFAIR EventSource = "bfair"
HomeTeamID int32 EVENT_SOURCE_1XBET EventSource = "1xbet"
AwayTeamID int32 EVENT_SOURCE_ENET EventSource = "enetpulse"
HomeKitImage string )
AwayKitImage string
LeagueID int32 type BaseEvent struct {
LeagueName string ID string
LeagueCC string SportID int32
StartTime string MatchName string
Score string HomeTeam string
MatchMinute int AwayTeam string
TimerStatus string HomeTeamID int64
AddedTime int AwayTeamID int64
MatchPeriod int HomeTeamImage string
IsLive bool AwayTeamImage string
Status string LeagueID int64
Source string 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 { type CreateEvent struct {
Success int `json:"success"` ID string
Pager struct { SportID int32
Page int `json:"page"` MatchName string
PerPage int `json:"per_page"` HomeTeam string
Total int `json:"total"` AwayTeam string
} HomeTeamID int64
Results []struct { AwayTeamID int64
ID string `json:"id"` HomeTeamImage string
SportID string `json:"sport_id"` AwayTeamImage string
Time string `json:"time"` LeagueID int64
League struct { LeagueName string
ID string `json:"id"` StartTime time.Time
Name string `json:"name"` IsLive bool
} `json:"league"` Status EventStatus
Home struct { Source EventSource
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 UpcomingEvent struct { type EventWithSettingsRes struct {
ID string `json:"id"` // Event ID ID string `json:"id"`
SportID int32 `json:"sport_id"` // Sport ID SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"` // Match or event name MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"` // Home team name (if available) HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"` // Away team name (can be empty/null) AwayTeam string `json:"away_team"`
HomeTeamID int32 `json:"home_team_id"` // Home team ID HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int32 `json:"away_team_id"` // Away team ID (can be empty/null) AwayTeamID int64 `json:"away_team_id"`
HomeKitImage string `json:"home_kit_image"` // Kit or image for home team (optional) HomeTeamImage string `json:"home_team_image"`
AwayKitImage string `json:"away_kit_image"` // Kit or image for away team (optional) AwayTeamImage string `json:"away_team_image"`
LeagueID int32 `json:"league_id"` // League ID LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"` // League name LeagueName string `json:"league_name"`
LeagueCC string `json:"league_cc"` // League country code LeagueCC string `json:"league_cc"`
StartTime time.Time `json:"start_time"` // Converted from "time" field in UNIX format StartTime time.Time `json:"start_time"`
Source string `json:"source"` // bet api provider (bet365, betfair) Source EventSource `json:"source"`
Status EventStatus `json:"status"` //Match Status for event Status EventStatus `json:"status"`
IsFeatured bool `json:"is_featured"` //Whether the event is featured or not IsFeatured bool `json:"is_featured"`
IsActive bool `json:"is_active"` //Whether the event is featured or not IsMonitored bool `json:"is_monitored"`
} IsActive bool `json:"is_active"`
type MatchResult struct { WinningUpperLimit int32 `json:"winning_upper_limit"`
EventID string Score string `json:"score,omitempty"`
FullScore string MatchMinute int `json:"match_minute,omitempty"`
HalfScore string TimerStatus string `json:"timer_status,omitempty"`
Status string AddedTime int `json:"added_time,omitempty"`
Scores map[string]map[string]string 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 { type EventSettings struct {
ID int64 `json:"id"` CompanyID int64
EventID string `json:"event_id"` EventID string
MarketType string `json:"market_type"` IsActive ValidBool
Name string `json:"name"` IsFeatured ValidBool
HitStatus string `json:"hit_status"` WinningUpperLimit ValidInt
UpdatedAt time.Time
}
type CreateEventSettings struct {
CompanyID int64
EventID string
IsActive ValidBool
IsFeatured ValidBool
WinningUpperLimit ValidInt
} }
type EventFilter struct { type EventFilter struct {
Query ValidString Query ValidString
SportID ValidInt32 SportID ValidInt32
LeagueID ValidInt32 LeagueID ValidInt64
CountryCode ValidString CountryCode ValidString
FirstStartTime ValidTime FirstStartTime ValidTime
LastStartTime ValidTime LastStartTime ValidTime
Limit ValidInt64 Limit ValidInt32
Offset ValidInt64 Offset ValidInt32
MatchStatus ValidString // e.g., "upcoming", "in_play", "ended" MatchStatus ValidString // e.g., "upcoming", "in_play", "ended"
Featured ValidBool 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 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"` ID int64 `json:"id" example:"1"`
Name string `json:"name" example:"BPL"` Name string `json:"name" example:"BPL"`
CountryCode string `json:"cc" example:"uk"` CountryCode string `json:"cc" example:"uk"`
@ -9,6 +27,49 @@ type League struct {
SportID int32 `json:"sport_id" example:"1"` SportID int32 `json:"sport_id" example:"1"`
IsFeatured bool `json:"is_featured" example:"false"` 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 { type UpdateLeague struct {
ID int64 `json:"id" example:"1"` ID int64 `json:"id" example:"1"`
@ -29,64 +90,87 @@ type LeagueFilter struct {
Offset ValidInt64 Offset ValidInt64
} }
// These leagues are automatically featured when the league is created func ConvertCreateLeague(league CreateLeague) dbgen.InsertLeagueParams {
var FeaturedLeagues = []int64{ return dbgen.InsertLeagueParams{
// Football ID: league.ID,
10044469, // Ethiopian Premier League Name: league.Name,
10041282, //Premier League CountryCode: league.CountryCode.ToPG(),
10083364, //La Liga Bet365ID: league.Bet365ID.ToPG(),
10041095, //German Bundesliga SportID: league.SportID,
10041100, //Ligue 1 DefaultIsActive: league.DefaultIsActive,
10041809, //UEFA Champions League DefaultIsFeatured: league.DefaultIsFeatured,
10041957, //UEFA Europa League }
10079560, //UEFA Conference League }
10050282, //UEFA Nations League
10044685, //FIFA Club World Cup func ConvertCreateLeagueSettings(leagueSetting CreateLeagueSettings) dbgen.InsertLeagueSettingsParams {
10050346, //UEFA Super Cup return dbgen.InsertLeagueSettingsParams{
10081269, //CONCACAF Champions Cup CompanyID: leagueSetting.CompanyID,
10070189, //CONCACAF Gold Cup LeagueID: leagueSetting.LeagueID,
10076185, //UEFA Regions Cup IsActive: leagueSetting.IsActive.ToPG(),
IsFeatured: leagueSetting.IsFeatured.ToPG(),
10067913, //Europe - World Cup Qualifying }
10040162, //Asia - World Cup Qualifying }
10067624, //South America - World Cup Qualifying
10073057, //North & Central America - World Cup Qualifying func ConvertDBBaseLeague(league dbgen.League) BaseLeague {
return BaseLeague{
10037075, //International Match ID: league.ID,
10077480, //Womens International Name: league.Name,
10037109, //Europe Friendlies CountryCode: ValidString{
10068837, //Euro U21 Value: league.CountryCode.String,
Valid: league.CountryCode.Valid,
10041315, //Italian Serie A },
10036538, //Spain Segunda Bet365ID: ValidInt32{
10047168, // US MLS Value: league.Bet365ID.Int32,
Valid: league.Bet365ID.Valid,
10043156, //England FA Cup },
10042103, //France Cup SportID: league.SportID,
10041088, //Premier League 2 DefaultIsActive: league.DefaultIsActive,
10084250, //Turkiye Super League DefaultIsFeatured: league.DefaultIsFeatured,
10041187, //Kenya Super League }
10041391, //Netherlands Eredivisie }
// Basketball func ConvertDBBaseLeagues(leagues []dbgen.League) []BaseLeague {
10041830, //NBA result := make([]BaseLeague, len(leagues))
10049984, //WNBA for i, league := range leagues {
10037165, //German Bundesliga result[i] = ConvertDBBaseLeague(league)
10036608, //Italian Lega 1 }
10040795, //EuroLeague return result
10041534, //Basketball Africa League }
// Ice Hockey func ConvertDBLeagueWithSetting(lws dbgen.LeagueWithSetting) LeagueWithSettings {
10037477, //NHL return LeagueWithSettings{
10037447, //AHL ID: lws.ID,
10069385, //IIHF World Championship Name: lws.Name,
CompanyID: lws.CompanyID,
// AMERICAN FOOTBALL CountryCode: ValidString{
10037219, //NFL Value: lws.CountryCode.String,
Valid: lws.CountryCode.Valid,
// BASEBALL },
10037485, // MLB Bet365ID: ValidInt32{
Value: lws.Bet365ID.Int32,
// VOLLEYBALL Valid: lws.Bet365ID.Valid,
10069666, //FIVB Nations League },
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 // The Market ID for the json data can be either string / int which is causing problems when UnMarshalling
type OddsMarket struct { type OddsMarket struct {
ID NullableInt64JSON `json:"id"` ID ValidInt64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Odds []json.RawMessage `json:"odds"` Odds []json.RawMessage `json:"odds"`
Header string `json:"header,omitempty"` Header string `json:"header,omitempty"`

View File

@ -1,49 +1,186 @@
package domain package domain
import ( import (
"encoding/json"
"time" "time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/jackc/pgx/v5/pgtype"
) )
type RawMessage interface{} type CreateOddMarket struct {
type Market struct {
EventID string EventID string
FI string
MarketCategory string MarketCategory string
MarketType string MarketType string
MarketName string MarketName string
MarketID string MarketID string
UpdatedAt time.Time UpdatedAt time.Time
Odds []map[string]interface{} Odds []map[string]interface{}
Name string
Handicap string
OddsVal float64
Source string
} }
type Odd struct { type OddMarket struct {
EventID string `json:"event_id"` ID int64 `json:"id"`
Fi string `json:"fi"` EventID string `json:"event_id"`
MarketType string `json:"market_type"` MarketType string `json:"market_type"`
MarketName string `json:"market_name"` MarketName string `json:"market_name"`
MarketCategory string `json:"market_category"` MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"` MarketID string `json:"market_id"`
Name string `json:"name"` RawOdds []json.RawMessage `json:"raw_odds"`
Handicap string `json:"handicap"` FetchedAt time.Time `json:"fetched_at"`
OddsValue float64 `json:"odds_value"` ExpiresAt time.Time `json:"expires_at"`
Section string `json:"section"` DefaultIsActive bool `json:"is_active"`
Category string `json:"category"` IsMonitored bool `json:"is_monitored"`
RawOdds []RawMessage `json:"raw_odds"` IsLive bool `json:"is_live"`
FetchedAt time.Time `json:"fetched_at"` Status EventStatus `json:"status"`
Source string `json:"source"` Source EventSource `json:"source"`
IsActive bool `json:"is_active"`
} }
type RawOddsByMarketID struct { type OddMarketWithSettings struct {
ID int64 `json:"id"` ID int64 `json:"id"`
MarketName string `json:"market_name"` EventID string `json:"event_id"`
Handicap string `json:"handicap"` MarketType string `json:"market_type"`
RawOdds []RawMessage `json:"raw_odds"` MarketName string `json:"market_name"`
FetchedAt time.Time `json:"fetched_at"` 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 ( import (
"time" "time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
) )
type MarketConfig struct { type MarketConfig struct {
@ -21,7 +23,7 @@ type Result struct {
FullTimeScore string FullTimeScore string
HalfTimeScore string HalfTimeScore string
SS string SS string
Scores map[string]Score Scores map[string]ScoreResultResponse
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
} }
@ -83,22 +85,78 @@ const (
TIME_STATUS_REMOVED TimeStatus = 99 TIME_STATUS_REMOVED TimeStatus = 99
) )
type ResultStatusCounts struct { type ResultLog struct {
IsNotFinished int `json:"is_not_finished"` ID int64 `json:"id"`
IsNotFinishedBets int `json:"is_not_finished_bets"` StatusNotFinishedCount int `json:"status_not_finished_count"`
IsToBeFixed int `json:"is_to_be_fixed"` StatusNotFinishedBets int `json:"status_not_finished_bets"`
IsToBeFixedBets int `json:"is_to_be_fixed_bets"` StatusToBeFixedCount int `json:"status_to_be_fixed_count"`
IsPostponed int `json:"is_postponed"` StatusToBeFixedBets int `json:"status_to_be_fixed_bets"`
IsPostponedBets int `json:"is_postponed_bets"` StatusPostponedCount int `json:"status_postponed_count"`
IsEnded int `json:"is_ended"` StatusPostponedBets int `json:"status_postponed_bets"`
IsEndedBets int `json:"is_ended_bets"` StatusEndedCount int `json:"status_ended_count"`
IsRemoved int `json:"is_removed"` StatusEndedBets int `json:"status_ended_bets"`
IsRemovedBets int `json:"is_removed_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 { type ResultStatusBets struct {
IsNotFinished []int64 `json:"is_not_finished"` StatusNotFinished []int64 `json:"status_not_finished"`
IsToBeFixed []int64 `json:"is_to_be_fixed"` StatusToBeFixed []int64 `json:"status_to_be_fixed"`
IsPostponed []int64 `json:"is_postponed"` StatusPostponed []int64 `json:"status_postponed"`
IsEnded []int64 `json:"is_ended"` StatusEnded []int64 `json:"status_ended"`
IsRemoved []int64 `json:"is_removed"` 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"` Results []json.RawMessage `json:"results"`
} }
type LeagueRes struct { type LeagueResultResponse struct {
ID string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
CC string `json:"cc"` CC string `json:"cc"`
} }
type Team struct { type TeamResultResponse struct {
ID string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
ImageID NullableInt64JSON `json:"image_id"` ImageID ValidInt64 `json:"image_id"`
CC string `json:"cc"` CC string `json:"cc"`
} }
type Score struct { type ScoreResultResponse struct {
Home string `json:"home"` Home string `json:"home"`
Away string `json:"away"` Away string `json:"away"`
} }
type CommonResultResponse struct { type CommonResultResponse struct {
ID string `json:"id"` ID string `json:"id"`
SportID string `json:"sport_id"` SportID string `json:"sport_id"`
Time string `json:"time"` Time string `json:"time"`
TimeStatus NullableInt64JSON `json:"time_status"` TimeStatus ValidInt64 `json:"time_status"`
League LeagueRes `json:"league"` League LeagueResultResponse `json:"league"`
Home Team `json:"home"` Home TeamResultResponse `json:"home"`
Away Team `json:"away"` Away TeamResultResponse `json:"away"`
SS string `json:"ss"` SS string `json:"ss"`
} }
type FootballResultResponse struct { type FootballResultResponse struct {
ID string `json:"id"` ID string `json:"id"`
SportID string `json:"sport_id"` SportID string `json:"sport_id"`
Time string `json:"time"` Time string `json:"time"`
TimeStatus string `json:"time_status"` TimeStatus string `json:"time_status"`
League LeagueRes `json:"league"` League LeagueResultResponse `json:"league"`
Home Team `json:"home"` Home TeamResultResponse `json:"home"`
Away Team `json:"away"` Away TeamResultResponse `json:"away"`
SS string `json:"ss"` SS string `json:"ss"`
Scores struct { Scores struct {
FirstHalf Score `json:"1"` FirstHalf ScoreResultResponse `json:"1"`
SecondHalf Score `json:"2"` SecondHalf ScoreResultResponse `json:"2"`
} `json:"scores"` } `json:"scores"`
Stats struct { Stats struct {
Attacks []string `json:"attacks"` Attacks []string `json:"attacks"`
@ -78,21 +78,21 @@ type FootballResultResponse struct {
} }
type BasketballResultResponse struct { type BasketballResultResponse struct {
ID string `json:"id"` ID string `json:"id"`
SportID string `json:"sport_id"` SportID string `json:"sport_id"`
Time string `json:"time"` Time string `json:"time"`
TimeStatus string `json:"time_status"` TimeStatus string `json:"time_status"`
League LeagueRes `json:"league"` League LeagueResultResponse `json:"league"`
Home Team `json:"home"` Home TeamResultResponse `json:"home"`
Away Team `json:"away"` Away TeamResultResponse `json:"away"`
SS string `json:"ss"` SS string `json:"ss"`
Scores struct { Scores struct {
FirstQuarter Score `json:"1"` FirstQuarter ScoreResultResponse `json:"1"`
SecondQuarter Score `json:"2"` SecondQuarter ScoreResultResponse `json:"2"`
FirstHalf Score `json:"3"` FirstHalf ScoreResultResponse `json:"3"`
ThirdQuarter Score `json:"4"` ThirdQuarter ScoreResultResponse `json:"4"`
FourthQuarter Score `json:"5"` FourthQuarter ScoreResultResponse `json:"5"`
TotalScore Score `json:"7"` TotalScore ScoreResultResponse `json:"7"`
} `json:"scores"` } `json:"scores"`
Stats struct { Stats struct {
TwoPoints []string `json:"2points"` TwoPoints []string `json:"2points"`
@ -125,19 +125,19 @@ type BasketballResultResponse struct {
Bet365ID string `json:"bet365_id"` Bet365ID string `json:"bet365_id"`
} }
type IceHockeyResultResponse struct { type IceHockeyResultResponse struct {
ID string `json:"id"` ID string `json:"id"`
SportID string `json:"sport_id"` SportID string `json:"sport_id"`
Time string `json:"time"` Time string `json:"time"`
TimeStatus string `json:"time_status"` TimeStatus string `json:"time_status"`
League LeagueRes `json:"league"` League LeagueResultResponse `json:"league"`
Home Team `json:"home"` Home TeamResultResponse `json:"home"`
Away Team `json:"away"` Away TeamResultResponse `json:"away"`
SS string `json:"ss"` SS string `json:"ss"`
Scores struct { Scores struct {
FirstPeriod Score `json:"1"` FirstPeriod ScoreResultResponse `json:"1"`
SecondPeriod Score `json:"2"` SecondPeriod ScoreResultResponse `json:"2"`
ThirdPeriod Score `json:"3"` ThirdPeriod ScoreResultResponse `json:"3"`
TotalScore Score `json:"5"` TotalScore ScoreResultResponse `json:"5"`
} `json:"scores"` } `json:"scores"`
Stats struct { Stats struct {
@ -222,11 +222,11 @@ type VolleyballResultResponse struct {
} `json:"away"` } `json:"away"`
SS string `json:"ss"` SS string `json:"ss"`
Scores struct { Scores struct {
FirstSet Score `json:"1"` FirstSet ScoreResultResponse `json:"1"`
SecondSet Score `json:"2"` SecondSet ScoreResultResponse `json:"2"`
ThirdSet Score `json:"3"` ThirdSet ScoreResultResponse `json:"3"`
FourthSet Score `json:"4"` FourthSet ScoreResultResponse `json:"4"`
FivethSet Score `json:"5"` FivethSet ScoreResultResponse `json:"5"`
} `json:"scores"` } `json:"scores"`
Stats struct { Stats struct {
PointsWonOnServe []string `json:"points_won_on_serve"` PointsWonOnServe []string `json:"points_won_on_serve"`
@ -290,10 +290,10 @@ type FutsalResultResponse struct {
} `json:"away"` } `json:"away"`
SS string `json:"ss"` SS string `json:"ss"`
Scores struct { Scores struct {
FirstPeriod Score `json:"1"` FirstPeriod ScoreResultResponse `json:"1"`
SecondPeriod Score `json:"2"` SecondPeriod ScoreResultResponse `json:"2"`
ThirdPeriod Score `json:"3"` ThirdPeriod ScoreResultResponse `json:"3"`
TotalScore Score `json:"4"` TotalScore ScoreResultResponse `json:"4"`
} `json:"scores"` } `json:"scores"`
Events []map[string]string `json:"events"` Events []map[string]string `json:"events"`
InplayCreatedAt string `json:"inplay_created_at"` InplayCreatedAt string `json:"inplay_created_at"`
@ -327,12 +327,12 @@ type NFLResultResponse struct {
} `json:"away"` } `json:"away"`
SS string `json:"ss"` SS string `json:"ss"`
Scores struct { Scores struct {
FirstQuarter Score `json:"1"` FirstQuarter ScoreResultResponse `json:"1"`
SecondQuarter Score `json:"2"` SecondQuarter ScoreResultResponse `json:"2"`
ThirdQuarter Score `json:"3"` ThirdQuarter ScoreResultResponse `json:"3"`
FourthQuarter Score `json:"4"` FourthQuarter ScoreResultResponse `json:"4"`
Overtime Score `json:"5"` Overtime ScoreResultResponse `json:"5"`
TotalScore Score `json:"7"` TotalScore ScoreResultResponse `json:"7"`
} `json:"scores"` } `json:"scores"`
Stats struct { Stats struct {
FirstDowns []string `json:"first_downs"` FirstDowns []string `json:"first_downs"`
@ -381,9 +381,9 @@ type RugbyResultResponse struct {
} `json:"away"` } `json:"away"`
SS string `json:"ss"` SS string `json:"ss"`
Scores struct { Scores struct {
FirstHalf Score `json:"1"` FirstHalf ScoreResultResponse `json:"1"`
SecondHalf Score `json:"2"` SecondHalf ScoreResultResponse `json:"2"`
TotalScore Score `json:"7"` TotalScore ScoreResultResponse `json:"7"`
} `json:"scores"` } `json:"scores"`
Stats struct { Stats struct {
Tries []string `json:"tries"` Tries []string `json:"tries"`
@ -433,17 +433,17 @@ type BaseballResultResponse struct {
} `json:"away"` } `json:"away"`
SS string `json:"ss"` SS string `json:"ss"`
Scores struct { Scores struct {
FirstInning Score `json:"1"` FirstInning ScoreResultResponse `json:"1"`
SecondInning Score `json:"2"` SecondInning ScoreResultResponse `json:"2"`
ThirdInning Score `json:"3"` ThirdInning ScoreResultResponse `json:"3"`
FourthInning Score `json:"4"` FourthInning ScoreResultResponse `json:"4"`
FifthInning Score `json:"5"` FifthInning ScoreResultResponse `json:"5"`
SixthInning Score `json:"6"` SixthInning ScoreResultResponse `json:"6"`
SeventhInning Score `json:"7"` SeventhInning ScoreResultResponse `json:"7"`
EighthInning Score `json:"8"` EighthInning ScoreResultResponse `json:"8"`
NinthInning Score `json:"9"` NinthInning ScoreResultResponse `json:"9"`
ExtraInnings Score `json:"10"` ExtraInnings ScoreResultResponse `json:"10"`
TotalScore Score `json:"11"` TotalScore ScoreResultResponse `json:"11"`
} `json:"scores"` } `json:"scores"`
Stats struct { Stats struct {
Hits []string `json:"hits"` Hits []string `json:"hits"`

View File

@ -9,3 +9,12 @@ const (
RoleCustomer Role = "customer" RoleCustomer Role = "customer"
RoleCashier Role = "cashier" 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 ( import (
"time" "time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
) )
type Setting struct { type Setting struct {
@ -11,68 +13,44 @@ type Setting struct {
} }
type SettingRes struct { type SettingRes struct {
Key string `json:"key"` Key string `json:"key"`
Value string `json:"value"` Value string `json:"value"`
UpdatedAt string `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
}
type CompanySetting struct {
Key string
Value string
CompanyID int64
UpdatedAt time.Time
CreatedAt time.Time
} }
type SettingList struct { type CompanySettingRes struct {
SMSProvider SMSProvider `json:"sms_provider"` Key string `json:"key"`
MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"` Value string `json:"value"`
BetAmountLimit Currency `json:"bet_amount_limit"` CompanyID int64 `json:"company_id"`
DailyTicketPerIP int64 `json:"daily_ticket_limit"` UpdatedAt time.Time `json:"updated_at"`
TotalWinningLimit Currency `json:"total_winning_limit"` CreatedAt time.Time `json:"created_at"`
AmountForBetReferral Currency `json:"amount_for_bet_referral"`
CashbackAmountCap Currency `json:"cashback_amount_cap"`
} }
type DBSettingList struct { func ConvertSetting(setting Setting) SettingRes {
SMSProvider ValidString return SettingRes(setting)
MaxNumberOfOutcomes ValidInt64
BetAmountLimit ValidInt64
DailyTicketPerIP ValidInt64
TotalWinningLimit ValidInt64
AmountForBetReferral ValidInt64
CashbackAmountCap ValidInt64
} }
func ConvertInt64SettingsMap(dbSettingList *DBSettingList) map[string]*ValidInt64 { func ConvertCompanySetting(companySetting dbgen.CompanySetting) CompanySetting {
return map[string]*ValidInt64{ return CompanySetting{
"max_number_of_outcomes": &dbSettingList.MaxNumberOfOutcomes, Key: companySetting.Key,
"bet_amount_limit": &dbSettingList.BetAmountLimit, Value: companySetting.Value,
"daily_ticket_limit": &dbSettingList.DailyTicketPerIP, CompanyID: companySetting.CompanyID,
"total_winnings_limit": &dbSettingList.TotalWinningLimit, UpdatedAt: companySetting.UpdatedAt.Time,
"amount_for_bet_referral": &dbSettingList.AmountForBetReferral, CreatedAt: companySetting.CreatedAt.Time,
"cashback_amount_cap": &dbSettingList.CashbackAmountCap,
} }
} }
func ConvertStringSettingsMap(dbSettingList *DBSettingList) map[string]*ValidString { func ConvertCompanySettings(settings []dbgen.CompanySetting) []CompanySetting {
return map[string]*ValidString{ result := make([]CompanySetting, 0, len(settings))
"sms_provider": &dbSettingList.SMSProvider, for _, setting := range settings {
} result = append(result, ConvertCompanySetting(setting))
}
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),
} }
return result
} }

View File

@ -39,6 +39,7 @@ type Ticket struct {
ID int64 ID int64
Amount Currency Amount Currency
TotalOdds float32 TotalOdds float32
CompanyID int64
} }
type GetTicket struct { type GetTicket struct {
@ -46,12 +47,14 @@ type GetTicket struct {
Amount Currency Amount Currency
TotalOdds float32 TotalOdds float32
Outcomes []TicketOutcome Outcomes []TicketOutcome
CompanyID int64
} }
type CreateTicket struct { type CreateTicket struct {
Amount Currency Amount Currency
TotalOdds float32 TotalOdds float32
IP string IP string
CompanyID int64
} }
type CreateTicketOutcomeReq struct { type CreateTicketOutcomeReq struct {
@ -80,4 +83,9 @@ type TicketRes struct {
Outcomes []TicketOutcome `json:"outcomes"` Outcomes []TicketOutcome `json:"outcomes"`
Amount float32 `json:"amount" example:"100.0"` Amount float32 `json:"amount" example:"100.0"`
TotalOdds float32 `json:"total_odds" example:"4.22"` 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 { type User struct {
ID int64 ID int64
FirstName string FirstName string
LastName string LastName string
Email string `json:"email"` Email string `json:"email"`
PhoneNumber string `json:"phone_number"` PhoneNumber string `json:"phone_number"`
Password []byte Password []byte
Role Role Role Role
//
EmailVerified bool EmailVerified bool
PhoneVerified bool PhoneVerified bool
// CreatedAt time.Time
CreatedAt time.Time UpdatedAt time.Time
UpdatedAt time.Time SuspendedAt time.Time
// Suspended bool
SuspendedAt time.Time CompanyID ValidInt64 //This should be null
Suspended bool
//
CompanyID ValidInt64
} }
type UserFilter struct { type UserFilter struct {
@ -39,10 +35,7 @@ type UserFilter struct {
CreatedBefore ValidTime CreatedBefore ValidTime
CreatedAfter ValidTime CreatedAfter ValidTime
} }
type ValidRole struct {
Value Role
Valid bool
}
type RegisterUserReq struct { type RegisterUserReq struct {
FirstName string FirstName string
@ -54,6 +47,7 @@ type RegisterUserReq struct {
Otp string Otp string
ReferralCode string `json:"referral_code"` ReferralCode string `json:"referral_code"`
OtpMedium OtpMedium OtpMedium OtpMedium
CompanyID ValidInt64
} }
type CreateUserReq struct { type CreateUserReq struct {
FirstName string 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

@ -10,8 +10,8 @@ import (
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
"github.com/jackc/pgx/v5/pgtype" "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{ user, err := s.queries.GetUserByEmailPhone(ctx, dbgen.GetUserByEmailPhoneParams{
Email: pgtype.Text{ Email: pgtype.Text{
String: email, String: email,
@ -21,6 +21,7 @@ func (s *Store) GetUserByEmailPhone(ctx context.Context, email, phone string) (d
String: phone, String: phone,
Valid: true, Valid: true,
}, },
CompanyID: companyID.ToPG(),
}) })
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {

View File

@ -19,115 +19,14 @@ var (
mongoLogger *zap.Logger 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) { 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 { if err != nil {
fmt.Println("We are here") fmt.Println("We are here")
logger.Error("Failed to create bet", slog.String("error", err.Error()), slog.Any("bet", bet)) logger.Error("Failed to create bet", slog.String("error", err.Error()), slog.Any("bet", bet))
return domain.Bet{}, err 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)) var dbParams []dbgen.CreateBetOutcomeParams = make([]dbgen.CreateBetOutcomeParams, 0, len(outcomes))
for _, outcome := range outcomes { for _, outcome := range outcomes {
dbParams = append(dbParams, convertDBCreateBetOutcome(outcome)) dbParams = append(dbParams, domain.ConvertDBCreateBetOutcome(outcome))
} }
rows, err := s.queries.CreateBetOutcome(ctx, dbParams) 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, Int64: flag.BetID,
Valid: flag.BetID != 0, Valid: flag.BetID != 0,
}, },
OddID: pgtype.Int8{ OddsMarketID: pgtype.Int8{
Int64: flag.OddID, Int64: flag.OddID,
Valid: flag.OddID != 0, Valid: flag.OddID != 0,
}, },
@ -177,7 +76,7 @@ func (s *Store) CreateFlag(ctx context.Context, flag domain.CreateFlagReq) (doma
return domain.Flag{}, err 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) { 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 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) { func (s *Store) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]domain.GetBet, error) {
bets, err := s.queries.GetAllBets(ctx, dbgen.GetAllBetsParams{ bets, err := s.queries.GetAllBets(ctx, dbgen.GetAllBetsParams{
UserID: pgtype.Int8{ UserID: filter.UserID.ToPG(),
Int64: filter.UserID.Value, CompanyID: filter.CompanyID.ToPG(),
Valid: filter.UserID.Valid, CashedOut: filter.CashedOut.ToPG(),
}, IsShopBet: filter.IsShopBet.ToPG(),
CashedOut: pgtype.Bool{ Query: filter.Query.ToPG(),
Bool: filter.CashedOut.Value, CreatedBefore: filter.CreatedBefore.ToPG(),
Valid: filter.CashedOut.Valid, CreatedAfter: filter.CreatedAfter.ToPG(),
},
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,
},
}) })
if err != nil { if err != nil {
domain.MongoDBLogger.Error("failed to get all bets", 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)) var result []domain.GetBet = make([]domain.GetBet, 0, len(bets))
for _, bet := range bets { for _, bet := range bets {
result = append(result, convertDBBetWithOutcomes(bet)) result = append(result, domain.ConvertDBBetWithOutcomes(bet))
} }
return result, nil 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)) var result []domain.GetBet = make([]domain.GetBet, 0, len(bets))
for _, bet := range bets { for _, bet := range bets {
result = append(result, convertDBBetWithOutcomes(bet)) result = append(result, domain.ConvertDBBetWithOutcomes(bet))
} }
return result, nil return result, nil
@ -258,7 +140,7 @@ func (s *Store) GetBetByFastCode(ctx context.Context, fastcode string) (domain.G
return domain.GetBet{}, err return domain.GetBet{}, err
} }
return convertDBBetWithOutcomes(bet), nil return domain.ConvertDBBetWithOutcomes(bet), nil
} }
func (s *Store) GetBetsForCashback(ctx context.Context) ([]domain.GetBet, error) { 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 { for _, bet := range bets {
cashbackBet := convertDBBetWithOutcomes(bet) cashbackBet := domain.ConvertDBBetWithOutcomes(bet)
res = append(res, cashbackBet) 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)) var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
for _, outcome := range outcomes { for _, outcome := range outcomes {
result = append(result, convertDBBetOutcomes(outcome)) result = append(result, domain.ConvertDBBetOutcomes(outcome))
} }
return result, nil 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)) var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
for _, outcome := range outcomes { for _, outcome := range outcomes {
result = append(result, convertDBBetOutcomes(outcome)) result = append(result, domain.ConvertDBBetOutcomes(outcome))
} }
return result, nil return result, nil
} }
@ -397,7 +279,7 @@ func (s *Store) UpdateBetOutcomeStatus(ctx context.Context, id int64, status dom
return domain.BetOutcome{}, err return domain.BetOutcome{}, err
} }
res := convertDBBetOutcomes(update) res := domain.ConvertDBBetOutcomes(update)
return res, nil return res, nil
} }
@ -415,7 +297,7 @@ func (s *Store) UpdateBetOutcomeStatusByBetID(ctx context.Context, id int64, sta
return domain.BetOutcome{}, err return domain.BetOutcome{}, err
} }
res := convertDBBetOutcomes(update) res := domain.ConvertDBBetOutcomes(update)
return res, nil 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)) var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
for _, outcome := range outcomes { for _, outcome := range outcomes {
result = append(result, convertDBBetOutcomes(outcome)) result = append(result, domain.ConvertDBBetOutcomes(outcome))
} }
return result, nil return result, nil
} }

View File

@ -9,7 +9,6 @@ import (
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
) )
func (s *Store) CreateBranch(ctx context.Context, branch domain.CreateBranch) (domain.Branch, error) { func (s *Store) CreateBranch(ctx context.Context, branch domain.CreateBranch) (domain.Branch, error) {
dbBranch, err := s.queries.CreateBranch(ctx, domain.ConvertCreateBranch(branch)) 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) { func (s *Store) GetAllBranches(ctx context.Context, filter domain.BranchFilter) ([]domain.BranchDetail, error) {
dbBranches, err := s.queries.GetAllBranches(ctx, dbgen.GetAllBranchesParams{ dbBranches, err := s.queries.GetAllBranches(ctx, dbgen.GetAllBranchesParams{
CompanyID: pgtype.Int8{ CompanyID: filter.CompanyID.ToPG(),
Int64: filter.CompanyID.Value, BranchManagerID: filter.BranchManagerID.ToPG(),
Valid: filter.CompanyID.Valid, Query: filter.Query.ToPG(),
}, CreatedBefore: filter.CreatedBefore.ToPG(),
BranchManagerID: pgtype.Int8{ CreatedAfter: filter.CreatedAfter.ToPG(),
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,
},
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -2,14 +2,36 @@ package repository
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt" "fmt"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/pkgs/helpers"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
) )
func (s *Store) CreateCompany(ctx context.Context, company domain.CreateCompany) (domain.Company, error) { 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 { if err != nil {
return domain.Company{}, err return domain.Company{}, err
} }
@ -56,6 +78,15 @@ func (s *Store) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany
return domain.ConvertDBCompanyDetails(dbCompany), nil 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) { func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) {
dbCompany, err := s.queries.UpdateCompany(ctx, domain.ConvertUpdateCompany(company)) 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" "context"
"fmt" "fmt"
"math" "math"
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
@ -13,90 +12,29 @@ import (
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
) )
func (s *Store) SaveEvent(ctx context.Context, e domain.Event) error { func (s *Store) SaveEvent(ctx context.Context, e domain.CreateEvent) error {
parsedTime, err := time.Parse(time.RFC3339, e.StartTime) return s.queries.InsertEvent(ctx, domain.ConvertCreateEvent(e))
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) SaveUpcomingEvent(ctx context.Context, e domain.UpcomingEvent) error {
return s.queries.InsertUpcomingEvent(ctx, dbgen.InsertUpcomingEventParams{ func (s *Store) InsertEventSettings(ctx context.Context, eventSetting domain.CreateEventSettings) error {
ID: e.ID, return s.queries.InsertEventSettings(ctx, domain.ConvertCreateEventSettings(eventSetting))
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) GetLiveEventIDs(ctx context.Context) ([]string, error) { func (s *Store) GetLiveEventIDs(ctx context.Context) ([]string, error) {
return s.queries.ListLiveEvents(ctx) 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) events, err := s.queries.GetAllUpcomingEvents(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
upcomingEvents := make([]domain.UpcomingEvent, len(events)) return domain.ConvertDBEvents(events), nil
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
} }
func (s *Store) GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, error) { func (s *Store) GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.BaseEvent, error) {
events, err := s.queries.GetExpiredUpcomingEvents(ctx, pgtype.Text{ events, err := s.queries.GetExpiredEvents(ctx, pgtype.Text{
String: filter.MatchStatus.Value, String: filter.MatchStatus.Value,
Valid: filter.MatchStatus.Valid, Valid: filter.MatchStatus.Valid,
}) })
@ -104,163 +42,98 @@ func (s *Store) GetExpiredUpcomingEvents(ctx context.Context, filter domain.Even
return nil, err return nil, err
} }
upcomingEvents := make([]domain.UpcomingEvent, len(events)) return domain.ConvertDBEvents(events), nil
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
} }
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{ events, err := s.queries.GetPaginatedUpcomingEvents(ctx, dbgen.GetPaginatedUpcomingEventsParams{
LeagueID: pgtype.Int4{ LeagueID: filter.LeagueID.ToPG(),
Int32: int32(filter.LeagueID.Value), SportID: filter.SportID.ToPG(),
Valid: filter.LeagueID.Valid, Query: filter.Query.ToPG(),
}, Limit: filter.Limit.ToPG(),
SportID: pgtype.Int4{ Offset: filter.Offset.ToPG(),
Int32: int32(filter.SportID.Value), FirstStartTime: filter.FirstStartTime.ToPG(),
Valid: filter.SportID.Valid, LastStartTime: filter.LastStartTime.ToPG(),
}, CountryCode: filter.CountryCode.ToPG(),
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,
},
}) })
if err != nil { if err != nil {
return nil, 0, err 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{ totalCount, err := s.queries.GetTotalEvents(ctx, dbgen.GetTotalEventsParams{
LeagueID: pgtype.Int4{ LeagueID: filter.LeagueID.ToPG(),
Int32: int32(filter.LeagueID.Value), SportID: filter.SportID.ToPG(),
Valid: filter.LeagueID.Valid, Query: filter.Query.ToPG(),
}, FirstStartTime: filter.FirstStartTime.ToPG(),
SportID: pgtype.Int4{ LastStartTime: filter.LastStartTime.ToPG(),
Int32: int32(filter.SportID.Value), CountryCode: filter.CountryCode.ToPG(),
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,
},
}) })
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value)) 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 { if err != nil {
return domain.UpcomingEvent{}, err return nil, 0, err
} }
return domain.UpcomingEvent{ totalCount, err := s.queries.GetTotalCompanyEvents(ctx, dbgen.GetTotalCompanyEventsParams{
ID: event.ID, CompanyID: companyID,
SportID: event.SportID.Int32, LeagueID: filter.LeagueID.ToPG(),
MatchName: event.MatchName.String, SportID: filter.SportID.ToPG(),
HomeTeam: event.HomeTeam.String, Query: filter.Query.ToPG(),
AwayTeam: event.AwayTeam.String, FirstStartTime: filter.FirstStartTime.ToPG(),
HomeTeamID: event.HomeTeamID.Int32, LastStartTime: filter.LastStartTime.ToPG(),
AwayTeamID: event.AwayTeamID.Int32, CountryCode: filter.CountryCode.ToPG(),
HomeKitImage: event.HomeKitImage.String, })
AwayKitImage: event.AwayKitImage.String, if err != nil {
LeagueID: event.LeagueID.Int32, return nil, 0, err
LeagueName: event.LeagueName.String, }
LeagueCC: event.LeagueCc.String,
StartTime: event.StartTime.Time.UTC(), numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value))
Source: event.Source.String, return domain.ConvertDBEventWithSettings(events), int64(numberOfPages), nil
Status: domain.EventStatus(event.Status.String), }
IsFeatured: event.IsFeatured, func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.BaseEvent, error) {
}, nil 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 { func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore string, status domain.EventStatus) error {
params := dbgen.UpdateMatchResultParams{ params := dbgen.UpdateMatchResultParams{
Score: pgtype.Text{String: fullScore, Valid: true}, Score: pgtype.Text{String: fullScore, Valid: true},
Status: pgtype.Text{String: string(status), Valid: true}, Status: string(status),
ID: eventID, 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 { func (s *Store) UpdateEventStatus(ctx context.Context, eventID string, status domain.EventStatus) error {
params := dbgen.UpdateMatchResultParams{ params := dbgen.UpdateMatchResultParams{
Status: pgtype.Text{ Status: string(status),
String: string(status), ID: eventID,
Valid: true,
},
ID: eventID,
} }
err := s.queries.UpdateMatchResult(ctx, params) 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 { func (s *Store) IsEventMonitored(ctx context.Context, eventID string) (bool, error) {
return s.queries.UpdateFeatured(ctx, dbgen.UpdateFeaturedParams{ isMonitored, err := s.queries.IsEventMonitored(ctx, eventID)
ID: eventID,
IsFeatured: isFeatured, 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 { func (s *Store) DeleteEvent(ctx context.Context, eventID string) error {
err := s.queries.DeleteEvent(ctx, eventID) err := s.queries.DeleteEvent(ctx, eventID)
if err != nil { 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" "github.com/jackc/pgx/v5/pgtype"
) )
func (s *Store) SaveLeague(ctx context.Context, l domain.League) error { func (s *Store) SaveLeague(ctx context.Context, league domain.CreateLeague) error {
return s.queries.InsertLeague(ctx, dbgen.InsertLeagueParams{ return s.queries.InsertLeague(ctx, domain.ConvertCreateLeague(league))
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) 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{ l, err := s.queries.GetAllLeagues(ctx, dbgen.GetAllLeaguesParams{
CountryCode: pgtype.Text{ CountryCode: filter.CountryCode.ToPG(),
String: filter.CountryCode.Value, SportID: filter.SportID.ToPG(),
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,
},
Limit: pgtype.Int4{ Limit: pgtype.Int4{
Int32: int32(filter.Limit.Value), Int32: int32(filter.Limit.Value),
Valid: filter.Limit.Valid, Valid: filter.Limit.Valid,
@ -51,85 +33,38 @@ func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) (
return nil, err return nil, err
} }
leagues := make([]domain.League, len(l)) return domain.ConvertDBBaseLeagues(l), nil
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
} }
func (s *Store) GetFeaturedLeagues(ctx context.Context) ([]domain.League, error) { func (s *Store) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, error) {
l, err := s.queries.GetFeaturedLeagues(ctx) 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 { if err != nil {
return nil, err return nil, err
} }
leagues := make([]domain.League, len(l)) return domain.ConvertDBLeagueWithSettings(l), nil
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
} }
func (s *Store) CheckLeagueSupport(ctx context.Context, leagueID int64) (bool, error) { func (s *Store) CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error) {
return s.queries.CheckLeagueSupport(ctx, leagueID) return s.queries.CheckLeagueSupport(ctx, dbgen.CheckLeagueSupportParams{
} LeagueID: leagueID,
CompanyID: companyID,
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) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error { func (s *Store) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error {
err := s.queries.UpdateLeague(ctx, dbgen.UpdateLeagueParams{ return s.queries.UpdateLeague(ctx, domain.ConvertUpdateLeague(league))
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
} }

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

View File

@ -8,93 +8,34 @@ import (
"github.com/jackc/pgx/v5/pgtype" "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) { func (s *Store) CreateResultLog(ctx context.Context, result domain.CreateResultLog) (domain.ResultLog, error) {
dbResult, err := s.queries.CreateResult(ctx, convertCreateResult(result)) dbResult, err := s.queries.CreateResultLog(ctx, domain.ConvertCreateResultLog(result))
if err != nil { 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 { func (s *Store) GetAllResultLog(ctx context.Context, filter domain.ResultFilter) ([]domain.ResultLog, error) {
return s.queries.InsertResult(ctx, convertResult(result)) dbResultLogs, err := s.queries.GetAllResultLog(ctx, dbgen.GetAllResultLogParams{
} CreatedBefore: pgtype.Timestamp{
Time: filter.CreatedBefore.Value,
func (s *Store) GetResultByBetOutcomeID(ctx context.Context, betOutcomeID int64) (domain.Result, error) { Valid: filter.CreatedBefore.Valid,
dbResult, err := s.queries.GetResultByBetOutcomeID(ctx, betOutcomeID) },
if err != nil { CreatedAfter: pgtype.Timestamp{
return domain.Result{}, err Time: filter.CreatedAfter.Value,
} Valid: filter.CreatedAfter.Valid,
return convertDBResult(dbResult), nil },
} })
func (s *Store) GetPendingBetOutcomes(ctx context.Context) ([]domain.BetOutcome, error) {
dbOutcomes, err := s.queries.GetPendingBetOutcomes(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
outcomes := make([]domain.BetOutcome, 0, len(dbOutcomes)) result := make([]domain.ResultLog, 0, len(dbResultLogs))
for _, dbOutcome := range dbOutcomes { for _, dbResultLog := range dbResultLogs {
outcomes = append(outcomes, domain.BetOutcome{ result = append(result, domain.ConvertDBResultLog(dbResultLog))
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,
})
} }
return outcomes, nil return result, nil
} }

View File

@ -2,116 +2,24 @@ package repository
import ( import (
"context" "context"
"fmt"
"strconv"
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"go.uber.org/zap" "go.uber.org/zap"
) )
func GetDBSettingList(settings []dbgen.Setting) (domain.SettingList, error) { func (s *Store) GetGlobalSettingList(ctx context.Context) (domain.SettingList, error) {
var dbSettingList domain.DBSettingList settings, err := s.queries.GetGlobalSettings(ctx)
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)
if err != nil { if err != nil {
domain.MongoDBLogger.Error("failed to get all settings", zap.Error(err)) 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) { func (s *Store) GetGlobalSettings(ctx context.Context) ([]domain.Setting, error) {
settings, err := s.queries.GetSettings(ctx) settings, err := s.queries.GetGlobalSettings(ctx)
if err != nil { if err != nil {
domain.MongoDBLogger.Error("failed to get all settings", zap.Error(err)) 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 return result, nil
} }
func (s *Store) GetSetting(ctx context.Context, key string) (domain.Setting, error) { func (s *Store) GetGlobalSetting(ctx context.Context, key string) (domain.Setting, error) {
dbSetting, err := s.queries.GetSetting(ctx, key) dbSetting, err := s.queries.GetGlobalSetting(ctx, key)
if err != nil { if err != nil {
domain.MongoDBLogger.Error("failed to get all settings", zap.Error(err)) 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 return result, nil
} }
func (s *Store) SaveSetting(ctx context.Context, key, value string) (domain.Setting, error) { func (s *Store) UpdateGlobalSetting(ctx context.Context, key, value string) error {
dbSetting, err := s.queries.SaveSetting(ctx, dbgen.SaveSettingParams{ err := s.queries.UpdateGlobalSetting(ctx, dbgen.UpdateGlobalSettingParams{
Key: key, Key: key,
Value: value, Value: value,
}) })
if err != nil { 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{ return err
Key: dbSetting.Key,
Value: dbSetting.Value,
}
return setting, 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)) var outcomes []domain.BetOutcome = make([]domain.BetOutcome, 0, len(bet.Outcomes))
for _, outcome := range bet.Outcomes { for _, outcome := range bet.Outcomes {
outcomes = append(outcomes, convertDBBetOutcomes(outcome)) outcomes = append(outcomes, domain.ConvertDBBetOutcomes(outcome))
} }
return domain.ShopBetDetail{ return domain.ShopBetDetail{
ID: bet.ID, ID: bet.ID,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,9 +7,10 @@ import (
) )
type Service interface { type Service interface {
SaveLeague(ctx context.Context, l domain.League) error SaveLeague(ctx context.Context, league domain.CreateLeague) error
GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.League, error) SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error
GetFeaturedLeagues(ctx context.Context) ([]domain.League, error) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error)
SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) 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 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 { func (s *service) SaveLeague(ctx context.Context, league domain.CreateLeague) error {
return s.store.SaveLeague(ctx, l) 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) return s.store.GetAllLeagues(ctx, filter)
} }
func (s *service) GetFeaturedLeagues(ctx context.Context) ([]domain.League, error) { func (s *service) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, error) {
return s.store.GetFeaturedLeagues(ctx) return s.store.GetAllLeaguesByCompany(ctx, companyID, filter)
} }
func (s *service) SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) error { func (s *service) CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error) {
return s.store.SetLeagueActive(ctx, leagueId, isActive) return s.store.CheckLeagueSupport(ctx, leagueID, companyID)
} }
func (s *service) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error { 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") 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 { if companyID.Valid {
return err 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 { switch settingsList.SMSProvider {

View File

@ -340,7 +340,7 @@ func (s *Service) SendNotificationSMS(ctx context.Context, recipientID int64, me
if user.PhoneNumber == "" { if user.PhoneNumber == "" {
return fmt.Errorf("Phone Number is invalid") 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 { if err != nil {
return err 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 FetchNonLiveOdds(ctx context.Context) error
FetchNonLiveOddsByEventID(ctx context.Context, eventIDStr string) (domain.BaseNonLiveOddResponse, error) FetchNonLiveOddsByEventID(ctx context.Context, eventIDStr string) (domain.BaseNonLiveOddResponse, error)
ParseOddSections(ctx context.Context, res json.RawMessage, sportID int64) (domain.ParseOddSectionsRes, error) ParseOddSections(ctx context.Context, res json.RawMessage, sportID int64) (domain.ParseOddSectionsRes, error)
GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.OddMarket, error)
GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string) ([]domain.Odd, error) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string) ([]domain.OddMarket, error)
GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit domain.ValidInt64, offset domain.ValidInt64) ([]domain.Odd, error) GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit domain.ValidInt64, offset domain.ValidInt64) ([]domain.OddMarket, error)
GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) GetALLPrematchOdds(ctx context.Context) ([]domain.OddMarket, error)
GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.RawOddsByMarketID, error) // GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.OddMarket, error)
DeleteOddsForEvent(ctx context.Context, eventID string) 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/config"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository" "github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
"go.uber.org/zap" "go.uber.org/zap"
) )
type ServiceImpl struct { type ServiceImpl struct {
store *repository.Store store *repository.Store
config *config.Config config *config.Config
eventSvc event.Service
logger *slog.Logger logger *slog.Logger
mongoLogger *zap.Logger mongoLogger *zap.Logger
client *http.Client 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{ return &ServiceImpl{
store: store, store: store,
config: cfg, config: cfg,
eventSvc: eventSvc,
logger: logger, logger: logger,
mongoLogger: mongoLogger, mongoLogger: mongoLogger,
client: &http.Client{Timeout: 10 * time.Second}, 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 { func (s *ServiceImpl) fetchBet365Odds(ctx context.Context) error {
eventIDs, err := s.store.GetAllUpcomingEvents(ctx) eventIDs, err := s.eventSvc.GetAllUpcomingEvents(ctx)
if err != nil { if err != nil {
s.mongoLogger.Error( s.mongoLogger.Error(
"Failed to fetch upcoming event IDs", "Failed to fetch upcoming event IDs",
@ -161,115 +164,117 @@ func (s *ServiceImpl) fetchBet365Odds(ctx context.Context) error {
return nil return nil
} }
func (s *ServiceImpl) fetchBwinOdds(ctx context.Context) error { // 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 // // 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 // // so instead of having event and odds fetched separetly event will also be fetched along with the odds
sportIds := []int{4, 12, 7} // sportIds := []int{4, 12, 7}
for _, sportId := range sportIds { // for _, sportId := range sportIds {
url := fmt.Sprintf("https://api.b365api.com/v1/bwin/prematch?sport_id=%d&token=%s", sportId, s.config.Bet365Token) // 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) // req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil { // if err != nil {
s.mongoLogger.Error( // s.mongoLogger.Error(
"Failed to create request for sportId", // "Failed to create request for sportId",
zap.Int("sportID", sportId), // zap.Int("sportID", sportId),
zap.Error(err), // zap.Error(err),
) // )
continue // continue
} // }
resp, err := s.client.Do(req) // resp, err := s.client.Do(req)
if err != nil { // if err != nil {
s.mongoLogger.Error( // s.mongoLogger.Error(
"Failed to fetch request for sportId", // "Failed to fetch request for sportId",
zap.Int("sportID", sportId), // zap.Int("sportID", sportId),
zap.Error(err), // zap.Error(err),
) // )
continue // continue
} // }
defer resp.Body.Close() // defer resp.Body.Close()
body, err := io.ReadAll(resp.Body) // body, err := io.ReadAll(resp.Body)
if err != nil { // if err != nil {
s.mongoLogger.Error( // s.mongoLogger.Error(
"Failed to read response body for sportId", // "Failed to read response body for sportId",
zap.Int("sportID", sportId), // zap.Int("sportID", sportId),
zap.Error(err), // zap.Error(err),
) // )
continue // continue
} // }
var data struct { // var data struct {
Success int `json:"success"` // Success int `json:"success"`
Results []map[string]interface{} `json:"results"` // Results []map[string]interface{} `json:"results"`
} // }
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 { // if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
fmt.Printf("Decode failed for sport_id=%d\nRaw: %s\n", sportId, string(body)) // fmt.Printf("Decode failed for sport_id=%d\nRaw: %s\n", sportId, string(body))
s.mongoLogger.Error( // s.mongoLogger.Error(
"Failed to decode BWin response body", // "Failed to decode BWin response body",
zap.Int("sportID", sportId), // zap.Int("sportID", sportId),
zap.Error(err), // zap.Error(err),
) // )
continue // continue
} // }
for _, res := range data.Results { // for _, res := range data.Results {
if getInt(res["Id"]) == -1 { // if getInt(res["Id"]) == -1 {
continue // continue
} // }
event := domain.Event{ // event := domain.CreateEvent{
ID: strconv.Itoa(getInt(res["Id"])), // ID: strconv.Itoa(getInt(res["Id"])),
SportID: int32(getInt(res["SportId"])), // SportID: int32(getInt(res["SportId"])),
LeagueID: int32(getInt(res["LeagueId"])), // LeagueID: int64(getInt(res["LeagueId"])),
LeagueName: getString(res["Leaguename"]), // LeagueName: getString(res["Leaguename"]),
HomeTeam: getString(res["HomeTeam"]), // HomeTeam: getString(res["HomeTeam"]),
HomeTeamID: int32(getInt(res["HomeTeamId"])), // HomeTeamID: int64(getInt(res["HomeTeamId"])),
AwayTeam: getString(res["AwayTeam"]), // AwayTeam: getString(res["AwayTeam"]),
AwayTeamID: int32(getInt(res["AwayTeamId"])), // AwayTeamID: int64(getInt(res["AwayTeamId"])),
StartTime: time.Now().UTC().Format(time.RFC3339), // StartTime: time.Now().UTC(),
TimerStatus: "1", // IsLive: true,
IsLive: true, // Status: domain.STATUS_IN_PLAY,
Status: "live", // Source: domain.EVENT_SOURCE_BWIN,
Source: "bwin", // MatchName: "",
} // HomeTeamImage: "",
// AwayTeamImage: "",
// }
if err := s.store.SaveEvent(ctx, event); err != nil { // if err := s.store.SaveEvent(ctx, event); err != nil {
fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err) // fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err)
s.mongoLogger.Error( // s.mongoLogger.Error(
"Could not store live event", // "Could not store live event",
zap.Int("sportID", sportId), // zap.Int("sportID", sportId),
zap.String("eventID", event.ID), // zap.String("eventID", event.ID),
zap.Error(err), // zap.Error(err),
) // )
continue // continue
} // }
for _, market := range []string{"Markets, optionMarkets"} { // for _, market := range []string{"Markets, optionMarkets"} {
for _, m := range getMapArray(res[market]) { // for _, m := range getMapArray(res[market]) {
name := getMap(m["name"]) // name := getMap(m["name"])
marketName := getString(name["value"]) // marketName := getString(name["value"])
market := domain.Market{ // market := domain.CreateOddMarket{
EventID: event.ID, // EventID: event.ID,
MarketID: getString(m["id"]), // MarketID: getString(m["id"]),
MarketCategory: getString(m["category"]), // MarketCategory: getString(m["category"]),
MarketName: marketName, // MarketName: marketName,
Source: "bwin",
}
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) { 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 // Check if the market id is a string
marketIDint := market.ID.Int64 marketIDint := market.ID.Value
// if err != nil { // if err != nil {
// s.mongoLogger.Error( // s.mongoLogger.Error(
// "Invalid market id", // "Invalid market id",
@ -576,9 +581,8 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
continue continue
} }
marketRecord := domain.Market{ marketRecord := domain.CreateOddMarket{
EventID: eventID, EventID: eventID,
FI: fi,
MarketCategory: sectionName, MarketCategory: sectionName,
MarketType: marketType, MarketType: marketType,
MarketName: market.Name, MarketName: market.Name,
@ -586,10 +590,20 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
UpdatedAt: updatedAt, UpdatedAt: updatedAt,
Odds: marketOdds, Odds: marketOdds,
// bwin won't reach this code so bet365 is hardcoded for now // 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 { if err != nil {
s.mongoLogger.Error( s.mongoLogger.Error(
"failed to save market", "failed to save market",
@ -598,7 +612,7 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
zap.String("eventID", eventID), zap.String("eventID", eventID),
zap.Error(err), 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 continue
} }
} }
@ -609,29 +623,111 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
return nil return nil
} }
func (s *ServiceImpl) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) { func (s *ServiceImpl) CheckAndInsertOddHistory(ctx context.Context, market domain.CreateOddMarket) error {
return s.store.GetPrematchOdds(ctx, eventID) isEventMonitored, err := s.eventSvc.IsEventMonitored(ctx, market.EventID)
}
func (s *ServiceImpl) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) { marketLogger := s.mongoLogger.With(
return s.store.GetALLPrematchOdds(ctx) zap.String("market_id", market.MarketID),
} zap.String("market_name", market.MarketName),
zap.String("eventID", market.EventID),
func (s *ServiceImpl) GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.RawOddsByMarketID, error) { )
rows, err := s.store.GetRawOddsByMarketID(ctx, marketID, upcomingID)
if err != nil { 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 return rows, nil
} }
func (s *ServiceImpl) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string) ([]domain.Odd, error) { func (s *ServiceImpl) GetOddsByEventID(ctx context.Context, upcomingID string, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) {
return s.store.GetPrematchOddsByUpcomingID(ctx, upcomingID) return s.store.GetOddsByEventID(ctx, upcomingID, filter)
} }
func (s *ServiceImpl) GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset domain.ValidInt64) ([]domain.Odd, error) { func (s *ServiceImpl) GetOddsWithSettingsByEventID(ctx context.Context, upcomingID string, companyID int64, filter domain.OddMarketFilter) ([]domain.OddMarketWithSettings, error) {
return s.store.GetPaginatedPrematchOddsByUpcomingID(ctx, upcomingID, limit, offset) return s.store.GetOddsWithSettingsByEventID(ctx, upcomingID, companyID, filter)
} }
func (s *ServiceImpl) DeleteOddsForEvent(ctx context.Context, eventID string) error { func (s *ServiceImpl) DeleteOddsForEvent(ctx context.Context, eventID string) error {
@ -651,6 +747,12 @@ func getInt(v interface{}) int {
} }
return -1 return -1
} }
func getFloat(v interface{}) float64 {
if n, ok := v.(float64); ok {
return n
}
return 0
}
func getMap(v interface{}) map[string]interface{} { func getMap(v interface{}) map[string]interface{} {
if m, ok := v.(map[string]interface{}); ok { if m, ok := v.(map[string]interface{}); ok {

View File

@ -9,7 +9,7 @@ import (
type ReferralStore interface { type ReferralStore interface {
GenerateReferralCode() (string, error) GenerateReferralCode() (string, error)
CreateReferral(ctx context.Context, userID int64) 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 ProcessDepositBonus(ctx context.Context, userID string, amount float64) error
GetReferralStats(ctx context.Context, userID string) (*domain.ReferralStats, error) GetReferralStats(ctx context.Context, userID string) (*domain.ReferralStats, error)
CreateReferralSettings(ctx context.Context, req domain.ReferralSettingsReq) 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 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) s.logger.Info("Processing referral", "referredPhone", referredPhone, "referralCode", referralCode)
referral, err := s.repo.GetReferralByCode(ctx, referralCode) referral, err := s.repo.GetReferralByCode(ctx, referralCode)
@ -121,7 +121,10 @@ func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCo
return ErrInvalidReferral 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 err != nil {
if errors.Is(err, domain.ErrUserNotFound) { if errors.Is(err, domain.ErrUserNotFound) {
s.logger.Warn("User not found for referral", "referredPhone", referredPhone) s.logger.Warn("User not found for referral", "referredPhone", referredPhone)

View File

@ -2,9 +2,16 @@ package result
import ( import (
"context" "context"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
) )
type ResultService interface { type ResultService interface {
FetchAndProcessResults(ctx context.Context) error FetchAndProcessResults(ctx context.Context) error
FetchAndStoreResult(ctx context.Context, eventID string) 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