package utils import ( "gorm.io/gorm/clause" "nCovTrack-Backend/global" "reflect" "regexp" "time" ) var colNameReg, _ = regexp.Compile(".*column:(.*);?") var uniqueKeyReg, _ = regexp.Compile(".*(primaryKey|unique).*") func getNotZeroFields[T any](model T) []string { t := reflect.TypeOf(model) v := reflect.ValueOf(model) var notZeroFields []string for i := 0; i < t.NumField(); i++ { if !v.Field(i).IsZero() { colName := colNameReg.FindSubmatch([]byte(t.Field(i).Tag.Get("gorm"))) if len(colName) != 2 { panic("Model Tag regex error") } notZeroFields = append(notZeroFields, string(colName[1])) } } return notZeroFields } func Upsert[T any](model *T, forceUpdateFiled ...string) (ok bool) { t := reflect.TypeOf(model).Elem() v := reflect.ValueOf(model).Elem() var uniqueKeyField []clause.Column notZeroField := NewSet(forceUpdateFiled...).Add("modify_time") for i := 0; i < t.NumField(); i++ { gormTag := t.Field(i).Tag.Get("gorm") if uniqueKey(gormTag) { uniqueKeyField = append(uniqueKeyField, clause.Column{Name: columnName(gormTag)}) continue } if !v.Field(i).IsZero() { notZeroField.Add(columnName(gormTag)) } else if t.Field(i).Type.Name() == "Time" { v.Field(i).Set(reflect.ValueOf(time.Now())) } } tx := global.Db.Clauses(clause.OnConflict{ Columns: uniqueKeyField, DoUpdates: clause.AssignmentColumns(notZeroField.ToSlice()), }, clause.Returning{}).Create(model) if tx.Error != nil { return false } return true } func columnName(gormTag string) string { colNames := colNameReg.FindSubmatch([]byte(gormTag)) if len(colNames) != 2 { panic("Model tag regex error") } return string(colNames[1]) } func uniqueKey(gormTag string) bool { return uniqueKeyReg.Match([]byte(gormTag)) }