103 lines
3.9 KiB
Go
103 lines
3.9 KiB
Go
package breeds
|
|
|
|
import (
|
|
_ "embed"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"github.com/mozillazg/go-pinyin"
|
|
"github.com/sundynix/pets-be/internal/model"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
//go:embed data.json
|
|
var data []byte
|
|
|
|
// SortFields provides both full pinyin and initials, retaining Latin breed names.
|
|
func SortFields(name string) (string, string, string) {
|
|
args := pinyin.NewArgs()
|
|
args.Fallback = func(r rune, _ pinyin.Args) []string {
|
|
if unicode.IsLetter(r) || unicode.IsDigit(r) {
|
|
return []string{strings.ToLower(string(r))}
|
|
}
|
|
return nil
|
|
}
|
|
words := pinyin.LazyPinyin(name, args)
|
|
// Breed-name phrases with common alternative pronunciations.
|
|
if strings.HasPrefix(name, "重庆") && len(words) > 0 {
|
|
words[0] = "chong"
|
|
}
|
|
if strings.HasPrefix(name, "长毛") && len(words) > 0 {
|
|
words[0] = "chang"
|
|
}
|
|
full := strings.Join(words, "")
|
|
var initials strings.Builder
|
|
for _, word := range words {
|
|
if word != "" {
|
|
initials.WriteByte(word[0])
|
|
}
|
|
}
|
|
initial := "#"
|
|
if len(full) > 0 && full[0] >= 'a' && full[0] <= 'z' {
|
|
initial = strings.ToUpper(full[:1])
|
|
}
|
|
return full, initials.String(), initial
|
|
}
|
|
|
|
func Defaults() ([]model.Breed, error) {
|
|
var rows []struct {
|
|
Origin string `json:"origin"`
|
|
BreedGroup string `json:"breed_group"`
|
|
FCINumber string `json:"fci_number"`
|
|
EnglishName string `json:"english_name"`
|
|
Height string `json:"height"`
|
|
Weight string `json:"weight"`
|
|
Summary string `json:"summary"`
|
|
Temperament string `json:"temperament"`
|
|
Traits string `json:"traits"`
|
|
CareNotes string `json:"care_notes"`
|
|
EncyclopediaUpdatedAt string `json:"encyclopedia_updated_at"`
|
|
Name string `json:"name"`
|
|
Aliases string `json:"aliases"`
|
|
Source string `json:"source"`
|
|
SourceKey string `json:"source_key"`
|
|
SourceURL string `json:"source_url"`
|
|
}
|
|
if err := json.Unmarshal(data, &rows); err != nil {
|
|
return nil, err
|
|
}
|
|
result := make([]model.Breed, 0, len(rows))
|
|
for _, row := range rows {
|
|
full, short, initial := SortFields(row.Name)
|
|
key := row.SourceKey
|
|
result = append(result, model.Breed{Origin: row.Origin, BreedGroup: row.BreedGroup, FCINumber: row.FCINumber, EnglishName: row.EnglishName, Height: row.Height, Weight: row.Weight, Summary: row.Summary, Temperament: row.Temperament, Traits: row.Traits, CareNotes: row.CareNotes, EncyclopediaUpdatedAt: row.EncyclopediaUpdatedAt, Name: row.Name, Aliases: row.Aliases, Pinyin: full, PinyinInitials: short, Initial: initial, Enabled: true, Source: row.Source, SourceKey: &key, SourceURL: row.SourceURL})
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// Existing entries (including edits and disabled breeds) are never overwritten.
|
|
func Seed(db *gorm.DB) (int64, error) {
|
|
rows, err := Defaults()
|
|
if err != nil {
|
|
return 0, fmt.Errorf("load breeds: %w", err)
|
|
}
|
|
result := db.Clauses(clause.OnConflict{DoNothing: true}).CreateInBatches(rows, 100)
|
|
if result.Error != nil {
|
|
return result.RowsAffected, result.Error
|
|
}
|
|
// Backfill newly introduced encyclopedia fields exactly once on untouched seed rows.
|
|
// Future starts never overwrite administrator changes.
|
|
for _, row := range rows {
|
|
if row.Summary == "" {
|
|
continue
|
|
}
|
|
if err := db.Model(&model.Breed{}).Where("source_key = ? AND name = ? AND (encyclopedia_updated_at IS NULL OR encyclopedia_updated_at = '') AND updated_at = created_at", row.SourceKey, row.Name).Updates(map[string]any{"origin": row.Origin, "breed_group": row.BreedGroup, "fci_number": row.FCINumber, "english_name": row.EnglishName, "height": row.Height, "weight": row.Weight, "summary": row.Summary, "temperament": row.Temperament, "traits": row.Traits, "care_notes": row.CareNotes, "encyclopedia_updated_at": row.EncyclopediaUpdatedAt}).Error; err != nil {
|
|
return result.RowsAffected, err
|
|
}
|
|
}
|
|
return result.RowsAffected, enrich(db)
|
|
}
|