From 7df74bc8e8d2d8a01cf4bd9c291c4a5ccbee93fd Mon Sep 17 00:00:00 2001 From: Yvan <8574526@qq,com> Date: Fri, 6 Nov 2026 07:22:51 +0800 Subject: [PATCH] perf: keep default ledger queries on platform time indexes --- internal/data/business/ledger.go | 30 +++++++++++++++++++ internal/data/business/ledger_test.go | 42 +++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/internal/data/business/ledger.go b/internal/data/business/ledger.go index f16feae..d3789ec 100644 --- a/internal/data/business/ledger.go +++ b/internal/data/business/ledger.go @@ -12,6 +12,30 @@ import ( type ledgerRepo struct{ data Provider } func NewLedgerRepo(data Provider) business.LedgerRepo { return &ledgerRepo{data: data} } + +// Enumerating the stored platform codes lets MySQL use the leading column of +// the time indexes even when the caller requests every platform. Read them +// from the table so historical or newly imported codes remain in scope. +func resolveLedgerSources(db *gorm.DB, table string, filter *business.LedgerFilter) error { + if len(filter.Sources) > 0 { + return nil + } + var sources []struct{ SourceDB *string } + if err := db.Table(table).Select("source_db").Distinct().Scan(&sources).Error; err != nil { + return business.ErrStorage + } + for _, source := range sources { + if source.SourceDB == nil { + // Legacy production columns are NOT NULL. Preserve unfiltered + // semantics if another supported storage layout contains NULL. + return nil + } + } + for _, source := range sources { + filter.Sources = append(filter.Sources, *source.SourceDB) + } + return nil +} func ledgerBasePromotes(db *gorm.DB, scope business.LedgerScope, filter business.LedgerFilter, alias string) *gorm.DB { q := db.Table("tab_promote " + alias) if len(filter.Sources) > 0 { @@ -149,6 +173,9 @@ func (r *ledgerRepo) Registrations(ctx context.Context, scope business.LedgerSco if err != nil { return nil, err } + if err := resolveLedgerSources(db, "tab_user", &filter); err != nil { + return nil, err + } q := registrationQuery(db, scope, filter, timeExpression) if err := q.Count(&page.Total).Error; err != nil { return nil, business.ErrStorage @@ -274,6 +301,9 @@ func (r *ledgerRepo) Spends(ctx context.Context, scope business.LedgerScope, fil page.TotalPayAmount = nil return page, nil } + if err := resolveLedgerSources(db, "tab_spend", &filter); err != nil { + return nil, err + } q := spendQuery(db, scope, filter, false) if err := q.Count(&page.Total).Error; err != nil { return nil, business.ErrStorage diff --git a/internal/data/business/ledger_test.go b/internal/data/business/ledger_test.go index c9315c7..6660f23 100644 --- a/internal/data/business/ledger_test.go +++ b/internal/data/business/ledger_test.go @@ -3,12 +3,54 @@ package business import ( "context" "fmt" + "reflect" "testing" "gorm.io/gorm" "kra/internal/biz/business" ) +func TestUnfilteredLedgerKeepsEveryStoredPlatform(t *testing.T) { + db, repo, _, filter := prepareLedgerData(t) + for _, query := range []string{ + "INSERT INTO tab_user(id,source_db,register_time,promote_id,puid) VALUES(90,'historical','1500',0,0)", + "INSERT INTO tab_spend(id,source_db,user_id,pay_amount,pay_time,pay_status,promote_id) VALUES(990,'historical',90,12.34,1500,1,0)", + } { + if err := db.Exec(query).Error; err != nil { + t.Fatal(err) + } + } + scope := business.LedgerScope{Viewer: business.UserScope{All: true}, Unrestricted: true, IncludeSub: true} + filter.Sources = nil + registrations, err := repo.Registrations(context.Background(), scope, filter, business.LedgerListOptions{Limit: 30}) + if err != nil { + t.Fatal(err) + } + spends, err := repo.Spends(context.Background(), scope, filter, business.LedgerListOptions{Limit: 30}) + if err != nil { + t.Fatal(err) + } + filter.Sources = []string{"lx", "hw", "historical"} + expectedRegistrations, err := repo.Registrations(context.Background(), scope, filter, business.LedgerListOptions{Limit: 30}) + if err != nil { + t.Fatal(err) + } + expectedSpends, err := repo.Spends(context.Background(), scope, filter, business.LedgerListOptions{Limit: 30}) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(registrations, expectedRegistrations) || !reflect.DeepEqual(spends, expectedSpends) { + t.Fatal("omitted platform filter lost historical, official or orphan rows") + } + if err := db.Exec("INSERT INTO tab_user(id,source_db,register_time,promote_id,puid) VALUES(91,NULL,'1500',0,0)").Error; err != nil { + t.Fatal(err) + } + all := business.LedgerFilter{} + if err := resolveLedgerSources(db, "tab_user", &all); err != nil || len(all.Sources) != 0 { + t.Fatalf("NULL platform must retain unfiltered semantics: %+v %v", all, err) + } +} + func prepareLedgerData(t *testing.T) (*gorm.DB, business.LedgerRepo, business.LedgerScope, business.LedgerFilter) { t.Helper() db, _ := prepareChannels(t)