merchant_repo.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package store
  2. import (
  3. "spider/internal/model"
  4. "spider/internal/plugin"
  5. "strings"
  6. "gorm.io/gorm"
  7. )
  8. // SaveRaw inserts a merchant into merchants_raw from plugin output.
  9. // Dedup: same tg_username + same source_url => skip (via unique index).
  10. // Returns true if a new record was inserted.
  11. func (s *Store) SaveRaw(data plugin.MerchantData) (bool, error) {
  12. if strings.TrimSpace(data.TgUsername) == "" {
  13. return false, nil // no tg_username = don't insert
  14. }
  15. username := strings.TrimPrefix(strings.TrimSpace(data.TgUsername), "@")
  16. tgLink := data.TgLink
  17. if tgLink == "" && username != "" {
  18. tgLink = "https://t.me/" + username
  19. }
  20. // Truncate source_url to fit the unique index (255+500 chars × 4 bytes = 3020 < 3072)
  21. sourceURL := data.SourceURL
  22. if len(sourceURL) > 490 {
  23. sourceURL = sourceURL[:490]
  24. }
  25. raw := model.MerchantRaw{
  26. MerchantName: data.MerchantName,
  27. TgUsername: username,
  28. TgLink: tgLink,
  29. Website: data.Website,
  30. Email: data.Email,
  31. Phone: data.Phone,
  32. IndustryTag: data.IndustryTag,
  33. SourceType: data.SourceType,
  34. SourceName: data.SourceName,
  35. SourceURL: sourceURL,
  36. OriginalText: data.OriginalText,
  37. Status: "raw",
  38. }
  39. // Use unique index for dedup: insert only if (tg_username, source_url) doesn't exist
  40. result := s.DB.Where("tg_username = ? AND source_url = ?", username, sourceURL).
  41. FirstOrCreate(&raw)
  42. if result.Error != nil {
  43. return false, result.Error
  44. }
  45. // RowsAffected == 1 means a new record was created
  46. return result.RowsAffected > 0, nil
  47. }
  48. // ListRawByStatus returns raw merchants with the given status.
  49. func (s *Store) ListRawByStatus(status string, limit int) ([]model.MerchantRaw, error) {
  50. var raws []model.MerchantRaw
  51. q := s.DB.Where("status = ?", status)
  52. if limit > 0 {
  53. q = q.Limit(limit)
  54. }
  55. err := q.Find(&raws).Error
  56. return raws, err
  57. }
  58. // UpdateRawStatus sets the status of a raw merchant.
  59. func (s *Store) UpdateRawStatus(id uint, status string) error {
  60. return s.DB.Model(&model.MerchantRaw{}).Where("id = ?", id).Update("status", status).Error
  61. }
  62. // BatchUpdateRawStatus sets the status for multiple raw merchants in one query.
  63. func (s *Store) BatchUpdateRawStatus(ids []uint, status string) error {
  64. if len(ids) == 0 {
  65. return nil
  66. }
  67. return s.DB.Model(&model.MerchantRaw{}).Where("id IN ?", ids).Update("status", status).Error
  68. }
  69. // SaveClean upserts a clean merchant by tg_username.
  70. func (s *Store) SaveClean(m *model.MerchantClean) error {
  71. var existing model.MerchantClean
  72. err := s.DB.Where("tg_username = ?", m.TgUsername).First(&existing).Error
  73. if err == gorm.ErrRecordNotFound {
  74. return s.DB.Create(m).Error
  75. }
  76. if err != nil {
  77. return err
  78. }
  79. m.ID = existing.ID
  80. return s.DB.Save(m).Error
  81. }
  82. // ListClean returns paginated clean merchants with optional filters.
  83. func (s *Store) ListClean(filters map[string]string, page, pageSize int) ([]model.MerchantClean, int64, error) {
  84. var merchants []model.MerchantClean
  85. var total int64
  86. q := s.DB.Model(&model.MerchantClean{})
  87. if v, ok := filters["status"]; ok && v != "" {
  88. q = q.Where("status = ?", v)
  89. }
  90. if v, ok := filters["level"]; ok && v != "" {
  91. q = q.Where("level = ?", v)
  92. }
  93. if v, ok := filters["industry_tag"]; ok && v != "" {
  94. q = q.Where("industry_tag = ?", v)
  95. }
  96. if v, ok := filters["search"]; ok && v != "" {
  97. like := "%" + v + "%"
  98. q = q.Where("tg_username LIKE ? OR merchant_name LIKE ?", like, like)
  99. }
  100. q.Count(&total)
  101. offset := (page - 1) * pageSize
  102. err := q.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&merchants).Error
  103. return merchants, total, err
  104. }