194 lines
7.4 KiB
Go
194 lines
7.4 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"time"
|
|
|
|
"dashboard-cdc-worker/internal/dashboard"
|
|
)
|
|
|
|
func (r *MySQLRepository) applyDailyUserMetric(ctx context.Context, tx *sql.Tx, c dashboard.Contribution, day time.Time, metricType string) error {
|
|
if c.DeltaSign < 0 {
|
|
return r.deleteDailyUserMetric(ctx, tx, c, day, metricType)
|
|
}
|
|
inserted, err := insertDailyUserMetric(ctx, tx, c, day, metricType)
|
|
if err != nil || !inserted {
|
|
return err
|
|
}
|
|
column := dailyMetricColumn(metricType)
|
|
if column == "" {
|
|
return nil
|
|
}
|
|
_, err = tx.ExecContext(ctx, `
|
|
INSERT INTO country_dashboard_daily_metric (
|
|
stat_date, date_number, sys_origin, country_code, country_name, refreshed_at
|
|
, `+column+`
|
|
) VALUES (?, ?, ?, ?, ?, NOW(), 1)
|
|
ON DUPLICATE KEY UPDATE `+column+` = `+column+` + VALUES(`+column+`),
|
|
country_name = VALUES(country_name), refreshed_at = NOW()
|
|
`, day, dashboard.DateNumber(day), c.SysOrigin, c.Country.Code, c.Country.Name)
|
|
return err
|
|
}
|
|
|
|
func (r *MySQLRepository) applyPeriodUserMetric(ctx context.Context, tx *sql.Tx, c dashboard.Contribution, window dashboard.PeriodWindow, statTimezone string, metricType string) error {
|
|
if c.DeltaSign < 0 {
|
|
return r.deletePeriodUserMetric(ctx, tx, c, window, statTimezone, metricType)
|
|
}
|
|
inserted, err := insertPeriodUserMetric(ctx, tx, c, window, statTimezone, metricType)
|
|
if err != nil || !inserted {
|
|
return err
|
|
}
|
|
column := periodMetricColumn(metricType)
|
|
if column == "" {
|
|
return nil
|
|
}
|
|
_, err = tx.ExecContext(ctx, `
|
|
INSERT INTO country_dashboard_period_metric (
|
|
period_type, period_key, stat_timezone, period_name, period_start_date, period_end_date,
|
|
sys_origin, country_code, country_name, refreshed_at
|
|
, `+column+`
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), 1)
|
|
ON DUPLICATE KEY UPDATE `+column+` = `+column+` + VALUES(`+column+`),
|
|
country_name = VALUES(country_name), refreshed_at = NOW()
|
|
`, window.Type, window.Key, statTimezone, window.Name, window.StartDate, window.EndDate,
|
|
c.SysOrigin, c.Country.Code, c.Country.Name)
|
|
return err
|
|
}
|
|
|
|
func (r *MySQLRepository) deleteDailyUserMetric(ctx context.Context, tx *sql.Tx, c dashboard.Contribution, day time.Time, metricType string) error {
|
|
deleted, err := deleteDailyUserMetricRow(ctx, tx, c, day, metricType)
|
|
if err != nil || !deleted {
|
|
return err
|
|
}
|
|
column := dailyMetricColumn(metricType)
|
|
if column == "" {
|
|
return nil
|
|
}
|
|
_, err = tx.ExecContext(ctx, `
|
|
UPDATE country_dashboard_daily_metric
|
|
SET `+column+` = GREATEST(`+column+` - 1, 0), refreshed_at = NOW()
|
|
WHERE stat_date = ? AND sys_origin = ? AND country_code = ?
|
|
`, day, c.SysOrigin, c.Country.Code)
|
|
return err
|
|
}
|
|
|
|
func (r *MySQLRepository) deletePeriodUserMetric(ctx context.Context, tx *sql.Tx, c dashboard.Contribution, window dashboard.PeriodWindow, statTimezone string, metricType string) error {
|
|
deleted, err := deletePeriodUserMetric(ctx, tx, c, window, statTimezone, metricType)
|
|
if err != nil || !deleted {
|
|
return err
|
|
}
|
|
column := periodMetricColumn(metricType)
|
|
if column == "" {
|
|
return nil
|
|
}
|
|
_, err = tx.ExecContext(ctx, `
|
|
UPDATE country_dashboard_period_metric
|
|
SET `+column+` = GREATEST(`+column+` - 1, 0), refreshed_at = NOW()
|
|
WHERE period_type = ? AND period_key = ? AND stat_timezone = ? AND sys_origin = ? AND country_code = ?
|
|
`, window.Type, window.Key, statTimezone, c.SysOrigin, c.Country.Code)
|
|
return err
|
|
}
|
|
|
|
func insertDailyUserMetric(ctx context.Context, tx *sql.Tx, c dashboard.Contribution, day time.Time, metricType string) (bool, error) {
|
|
result, err := tx.ExecContext(ctx, `
|
|
INSERT IGNORE INTO country_dashboard_daily_user_metric (
|
|
stat_date, sys_origin, country_code, country_name, user_id, metric_type
|
|
) VALUES (?, ?, ?, ?, ?, ?)
|
|
`, day, c.SysOrigin, c.Country.Code, c.Country.Name, c.UserID, metricType)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
affected, err := result.RowsAffected()
|
|
return affected > 0, err
|
|
}
|
|
|
|
func deleteDailyUserMetricRow(ctx context.Context, tx *sql.Tx, c dashboard.Contribution, day time.Time, metricType string) (bool, error) {
|
|
result, err := tx.ExecContext(ctx, `
|
|
DELETE FROM country_dashboard_daily_user_metric
|
|
WHERE stat_date = ? AND sys_origin = ? AND country_code = ? AND user_id = ? AND metric_type = ?
|
|
`, day, c.SysOrigin, c.Country.Code, c.UserID, metricType)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
affected, err := result.RowsAffected()
|
|
return affected > 0, err
|
|
}
|
|
|
|
func (r *MySQLRepository) applyGamePeriodUserMetric(ctx context.Context, tx *sql.Tx, c dashboard.Contribution, window dashboard.PeriodWindow, statTimezone string) error {
|
|
result, err := tx.ExecContext(ctx, `
|
|
INSERT IGNORE INTO country_dashboard_game_period_user_metric (
|
|
period_type, period_key, stat_timezone, period_name, period_start_date, period_end_date,
|
|
sys_origin, country_code, country_name, game_provider, game_id, user_id
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`, window.Type, window.Key, statTimezone, window.Name, window.StartDate, window.EndDate,
|
|
c.SysOrigin, c.Country.Code, c.Country.Name, c.GameProvider, c.GameID, c.UserID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
affected, err := result.RowsAffected()
|
|
if err != nil || affected == 0 {
|
|
return err
|
|
}
|
|
_, err = tx.ExecContext(ctx, `
|
|
INSERT INTO country_dashboard_game_period_metric (
|
|
period_type, period_key, stat_timezone, period_name, period_start_date, period_end_date,
|
|
sys_origin, country_code, country_name, game_provider, game_id, game_name, user_count, refreshed_at
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, NOW())
|
|
ON DUPLICATE KEY UPDATE user_count = user_count + VALUES(user_count), country_name = VALUES(country_name),
|
|
game_name = VALUES(game_name), refreshed_at = NOW()
|
|
`, window.Type, window.Key, statTimezone, window.Name, window.StartDate, window.EndDate,
|
|
c.SysOrigin, c.Country.Code, c.Country.Name, c.GameProvider, c.GameID, c.GameName)
|
|
return err
|
|
}
|
|
|
|
func insertPeriodUserMetric(ctx context.Context, tx *sql.Tx, c dashboard.Contribution, window dashboard.PeriodWindow, statTimezone string, metricType string) (bool, error) {
|
|
result, err := tx.ExecContext(ctx, `
|
|
INSERT IGNORE INTO country_dashboard_period_user_metric (
|
|
period_type, period_key, stat_timezone, period_name, period_start_date, period_end_date,
|
|
sys_origin, country_code, country_name, user_id, metric_type
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`, window.Type, window.Key, statTimezone, window.Name, window.StartDate, window.EndDate,
|
|
c.SysOrigin, c.Country.Code, c.Country.Name, c.UserID, metricType)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
affected, err := result.RowsAffected()
|
|
return affected > 0, err
|
|
}
|
|
|
|
func deletePeriodUserMetric(ctx context.Context, tx *sql.Tx, c dashboard.Contribution, window dashboard.PeriodWindow, statTimezone string, metricType string) (bool, error) {
|
|
result, err := tx.ExecContext(ctx, `
|
|
DELETE FROM country_dashboard_period_user_metric
|
|
WHERE period_type = ? AND period_key = ? AND stat_timezone = ?
|
|
AND sys_origin = ? AND country_code = ? AND user_id = ? AND metric_type = ?
|
|
`, window.Type, window.Key, statTimezone, c.SysOrigin, c.Country.Code, c.UserID, metricType)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
affected, err := result.RowsAffected()
|
|
return affected > 0, err
|
|
}
|
|
|
|
func dailyMetricColumn(metricType string) string {
|
|
switch metricType {
|
|
case dashboard.MetricCountryNewUser:
|
|
return "country_new_user"
|
|
case dashboard.MetricLuckyGiftUser:
|
|
return "lucky_gift_user"
|
|
case dashboard.MetricGameUser:
|
|
return "game_user"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func periodMetricColumn(metricType string) string {
|
|
return dailyMetricColumn(metricType)
|
|
}
|
|
|
|
func dashboardPtr(value time.Time) *time.Time {
|
|
v := value
|
|
return &v
|
|
}
|