From 0b45d48e85e594303b138f7cced59727aa4ddcca Mon Sep 17 00:00:00 2001 From: LLLLLLiulei <1065070665@qq.com> Date: Thu, 5 Feb 2026 18:40:49 +0800 Subject: [PATCH] perf: batch fetch proxies for account export --- .../internal/handler/admin/account_data.go | 27 +++++++++++++++++-- .../admin/account_data_handler_test.go | 2 +- .../handler/admin/admin_service_stub_test.go | 18 +++++++++++++ backend/internal/repository/proxy_repo.go | 19 +++++++++++++ backend/internal/server/api_contract_test.go | 4 +++ backend/internal/service/admin_service.go | 5 ++++ .../service/admin_service_delete_test.go | 4 +++ backend/internal/service/proxy_service.go | 1 + 8 files changed, 77 insertions(+), 3 deletions(-) diff --git a/backend/internal/handler/admin/account_data.go b/backend/internal/handler/admin/account_data.go index 6e90c2e5..86f4cbae 100644 --- a/backend/internal/handler/admin/account_data.go +++ b/backend/internal/handler/admin/account_data.go @@ -393,8 +393,31 @@ func (h *AccountHandler) resolveExportAccounts(ctx context.Context, ids []int64, } func (h *AccountHandler) resolveExportProxies(ctx context.Context, accounts []service.Account) ([]service.Proxy, error) { - _ = accounts - return h.listAllProxies(ctx) + if len(accounts) == 0 { + return []service.Proxy{}, nil + } + + seen := make(map[int64]struct{}) + ids := make([]int64, 0) + for i := range accounts { + if accounts[i].ProxyID == nil { + continue + } + id := *accounts[i].ProxyID + if id <= 0 { + continue + } + if _, ok := seen[id]; ok { + continue + } + seen[id] = struct{}{} + ids = append(ids, id) + } + if len(ids) == 0 { + return []service.Proxy{}, nil + } + + return h.adminService.GetProxiesByIDs(ctx, ids) } func parseAccountIDs(c *gin.Context) ([]int64, error) { diff --git a/backend/internal/handler/admin/account_data_handler_test.go b/backend/internal/handler/admin/account_data_handler_test.go index 9a6870f4..a96e27c0 100644 --- a/backend/internal/handler/admin/account_data_handler_test.go +++ b/backend/internal/handler/admin/account_data_handler_test.go @@ -121,7 +121,7 @@ func TestExportDataIncludesSecrets(t *testing.T) { require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp)) require.Equal(t, 0, resp.Code) require.Equal(t, dataType, resp.Data.Type) - require.Len(t, resp.Data.Proxies, 2) + require.Len(t, resp.Data.Proxies, 1) require.Equal(t, "pass", resp.Data.Proxies[0].Password) require.Len(t, resp.Data.Accounts, 1) require.Equal(t, "secret", resp.Data.Accounts[0].Credentials["token"]) diff --git a/backend/internal/handler/admin/admin_service_stub_test.go b/backend/internal/handler/admin/admin_service_stub_test.go index a5376e4a..77d288f9 100644 --- a/backend/internal/handler/admin/admin_service_stub_test.go +++ b/backend/internal/handler/admin/admin_service_stub_test.go @@ -269,6 +269,24 @@ func (s *stubAdminService) GetProxy(ctx context.Context, id int64) (*service.Pro return &proxy, nil } +func (s *stubAdminService) GetProxiesByIDs(ctx context.Context, ids []int64) ([]service.Proxy, error) { + if len(ids) == 0 { + return []service.Proxy{}, nil + } + out := make([]service.Proxy, 0, len(ids)) + seen := make(map[int64]struct{}, len(ids)) + for _, id := range ids { + seen[id] = struct{}{} + } + for i := range s.proxies { + proxy := s.proxies[i] + if _, ok := seen[proxy.ID]; ok { + out = append(out, proxy) + } + } + return out, nil +} + func (s *stubAdminService) CreateProxy(ctx context.Context, input *service.CreateProxyInput) (*service.Proxy, error) { s.mu.Lock() s.createdProxies = append(s.createdProxies, input) diff --git a/backend/internal/repository/proxy_repo.go b/backend/internal/repository/proxy_repo.go index 36965c05..07c2a204 100644 --- a/backend/internal/repository/proxy_repo.go +++ b/backend/internal/repository/proxy_repo.go @@ -60,6 +60,25 @@ func (r *proxyRepository) GetByID(ctx context.Context, id int64) (*service.Proxy return proxyEntityToService(m), nil } +func (r *proxyRepository) ListByIDs(ctx context.Context, ids []int64) ([]service.Proxy, error) { + if len(ids) == 0 { + return []service.Proxy{}, nil + } + + proxies, err := r.client.Proxy.Query(). + Where(proxy.IDIn(ids...)). + All(ctx) + if err != nil { + return nil, err + } + + out := make([]service.Proxy, 0, len(proxies)) + for i := range proxies { + out = append(out, *proxyEntityToService(proxies[i])) + } + return out, nil +} + func (r *proxyRepository) Update(ctx context.Context, proxyIn *service.Proxy) error { builder := r.client.Proxy.UpdateOneID(proxyIn.ID). SetName(proxyIn.Name). diff --git a/backend/internal/server/api_contract_test.go b/backend/internal/server/api_contract_test.go index e197b776..9c8d514b 100644 --- a/backend/internal/server/api_contract_test.go +++ b/backend/internal/server/api_contract_test.go @@ -1059,6 +1059,10 @@ func (stubProxyRepo) GetByID(ctx context.Context, id int64) (*service.Proxy, err return nil, service.ErrProxyNotFound } +func (stubProxyRepo) ListByIDs(ctx context.Context, ids []int64) ([]service.Proxy, error) { + return nil, errors.New("not implemented") +} + func (stubProxyRepo) Update(ctx context.Context, proxy *service.Proxy) error { return errors.New("not implemented") } diff --git a/backend/internal/service/admin_service.go b/backend/internal/service/admin_service.go index 3f7624ac..0b65a5ae 100644 --- a/backend/internal/service/admin_service.go +++ b/backend/internal/service/admin_service.go @@ -56,6 +56,7 @@ type AdminService interface { GetAllProxies(ctx context.Context) ([]Proxy, error) GetAllProxiesWithAccountCount(ctx context.Context) ([]ProxyWithAccountCount, error) GetProxy(ctx context.Context, id int64) (*Proxy, error) + GetProxiesByIDs(ctx context.Context, ids []int64) ([]Proxy, error) CreateProxy(ctx context.Context, input *CreateProxyInput) (*Proxy, error) UpdateProxy(ctx context.Context, id int64, input *UpdateProxyInput) (*Proxy, error) DeleteProxy(ctx context.Context, id int64) error @@ -1346,6 +1347,10 @@ func (s *adminServiceImpl) GetProxy(ctx context.Context, id int64) (*Proxy, erro return s.proxyRepo.GetByID(ctx, id) } +func (s *adminServiceImpl) GetProxiesByIDs(ctx context.Context, ids []int64) ([]Proxy, error) { + return s.proxyRepo.ListByIDs(ctx, ids) +} + func (s *adminServiceImpl) CreateProxy(ctx context.Context, input *CreateProxyInput) (*Proxy, error) { proxy := &Proxy{ Name: input.Name, diff --git a/backend/internal/service/admin_service_delete_test.go b/backend/internal/service/admin_service_delete_test.go index e2aa83d9..c775749d 100644 --- a/backend/internal/service/admin_service_delete_test.go +++ b/backend/internal/service/admin_service_delete_test.go @@ -187,6 +187,10 @@ func (s *proxyRepoStub) GetByID(ctx context.Context, id int64) (*Proxy, error) { panic("unexpected GetByID call") } +func (s *proxyRepoStub) ListByIDs(ctx context.Context, ids []int64) ([]Proxy, error) { + panic("unexpected ListByIDs call") +} + func (s *proxyRepoStub) Update(ctx context.Context, proxy *Proxy) error { panic("unexpected Update call") } diff --git a/backend/internal/service/proxy_service.go b/backend/internal/service/proxy_service.go index a5d897f6..80045187 100644 --- a/backend/internal/service/proxy_service.go +++ b/backend/internal/service/proxy_service.go @@ -16,6 +16,7 @@ var ( type ProxyRepository interface { Create(ctx context.Context, proxy *Proxy) error GetByID(ctx context.Context, id int64) (*Proxy, error) + ListByIDs(ctx context.Context, ids []int64) ([]Proxy, error) Update(ctx context.Context, proxy *Proxy) error Delete(ctx context.Context, id int64) error