perf: 减少统计页面资料读取并优化区服选项查询
This commit is contained in:
@@ -69,6 +69,7 @@ type AnalyticsPage struct {
|
||||
}
|
||||
type AnalyticsRepo interface {
|
||||
Aggregate(context.Context, AnalyticsKind, AnalyticsScope, AnalyticsFilter) (*AnalyticsData, error)
|
||||
FillNames(context.Context, AnalyticsKind, AnalyticsScope, AnalyticsFilter, []*AnalyticsRow) error
|
||||
}
|
||||
type AnalyticsUsecase struct {
|
||||
repo AnalyticsRepo
|
||||
@@ -138,7 +139,8 @@ func (uc *AnalyticsUsecase) List(ctx context.Context, kind AnalyticsKind, filter
|
||||
filter.Begin = filter.StartDate.Format("2006-01-02")
|
||||
filter.End = filter.EndDate.Format("2006-01-02")
|
||||
out := &AnalyticsPage{Rows: []*AnalyticsRow{}, Begin: filter.Begin, End: filter.End, Available: true}
|
||||
data, err := uc.repo.Aggregate(ctx, kind, AnalyticsScope{Viewer: viewer, IncludeSub: pref.IncludeSubPromote, IDCardDedup: pref.IDCardDedup}, filter)
|
||||
scope := AnalyticsScope{Viewer: viewer, IncludeSub: pref.IncludeSubPromote, IDCardDedup: pref.IDCardDedup}
|
||||
data, err := uc.repo.Aggregate(ctx, kind, scope, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -165,9 +167,6 @@ func (uc *AnalyticsUsecase) List(ctx context.Context, kind AnalyticsKind, filter
|
||||
pay.Add(pay, rounded)
|
||||
}
|
||||
counts = analyticsAdd(counts, row.Counts)
|
||||
if kind == ChannelAnalytics {
|
||||
row.Name = (&LedgerNames{PromoteID: &row.ID, PromoteAccount: row.Name}).DisplayPromote()
|
||||
}
|
||||
}
|
||||
if kind == ChannelAnalytics {
|
||||
counts = analyticsCap(counts)
|
||||
@@ -187,6 +186,28 @@ func (uc *AnalyticsUsecase) List(ctx context.Context, kind AnalyticsKind, filter
|
||||
if err := analyticsValues(out.Summary); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 仅按渠道名称或类型排序时需要提前读取全部资料;数字指标排序
|
||||
// 确定当前页后再补名称和商务信息,汇总仍使用全部可见统计行。
|
||||
namesBeforeSort := kind == ChannelAnalytics && (filter.SortField == "promoteName" || filter.SortField == "promoteType")
|
||||
fillNames := func(rows []*AnalyticsRow) error {
|
||||
if len(rows) == 0 {
|
||||
return nil
|
||||
}
|
||||
if err := uc.repo.FillNames(ctx, kind, scope, filter, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
if kind == ChannelAnalytics {
|
||||
for _, row := range rows {
|
||||
row.Name = (&LedgerNames{PromoteID: &row.ID, PromoteAccount: row.Name}).DisplayPromote()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if namesBeforeSort {
|
||||
if err := fillNames(data.Rows); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := sortAnalytics(data.Rows, kind, filter.SortField, filter.Ascending); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -205,6 +226,11 @@ func (uc *AnalyticsUsecase) List(ctx context.Context, kind AnalyticsKind, filter
|
||||
if from < len(data.Rows) {
|
||||
out.Rows = data.Rows[from:to]
|
||||
}
|
||||
if !namesBeforeSort {
|
||||
if err := fillNames(out.Rows); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
func sortAnalytics(rows []*AnalyticsRow, kind AnalyticsKind, field string, ascending bool) error {
|
||||
|
||||
@@ -7,9 +7,23 @@ import (
|
||||
)
|
||||
|
||||
type analyticsRepoFake struct {
|
||||
data *AnalyticsData
|
||||
scope AnalyticsScope
|
||||
filter AnalyticsFilter
|
||||
data *AnalyticsData
|
||||
scope AnalyticsScope
|
||||
filter AnalyticsFilter
|
||||
fillCalls [][]AnalyticsKey
|
||||
fill func([]*AnalyticsRow) error
|
||||
}
|
||||
|
||||
func (r *analyticsRepoFake) FillNames(_ context.Context, _ AnalyticsKind, _ AnalyticsScope, _ AnalyticsFilter, rows []*AnalyticsRow) error {
|
||||
keys := make([]AnalyticsKey, len(rows))
|
||||
for i, row := range rows {
|
||||
keys[i] = row.AnalyticsKey
|
||||
}
|
||||
r.fillCalls = append(r.fillCalls, keys)
|
||||
if r.fill != nil {
|
||||
return r.fill(rows)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *analyticsRepoFake) Aggregate(_ context.Context, _ AnalyticsKind, s AnalyticsScope, f AnalyticsFilter) (*AnalyticsData, error) {
|
||||
@@ -76,3 +90,75 @@ func TestAnalyticsSortAndMissingData(t *testing.T) {
|
||||
t.Fatal("倒置日期应被拒绝")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnalyticsLoadsMetadataOnlyForSelectedPage(t *testing.T) {
|
||||
for _, kind := range []AnalyticsKind{ChannelAnalytics, GameAnalytics} {
|
||||
t.Run(string(kind), func(t *testing.T) {
|
||||
uc, repo := analyticsFixture()
|
||||
for _, row := range repo.data.Rows {
|
||||
row.Name = ""
|
||||
}
|
||||
repo.fill = func(rows []*AnalyticsRow) error {
|
||||
for _, row := range rows {
|
||||
row.Name = "本页资料"
|
||||
row.BindingAccount = "本页商务"
|
||||
}
|
||||
return nil
|
||||
}
|
||||
page, err := uc.List(accountContext(7, 901), kind, AnalyticsFilter{SortField: "totalPay"}, 1, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(repo.fillCalls) != 1 || len(repo.fillCalls[0]) != 1 || repo.fillCalls[0][0].ID != 2 {
|
||||
t.Fatalf("应只读取排序后当前页的资料: %+v", repo.fillCalls)
|
||||
}
|
||||
if page.Total != 2 || page.Summary.Pay != "50.00" || page.Rows[0].Name != "本页资料" || page.Rows[0].BindingAccount != "本页商务" {
|
||||
t.Fatalf("延迟读取影响汇总或展示资料: %+v", page)
|
||||
}
|
||||
repo.fillCalls = nil
|
||||
page, err = uc.List(accountContext(7, 901), kind, AnalyticsFilter{}, 3, 1)
|
||||
if err != nil || len(page.Rows) != 0 || len(repo.fillCalls) != 0 || page.Summary.Pay != "50.00" {
|
||||
t.Fatal("空页不应读取资料,汇总仍须保留")
|
||||
}
|
||||
repo.fill = func([]*AnalyticsRow) error { return ErrStorage }
|
||||
if _, err := uc.List(accountContext(7, 901), kind, AnalyticsFilter{}, 1, 1); err != ErrStorage {
|
||||
t.Fatalf("资料读取错误必须向上传递: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnalyticsLoadsMetadataBeforeNameOrTypeSort(t *testing.T) {
|
||||
for _, field := range []string{"promoteName", "promoteType"} {
|
||||
t.Run(field, func(t *testing.T) {
|
||||
uc, repo := analyticsFixture()
|
||||
for _, row := range repo.data.Rows {
|
||||
row.Name = ""
|
||||
}
|
||||
repo.fill = func(rows []*AnalyticsRow) error {
|
||||
for _, row := range rows {
|
||||
name, kind := "Zulu", 9
|
||||
if row.ID == 2 {
|
||||
name, kind = "Alpha", 1
|
||||
}
|
||||
row.Name, row.PromoteType = name, &kind
|
||||
}
|
||||
return nil
|
||||
}
|
||||
page, err := uc.List(accountContext(7, 901), ChannelAnalytics, AnalyticsFilter{SortField: field, Ascending: true}, 1, 1)
|
||||
if err != nil || len(page.Rows) != 1 || page.Rows[0].ID != 2 || len(repo.fillCalls) != 1 || len(repo.fillCalls[0]) != 2 {
|
||||
t.Fatalf("按资料字段排序前必须读取全体资料: page=%+v calls=%+v err=%v", page, repo.fillCalls, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnalyticsDeferredNamesPreserveOfficialAndUnknownLabels(t *testing.T) {
|
||||
uc, repo := analyticsFixture()
|
||||
repo.data.Rows[0].ID, repo.data.Rows[0].Name = 0, ""
|
||||
repo.data.Rows[1].Name = ""
|
||||
page, err := uc.List(accountContext(1, 888), ChannelAnalytics, AnalyticsFilter{SortField: "promoteId", Ascending: true}, 1, 10)
|
||||
if err != nil || page.Rows[0].Name != "官方渠道" || page.Rows[1].Name != "未知渠道(ID:2)" {
|
||||
t.Fatalf("默认渠道名丢失: %+v %v", page, err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user