forked from mirror/gorm
175 lines
4.6 KiB
Go
175 lines
4.6 KiB
Go
package callbacks
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"github.com/jinzhu/gorm"
|
|
"github.com/jinzhu/gorm/schema"
|
|
"github.com/jinzhu/gorm/utils"
|
|
)
|
|
|
|
func SaveBeforeAssociations(db *gorm.DB) {
|
|
if db.Statement.Schema != nil {
|
|
// Save Belongs To associations
|
|
for _, rel := range db.Statement.Schema.Relationships.BelongsTo {
|
|
creatable, updatable, saveRef := saveAssociationCheck(db, rel.Field)
|
|
if !(creatable || updatable) {
|
|
continue
|
|
}
|
|
|
|
switch db.Statement.ReflectValue.Kind() {
|
|
case reflect.Slice:
|
|
case reflect.Struct:
|
|
if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero {
|
|
f := rel.Field.ReflectValueOf(db.Statement.ReflectValue)
|
|
_, isZero := rel.FieldSchema.PrioritizedPrimaryField.ValueOf(f)
|
|
|
|
if isZero && creatable {
|
|
if f.Kind() == reflect.Ptr {
|
|
db.Session(&gorm.Session{}).Create(f.Interface())
|
|
} else {
|
|
db.Session(&gorm.Session{}).Create(f.Addr().Interface())
|
|
}
|
|
} else if !isZero && updatable {
|
|
if f.Kind() == reflect.Ptr {
|
|
db.Session(&gorm.Session{}).Save(f.Interface())
|
|
} else {
|
|
db.Session(&gorm.Session{}).Save(f.Addr().Interface())
|
|
}
|
|
} else {
|
|
continue
|
|
}
|
|
|
|
if saveRef {
|
|
for _, ref := range rel.References {
|
|
if !ref.OwnPrimaryKey {
|
|
fv, _ := ref.PrimaryKey.ValueOf(f)
|
|
ref.ForeignKey.Set(db.Statement.ReflectValue, fv)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func SaveAfterAssociations(db *gorm.DB) {
|
|
// Save Has One associations
|
|
for _, rel := range db.Statement.Schema.Relationships.HasOne {
|
|
creatable, updatable, saveRef := saveAssociationCheck(db, rel.Field)
|
|
if !(creatable || updatable) {
|
|
continue
|
|
}
|
|
|
|
switch db.Statement.ReflectValue.Kind() {
|
|
case reflect.Slice:
|
|
case reflect.Struct:
|
|
if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero {
|
|
f := rel.Field.ReflectValueOf(db.Statement.ReflectValue)
|
|
|
|
if saveRef {
|
|
for _, ref := range rel.References {
|
|
if ref.OwnPrimaryKey {
|
|
fv, _ := ref.PrimaryKey.ValueOf(db.Statement.ReflectValue)
|
|
ref.ForeignKey.Set(f, fv)
|
|
} else if ref.PrimaryValue != "" {
|
|
ref.ForeignKey.Set(f, ref.PrimaryValue)
|
|
}
|
|
}
|
|
}
|
|
|
|
_, isZero := rel.FieldSchema.PrioritizedPrimaryField.ValueOf(f)
|
|
|
|
if isZero && creatable {
|
|
if f.Kind() == reflect.Ptr {
|
|
db.Session(&gorm.Session{}).Create(f.Interface())
|
|
} else {
|
|
db.Session(&gorm.Session{}).Create(f.Addr().Interface())
|
|
}
|
|
} else if !isZero && updatable {
|
|
if f.Kind() == reflect.Ptr {
|
|
db.Session(&gorm.Session{}).Save(f.Interface())
|
|
} else {
|
|
db.Session(&gorm.Session{}).Save(f.Addr().Interface())
|
|
}
|
|
} else {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Save Has Many associations
|
|
for _, rel := range db.Statement.Schema.Relationships.HasMany {
|
|
creatable, updatable, _ := saveAssociationCheck(db, rel.Field)
|
|
if !(creatable || updatable) {
|
|
continue
|
|
}
|
|
|
|
fieldType := rel.Field.IndirectFieldType.Elem()
|
|
isPtr := true
|
|
if fieldType.Kind() != reflect.Ptr {
|
|
isPtr = false
|
|
fieldType = reflect.PtrTo(fieldType)
|
|
}
|
|
elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 0)
|
|
|
|
switch db.Statement.ReflectValue.Kind() {
|
|
case reflect.Slice:
|
|
for i := 0; i < db.Statement.ReflectValue.Len(); i++ {
|
|
db.Statement.ReflectValue.Index(i)
|
|
}
|
|
case reflect.Struct:
|
|
if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero {
|
|
f := reflect.Indirect(rel.Field.ReflectValueOf(db.Statement.ReflectValue))
|
|
|
|
for i := 0; i < f.Len(); i++ {
|
|
elem := f.Index(i)
|
|
_, isZero := rel.FieldSchema.PrioritizedPrimaryField.ValueOf(elem)
|
|
for _, ref := range rel.References {
|
|
if ref.OwnPrimaryKey {
|
|
fv, _ := ref.PrimaryKey.ValueOf(db.Statement.ReflectValue)
|
|
ref.ForeignKey.Set(elem, fv)
|
|
} else if ref.PrimaryValue != "" {
|
|
ref.ForeignKey.Set(elem, ref.PrimaryValue)
|
|
}
|
|
}
|
|
|
|
if isZero && creatable {
|
|
if isPtr {
|
|
elems = reflect.Append(elems, elem)
|
|
} else {
|
|
elems = reflect.Append(elems, elem.Addr())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if elems.Len() > 0 {
|
|
db.Session(&gorm.Session{}).Create(elems.Interface())
|
|
}
|
|
}
|
|
}
|
|
|
|
func saveAssociationCheck(db *gorm.DB, field *schema.Field) (bool, bool, bool) {
|
|
creatable := field.Creatable
|
|
updatable := field.Updatable
|
|
saveRef := true
|
|
|
|
if value, ok := db.Get("gorm:association_autocreate"); creatable && ok {
|
|
creatable = utils.CheckTruth(value)
|
|
}
|
|
|
|
if value, ok := db.Get("gorm:association_autoupdate"); updatable && ok {
|
|
updatable = utils.CheckTruth(value)
|
|
}
|
|
|
|
if value, ok := db.Get("gorm:association_save_reference"); ok {
|
|
saveRef = utils.CheckTruth(value)
|
|
}
|
|
|
|
return creatable, updatable, saveRef
|
|
}
|