2021-02-05 16:32:08 +01:00
|
|
|
package entity
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2021-02-06 16:30:30 +01:00
|
|
|
// Values returns entity values as string map.
|
|
|
|
func Values(m interface{}, omit ...string) (result map[string]interface{}) {
|
|
|
|
skip := func(name string) bool {
|
|
|
|
for _, s := range omit {
|
|
|
|
if name == s {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
result = make(map[string]interface{})
|
|
|
|
|
|
|
|
elem := reflect.ValueOf(m).Elem()
|
|
|
|
relType := elem.Type()
|
|
|
|
|
|
|
|
for i := 0; i < relType.NumField(); i++ {
|
|
|
|
name := relType.Field(i).Name
|
|
|
|
|
|
|
|
if skip(name) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
result[name] = elem.Field(i).Interface()
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2021-02-05 16:32:08 +01:00
|
|
|
// Save updates an entity in the database, or inserts if it doesn't exist.
|
|
|
|
func Save(m interface{}, primaryKeys ...string) (err error) {
|
|
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
err = fmt.Errorf("save: %s (panic)", r)
|
2021-02-06 16:30:30 +01:00
|
|
|
log.Error(err)
|
2021-02-05 16:32:08 +01:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err := Update(m, primaryKeys...); err == nil {
|
|
|
|
return nil
|
|
|
|
} else if err := UnscopedDb().Save(m).Error; err == nil {
|
|
|
|
return nil
|
|
|
|
} else if !strings.Contains(strings.ToLower(err.Error()), "lock") {
|
|
|
|
return err
|
|
|
|
} else if err := UnscopedDb().Save(m).Error; err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update updates an existing entity in the database.
|
|
|
|
func Update(m interface{}, primaryKeys ...string) (err error) {
|
|
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
err = fmt.Errorf("update: %s (panic)", r)
|
2021-02-06 16:30:30 +01:00
|
|
|
log.Error(err)
|
2021-02-05 16:32:08 +01:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
v := reflect.ValueOf(m).Elem()
|
|
|
|
|
2021-02-05 18:22:52 +01:00
|
|
|
// Abort if a primary key is zero.
|
2021-02-05 16:32:08 +01:00
|
|
|
for _, k := range primaryKeys {
|
|
|
|
if field := v.FieldByName(k); field.IsZero() {
|
|
|
|
return fmt.Errorf("key '%s' not found", k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-05 18:22:52 +01:00
|
|
|
// Update all values except primary keys.
|
2021-02-06 16:30:30 +01:00
|
|
|
if res := UnscopedDb().Model(m).Updates(Values(m, primaryKeys...)); res.Error != nil {
|
2021-02-05 16:32:08 +01:00
|
|
|
return res.Error
|
|
|
|
} else if res.RowsAffected > 1 {
|
2021-02-06 16:30:30 +01:00
|
|
|
log.Warnf("update: more than one row affected")
|
|
|
|
} else if res.RowsAffected == 0 {
|
|
|
|
// MariaDB may report zero rows in case no data was actually changed, even though the row exists.
|
|
|
|
log.Tracef("update: no rows affected")
|
2021-02-05 16:32:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|