194 lines
6.8 KiB
Go
194 lines
6.8 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"time"
|
|
|
|
"github.com/shopspring/decimal"
|
|
|
|
"dashboard-cdc-worker/internal/dashboard"
|
|
)
|
|
|
|
func (r *MySQLRepository) listSQLLuckyGiftRows(ctx context.Context, start, end time.Time,
|
|
statTimezone string) ([]sqlLuckyGiftRow, error) {
|
|
query := `
|
|
SELECT CAST(t.id AS CHAR), t.user_id, DATE_FORMAT(CONVERT_TZ(t.create_time, '+03:00', ?), '%Y-%m-%d'),
|
|
t.sys_origin, IFNULL(NULLIF(u.country_code, ''), ?),
|
|
IFNULL(NULLIF(u.country_name, ''), IFNULL(NULLIF(u.country_code, ''), ?)),
|
|
t.pay_amount, t.award_amount
|
|
FROM ` + quoteIdent(r.cfg.MySQL.Schema) + `.game_lucky_gift_count t
|
|
JOIN ` + quoteIdent(r.cfg.MySQL.Schema) + `.user_base_info u ON u.id = t.user_id
|
|
WHERE t.create_time >= ?
|
|
AND t.create_time < ?
|
|
AND t.sys_origin IN ` + inStringPlaceholders(len(r.cfg.Dashboard.SysOrigins)) + `
|
|
AND u.origin_sys = t.sys_origin
|
|
AND (u.is_del = 0 OR u.is_del IS NULL)`
|
|
args := []interface{}{timezoneOffset(statTimezone), r.cfg.Dashboard.UnknownCountryCode,
|
|
r.cfg.Dashboard.UnknownCountryCode, start, end}
|
|
args = append(args, stringArgs(r.cfg.Dashboard.SysOrigins)...)
|
|
rows, err := r.db.QueryContext(ctx, query, args...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var result []sqlLuckyGiftRow
|
|
for rows.Next() {
|
|
var item sqlLuckyGiftRow
|
|
var pay, payout decimal.Decimal
|
|
if err := rows.Scan(&item.id, &item.userID, &item.day, &item.sysOrigin, &item.country.Code,
|
|
&item.country.Name, &pay, &payout); err != nil {
|
|
return nil, err
|
|
}
|
|
item.payAmount = pay
|
|
item.payout = payout
|
|
result = append(result, item)
|
|
}
|
|
return result, rows.Err()
|
|
}
|
|
|
|
func (r *MySQLRepository) replaceGiftMetricRows(ctx context.Context, tx *sql.Tx,
|
|
statTimezone string, start, end time.Time, rows map[string]*giftMetricRow) error {
|
|
location, err := time.LoadLocation(statTimezone)
|
|
if err != nil {
|
|
location = time.UTC
|
|
}
|
|
for day := start.In(location); day.Before(end); day = day.AddDate(0, 0, 1) {
|
|
dayStart := time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, location)
|
|
dayEnd := dayStart.AddDate(0, 0, 1)
|
|
dayKey := dayStart.Format("2006-01-02")
|
|
for _, sysOrigin := range r.cfg.Dashboard.SysOrigins {
|
|
if _, err := tx.ExecContext(ctx, `
|
|
UPDATE country_dashboard_period_metric
|
|
SET gift_consume = 0,
|
|
lucky_gift_total_flow = 0,
|
|
lucky_gift_user = 0,
|
|
lucky_gift_payout = 0,
|
|
lucky_gift_anchor_share = 0,
|
|
refreshed_at = NOW()
|
|
WHERE period_type = 'DAY' AND period_key = ? AND stat_timezone = ? AND sys_origin = ?`,
|
|
dayKey, statTimezone, sysOrigin); err != nil {
|
|
return err
|
|
}
|
|
if _, err := tx.ExecContext(ctx, `
|
|
DELETE FROM country_dashboard_period_user_metric
|
|
WHERE period_type = 'DAY' AND period_key = ? AND stat_timezone = ? AND sys_origin = ?
|
|
AND metric_type = ?`, dayKey, statTimezone, sysOrigin, dashboard.MetricLuckyGiftUser); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := r.upsertGiftMetricRows(ctx, tx, statTimezone, dayStart, dayEnd, rows); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *MySQLRepository) upsertGiftMetricRows(ctx context.Context, tx *sql.Tx,
|
|
statTimezone string, dayStart, dayEnd time.Time, rows map[string]*giftMetricRow) error {
|
|
dayKey := dayStart.Format("2006-01-02")
|
|
var metricRows []*giftMetricRow
|
|
for _, row := range rows {
|
|
if row.day != dayKey || row.empty() {
|
|
continue
|
|
}
|
|
if row.sysOrigin == "" {
|
|
row.sysOrigin = defaultSysOrigin(r.cfg.Dashboard.SysOrigins)
|
|
}
|
|
if !r.allowedOrigin(row.sysOrigin) {
|
|
continue
|
|
}
|
|
if row.country.Code == "" {
|
|
row.country.Code = r.cfg.Dashboard.UnknownCountryCode
|
|
}
|
|
if row.country.Name == "" {
|
|
row.country.Name = row.country.Code
|
|
}
|
|
metricRows = append(metricRows, row)
|
|
}
|
|
if len(metricRows) == 0 {
|
|
return nil
|
|
}
|
|
args := make([]interface{}, 0, len(metricRows)*14)
|
|
for _, row := range metricRows {
|
|
args = append(args, dashboard.PeriodDay, dayKey, statTimezone, dayKey, dayStart, dayEnd,
|
|
row.sysOrigin, row.country.Code, row.country.Name, row.giftConsume,
|
|
row.luckyGiftTotalFlow, len(row.luckyGiftUsers), row.luckyGiftPayout,
|
|
row.luckyGiftAnchorShare)
|
|
}
|
|
if _, 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, gift_consume, lucky_gift_total_flow,
|
|
lucky_gift_user, lucky_gift_payout, lucky_gift_anchor_share
|
|
) VALUES `+placeholders(len(metricRows), 14)+`
|
|
ON DUPLICATE KEY UPDATE
|
|
period_name = VALUES(period_name),
|
|
period_start_date = VALUES(period_start_date),
|
|
period_end_date = VALUES(period_end_date),
|
|
country_name = VALUES(country_name),
|
|
gift_consume = VALUES(gift_consume),
|
|
lucky_gift_total_flow = VALUES(lucky_gift_total_flow),
|
|
lucky_gift_user = VALUES(lucky_gift_user),
|
|
lucky_gift_payout = VALUES(lucky_gift_payout),
|
|
lucky_gift_anchor_share = VALUES(lucky_gift_anchor_share),
|
|
refreshed_at = NOW()`, args...); err != nil {
|
|
return err
|
|
}
|
|
for _, row := range metricRows {
|
|
if len(row.luckyGiftUsers) == 0 {
|
|
continue
|
|
}
|
|
key := periodUserKey{
|
|
periodType: dashboard.PeriodDay, periodKey: dayKey, statTimezone: statTimezone,
|
|
periodName: dayKey, startDate: dayStart, endDate: dayEnd, sysOrigin: row.sysOrigin,
|
|
countryCode: row.country.Code, countryName: row.country.Name, metricType: dashboard.MetricLuckyGiftUser,
|
|
}
|
|
if _, err := bulkInsertPeriodUsers(ctx, tx, key, int64SetToSlice(row.luckyGiftUsers)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *MySQLRepository) loadSourceUserCountriesByID(ctx context.Context, ids []int64) (map[int64]dashboard.UserCountry, error) {
|
|
result := make(map[int64]dashboard.UserCountry)
|
|
for start := 0; start < len(ids); start += bulkInsertChunkSize {
|
|
end := min(start+bulkInsertChunkSize, len(ids))
|
|
args := make([]interface{}, 0, end-start+2)
|
|
args = append(args, r.cfg.Dashboard.UnknownCountryCode, r.cfg.Dashboard.UnknownCountryCode)
|
|
for _, id := range ids[start:end] {
|
|
args = append(args, id)
|
|
}
|
|
rows, err := r.db.QueryContext(ctx, `
|
|
SELECT id, origin_sys, IFNULL(NULLIF(country_code, ''), ?),
|
|
IFNULL(NULLIF(country_name, ''), IFNULL(NULLIF(country_code, ''), ?)),
|
|
IFNULL(is_del, 0), create_time, update_time
|
|
FROM `+quoteIdent(r.cfg.MySQL.Schema)+`.user_base_info
|
|
WHERE id IN `+inPlaceholders(end-start), args...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for rows.Next() {
|
|
var user dashboard.UserCountry
|
|
var createdAt, updatedAt sql.NullTime
|
|
if err := rows.Scan(&user.UserID, &user.SysOrigin, &user.Country.Code, &user.Country.Name,
|
|
&user.IsDeleted, &createdAt, &updatedAt); err != nil {
|
|
_ = rows.Close()
|
|
return nil, err
|
|
}
|
|
if createdAt.Valid {
|
|
user.CreatedAt = createdAt.Time
|
|
}
|
|
if updatedAt.Valid {
|
|
user.UpdatedAt = updatedAt.Time
|
|
}
|
|
result[user.UserID] = user
|
|
}
|
|
if err := rows.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|