From cd15dafcee0ee20e7a4dffb08df5d8b2f1aaa240 Mon Sep 17 00:00:00 2001 From: yanweidong Date: Tue, 7 Apr 2026 21:40:29 +0800 Subject: [PATCH] fix bug --- collector/collector_test.go | 58 ------------------------ storage/storage.go | 89 ++++++++++++++++++++++++------------- 2 files changed, 59 insertions(+), 88 deletions(-) delete mode 100644 collector/collector_test.go diff --git a/collector/collector_test.go b/collector/collector_test.go deleted file mode 100644 index f4f2b28..0000000 --- a/collector/collector_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package collector - -import ( - "encoding/json" - "os" - "testing" - - "git.apinb.com/quant/collector/types" -) - -// TestCalculateHash 测试Hash计算功能 -func TestCalculateHash(t *testing.T) { - // 读取样本数据 - data, err := os.ReadFile("../exmple/status.json") - if err != nil { - t.Fatalf("读取样本文件失败: %v", err) - } - - var status types.Status - if err := json.Unmarshal(data, &status); err != nil { - t.Fatalf("JSON解析失败: %v", err) - } - - collector := NewCollector("http://localhost:5000/status") - hash, err := collector.CalculateHash(&status) - if err != nil { - t.Fatalf("计算Hash失败: %v", err) - } - - if hash == "" { - t.Error("Hash值不能为空") - } - - t.Logf("计算的Hash: %s", hash) -} - -// TestHasChanged 测试变化检测 -func TestHasChanged(t *testing.T) { - collector := NewCollector("http://localhost:5000/status") - - // 第一次应该返回true - if !collector.HasChanged("hash1") { - t.Error("第一次检测应该返回true") - } - - // 更新hash - collector.UpdateHash("hash1") - - // 相同的hash应该返回false - if collector.HasChanged("hash1") { - t.Error("相同的hash应该返回false") - } - - // 不同的hash应该返回true - if !collector.HasChanged("hash2") { - t.Error("不同的hash应该返回true") - } -} diff --git a/storage/storage.go b/storage/storage.go index 790bd58..4a8538b 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -87,6 +87,11 @@ func (s *Storage) AutoMigrate() error { // SaveStatus 保存完整状态数据(使用事务) func (s *Storage) SaveStatus(status *types.Status, dataHash string) error { + // 验证必要字段 - AccountID是所有Upsert的共同条件 + if status.Data.Assets.AccountID == "" { + return fmt.Errorf("账户ID不能为空") + } + return s.db.Transaction(func(tx *gorm.DB) error { // 计算Ymd (年月日数字格式,如20260407) now := time.Now() @@ -117,6 +122,14 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error { if len(status.Data.Orders) > 0 { orders := make([]models.CollectorOrder, 0, len(status.Data.Orders)) for _, order := range status.Data.Orders { + // 验证Upsert必要条件: OrderID和StockCode + if order.OrderID == 0 { + continue + } + if order.StockCode == "" { + continue + } + orders = append(orders, models.CollectorOrder{ OrderID: order.OrderID, AccountID: status.Data.Assets.AccountID, @@ -134,15 +147,17 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error { }) } // 使用Upsert逻辑: 以 account_id, order_id, ymd 为条件 - if err := tx.Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "account_id"}, {Name: "order_id"}, {Name: "ymd"}}, - DoUpdates: clause.AssignmentColumns([]string{ - "stock_code", "price", "volume", - "traded_price", "traded_volume", "order_status", - "order_time", "order_remark", "data_hash", "collected_at", - }), - }).Create(&orders).Error; err != nil { - return fmt.Errorf("保存订单失败: %w", err) + if len(orders) > 0 { + if err := tx.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "account_id"}, {Name: "order_id"}, {Name: "ymd"}}, + DoUpdates: clause.AssignmentColumns([]string{ + "stock_code", "price", "volume", + "traded_price", "traded_volume", "order_status", + "order_time", "order_remark", "data_hash", "collected_at", + }), + }).Create(&orders).Error; err != nil { + return fmt.Errorf("保存订单失败: %w", err) + } } } @@ -150,6 +165,11 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error { if len(status.Data.Positions) > 0 { positions := make([]models.CollectorPosition, 0, len(status.Data.Positions)) for _, pos := range status.Data.Positions { + // 验证Upsert必要条件: Code + if pos.Code == "" { + continue + } + positions = append(positions, models.CollectorPosition{ AccountID: status.Data.Assets.AccountID, Code: pos.Code, @@ -169,16 +189,18 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error { }) } // 使用Upsert逻辑: 以 account_id, code, ymd 为条件 - if err := tx.Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "account_id"}, {Name: "code"}, {Name: "ymd"}}, - DoUpdates: clause.AssignmentColumns([]string{ - "volume", "can_use_volume", "frozen_volume", - "avg_price", "open_price", "current_price", - "market_value", "profit", "profit_rate", - "min_profit_rate", "data_hash", "collected_at", - }), - }).Create(&positions).Error; err != nil { - return fmt.Errorf("保存持仓失败: %w", err) + if len(positions) > 0 { + if err := tx.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "account_id"}, {Name: "code"}, {Name: "ymd"}}, + DoUpdates: clause.AssignmentColumns([]string{ + "volume", "can_use_volume", "frozen_volume", + "avg_price", "open_price", "current_price", + "market_value", "profit", "profit_rate", + "min_profit_rate", "data_hash", "collected_at", + }), + }).Create(&positions).Error; err != nil { + return fmt.Errorf("保存持仓失败: %w", err) + } } } @@ -186,6 +208,11 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error { if len(status.Data.TickData) > 0 { ticks := make([]models.CollectorTick, 0, len(status.Data.TickData)) for code, tick := range status.Data.TickData { + // 验证Upsert必要条件: StockCode + if code == "" { + continue + } + ticks = append(ticks, models.CollectorTick{ StockCode: code, Ymd: ymd, @@ -209,17 +236,19 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error { }) } // 使用Upsert逻辑: 以 stock_code, ymd 为条件 - if err := tx.Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "stock_code"}, {Name: "ymd"}}, - DoUpdates: clause.AssignmentColumns([]string{ - "last_price", "open", "high", "low", "last_close", - "volume", "amount", "pvolume", - "bid_prices", "bid_volumes", "ask_prices", "ask_volumes", - "time", "timetag", "stock_status", - "data_hash", "collected_at", - }), - }).Create(&ticks).Error; err != nil { - return fmt.Errorf("保存行情数据失败: %w", err) + if len(ticks) > 0 { + if err := tx.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "stock_code"}, {Name: "ymd"}}, + DoUpdates: clause.AssignmentColumns([]string{ + "last_price", "open", "high", "low", "last_close", + "volume", "amount", "pvolume", + "bid_prices", "bid_volumes", "ask_prices", "ask_volumes", + "time", "timetag", "stock_status", + "data_hash", "collected_at", + }), + }).Create(&ticks).Error; err != nil { + return fmt.Errorf("保存行情数据失败: %w", err) + } } }