184 lines
4.4 KiB
Go
184 lines
4.4 KiB
Go
package storage
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/shopspring/decimal"
|
|
"go.mongodb.org/mongo-driver/v2/bson"
|
|
|
|
"dashboard-cdc-worker/internal/dashboard"
|
|
)
|
|
|
|
func mergeMongoGiftRows(rows map[string]*giftMetricRow, metrics []mongoGiftAmount, anchorShare bool) {
|
|
for _, item := range metrics {
|
|
key := giftMetricKey(item.day, "", item.userID)
|
|
row := rows[key]
|
|
if row == nil {
|
|
row = &giftMetricRow{day: item.day, luckyGiftUsers: make(map[int64]struct{})}
|
|
rows[key] = row
|
|
}
|
|
if anchorShare {
|
|
row.luckyGiftAnchorShare = row.luckyGiftAnchorShare.Add(item.amount)
|
|
} else {
|
|
row.giftConsume = row.giftConsume.Add(item.amount)
|
|
}
|
|
}
|
|
}
|
|
|
|
func mergeSQLLuckyGiftRows(rows map[string]*giftMetricRow, metrics []sqlLuckyGiftRow) {
|
|
for _, item := range metrics {
|
|
key := giftMetricKey(item.day, item.country.Code, 0)
|
|
row := rows[key]
|
|
if row == nil {
|
|
row = &giftMetricRow{
|
|
day: item.day,
|
|
sysOrigin: item.sysOrigin,
|
|
country: item.country,
|
|
luckyGiftUsers: make(map[int64]struct{}),
|
|
}
|
|
rows[key] = row
|
|
}
|
|
row.sysOrigin = item.sysOrigin
|
|
row.country = item.country
|
|
row.luckyGiftTotalFlow = row.luckyGiftTotalFlow.Add(item.payAmount)
|
|
row.luckyGiftPayout = row.luckyGiftPayout.Add(item.payout)
|
|
row.luckyGiftUsers[item.userID] = struct{}{}
|
|
}
|
|
}
|
|
|
|
func applyGiftUserCountries(rows map[string]*giftMetricRow, users map[int64]dashboard.UserCountry, unknownCountry string) {
|
|
for key, row := range rows {
|
|
if row.country.Code != "" {
|
|
continue
|
|
}
|
|
parts := strings.Split(key, "|")
|
|
if len(parts) != 3 {
|
|
continue
|
|
}
|
|
userID := parseInt64(parts[2])
|
|
user, ok := users[userID]
|
|
if !ok {
|
|
delete(rows, key)
|
|
continue
|
|
}
|
|
row.sysOrigin = user.SysOrigin
|
|
row.country = user.Country
|
|
countryKey := giftMetricKey(row.day, row.country.Code, 0)
|
|
countryRow := rows[countryKey]
|
|
if countryRow == nil {
|
|
countryRow = &giftMetricRow{
|
|
day: row.day,
|
|
sysOrigin: row.sysOrigin,
|
|
country: row.country,
|
|
luckyGiftUsers: make(map[int64]struct{}),
|
|
}
|
|
rows[countryKey] = countryRow
|
|
}
|
|
countryRow.giftConsume = countryRow.giftConsume.Add(row.giftConsume)
|
|
countryRow.luckyGiftAnchorShare = countryRow.luckyGiftAnchorShare.Add(row.luckyGiftAnchorShare)
|
|
delete(rows, key)
|
|
}
|
|
}
|
|
|
|
func (row *giftMetricRow) empty() bool {
|
|
return row.giftConsume.IsZero() &&
|
|
row.luckyGiftAnchorShare.IsZero() &&
|
|
row.luckyGiftTotalFlow.IsZero() &&
|
|
row.luckyGiftPayout.IsZero() &&
|
|
len(row.luckyGiftUsers) == 0
|
|
}
|
|
|
|
func giftMetricKey(day, countryCode string, userID int64) string {
|
|
return fmt.Sprintf("%s|%s|%d", day, countryCode, userID)
|
|
}
|
|
|
|
func int64SetToSlice(values map[int64]struct{}) []int64 {
|
|
out := make([]int64, 0, len(values))
|
|
for value := range values {
|
|
out = append(out, value)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func bsonInt64(value interface{}) int64 {
|
|
switch typed := value.(type) {
|
|
case int64:
|
|
return typed
|
|
case int32:
|
|
return int64(typed)
|
|
case int:
|
|
return int64(typed)
|
|
case float64:
|
|
return int64(typed)
|
|
case string:
|
|
return parseInt64(typed)
|
|
default:
|
|
return parseInt64(fmt.Sprint(typed))
|
|
}
|
|
}
|
|
|
|
func bsonDecimal(value interface{}) decimal.Decimal {
|
|
switch typed := value.(type) {
|
|
case decimal.Decimal:
|
|
return typed
|
|
case bson.Decimal128:
|
|
parsed, err := decimal.NewFromString(typed.String())
|
|
if err == nil {
|
|
return parsed
|
|
}
|
|
case int64:
|
|
return decimal.NewFromInt(typed)
|
|
case int32:
|
|
return decimal.NewFromInt(int64(typed))
|
|
case int:
|
|
return decimal.NewFromInt(int64(typed))
|
|
case float64:
|
|
return decimal.NewFromFloat(typed)
|
|
case string:
|
|
parsed, err := decimal.NewFromString(typed)
|
|
if err == nil {
|
|
return parsed
|
|
}
|
|
}
|
|
parsed, err := decimal.NewFromString(fmt.Sprint(value))
|
|
if err != nil {
|
|
return decimal.Zero
|
|
}
|
|
return parsed
|
|
}
|
|
|
|
func parseInt64(value string) int64 {
|
|
parsed, _ := strconv.ParseInt(strings.TrimSpace(value), 10, 64)
|
|
return parsed
|
|
}
|
|
|
|
func defaultSysOrigin(values []string) string {
|
|
if len(values) == 0 {
|
|
return ""
|
|
}
|
|
return strings.TrimSpace(values[0])
|
|
}
|
|
|
|
func timezoneOffset(timezone string) string {
|
|
location, err := time.LoadLocation(timezone)
|
|
if err != nil {
|
|
return "+00:00"
|
|
}
|
|
_, offset := time.Now().In(location).Zone()
|
|
sign := "+"
|
|
if offset < 0 {
|
|
sign = "-"
|
|
offset = -offset
|
|
}
|
|
hours := offset / 3600
|
|
minutes := (offset % 3600) / 60
|
|
return fmt.Sprintf("%s%02d:%02d", sign, hours, minutes)
|
|
}
|
|
|
|
func quoteIdent(value string) string {
|
|
return "`" + strings.ReplaceAll(value, "`", "``") + "`"
|
|
}
|