gorm/callbacks/preload.go

118 lines
4.1 KiB
Go
Raw Normal View History

2020-05-07 05:03:48 +03:00
package callbacks
import (
2020-05-14 07:19:12 +03:00
"reflect"
2020-05-07 05:03:48 +03:00
"github.com/jinzhu/gorm"
2020-05-14 07:19:12 +03:00
"github.com/jinzhu/gorm/clause"
2020-05-07 05:03:48 +03:00
"github.com/jinzhu/gorm/schema"
2020-05-14 07:19:12 +03:00
"github.com/jinzhu/gorm/utils"
2020-05-07 05:03:48 +03:00
)
func preload(db *gorm.DB, rels []*schema.Relationship, conds []interface{}) {
2020-05-14 07:19:12 +03:00
var (
reflectValue = db.Statement.ReflectValue
2020-05-14 07:19:12 +03:00
rel = rels[len(rels)-1]
tx = db.Session(&gorm.Session{})
2020-05-14 07:19:12 +03:00
relForeignKeys []string
relForeignFields []*schema.Field
foreignFields []*schema.Field
foreignValues [][]interface{}
identityMap = map[string][]reflect.Value{}
)
if len(rels) > 1 {
2020-05-23 19:52:25 +03:00
reflectValue = schema.GetRelationsValues(reflectValue, rels[:len(rels)-1])
2020-05-14 07:19:12 +03:00
}
if rel.JoinTable != nil {
var joinForeignFields, joinRelForeignFields []*schema.Field
var joinForeignKeys []string
for _, ref := range rel.References {
if ref.OwnPrimaryKey {
joinForeignKeys = append(joinForeignKeys, ref.ForeignKey.DBName)
joinForeignFields = append(joinForeignFields, ref.ForeignKey)
foreignFields = append(foreignFields, ref.PrimaryKey)
} else if ref.PrimaryValue != "" {
tx.Where(clause.Eq{Column: ref.ForeignKey.DBName, Value: ref.PrimaryValue})
} else {
joinRelForeignFields = append(joinRelForeignFields, ref.ForeignKey)
relForeignKeys = append(relForeignKeys, ref.PrimaryKey.DBName)
relForeignFields = append(relForeignFields, ref.PrimaryKey)
}
}
2020-05-23 16:03:28 +03:00
joinIdentityMap, joinForeignValues := schema.GetIdentityFieldValuesMap(reflectValue, foreignFields)
if len(joinForeignValues) == 0 {
return
}
2020-05-18 08:07:11 +03:00
joinResults := rel.JoinTable.MakeSlice().Elem()
column, values := schema.ToQueryValues(joinForeignKeys, joinForeignValues)
tx.Where(clause.IN{Column: column, Values: values}).Find(joinResults.Addr().Interface())
2020-05-14 07:19:12 +03:00
// convert join identity map to relation identity map
2020-05-23 16:03:28 +03:00
fieldValues := make([]interface{}, len(foreignFields))
joinFieldValues := make([]interface{}, len(joinForeignFields))
2020-05-14 07:19:12 +03:00
for i := 0; i < joinResults.Len(); i++ {
2020-05-23 16:03:28 +03:00
for idx, field := range joinForeignFields {
fieldValues[idx], _ = field.ValueOf(joinResults.Index(i))
2020-05-14 07:19:12 +03:00
}
2020-05-23 16:03:28 +03:00
for idx, field := range joinRelForeignFields {
joinFieldValues[idx], _ = field.ValueOf(joinResults.Index(i))
2020-05-14 07:19:12 +03:00
}
if results, ok := joinIdentityMap[utils.ToStringKey(fieldValues...)]; ok {
identityMap[utils.ToStringKey(joinFieldValues...)] = results
}
}
2020-05-18 08:07:11 +03:00
_, foreignValues = schema.GetIdentityFieldValuesMap(joinResults, joinRelForeignFields)
2020-05-14 07:19:12 +03:00
} else {
for _, ref := range rel.References {
if ref.OwnPrimaryKey {
relForeignKeys = append(relForeignKeys, ref.ForeignKey.DBName)
relForeignFields = append(relForeignFields, ref.ForeignKey)
foreignFields = append(foreignFields, ref.PrimaryKey)
} else if ref.PrimaryValue != "" {
tx.Where(clause.Eq{Column: ref.ForeignKey.DBName, Value: ref.PrimaryValue})
} else {
relForeignKeys = append(relForeignKeys, ref.PrimaryKey.DBName)
relForeignFields = append(relForeignFields, ref.PrimaryKey)
foreignFields = append(foreignFields, ref.ForeignKey)
}
}
2020-05-18 08:07:11 +03:00
identityMap, foreignValues = schema.GetIdentityFieldValuesMap(reflectValue, foreignFields)
2020-05-23 16:03:28 +03:00
if len(foreignValues) == 0 {
return
}
2020-05-14 07:19:12 +03:00
}
2020-05-18 08:07:11 +03:00
reflectResults := rel.FieldSchema.MakeSlice().Elem()
column, values := schema.ToQueryValues(relForeignKeys, foreignValues)
tx.Where(clause.IN{Column: column, Values: values}).Find(reflectResults.Addr().Interface(), conds...)
2020-05-14 07:19:12 +03:00
2020-05-23 16:03:28 +03:00
fieldValues := make([]interface{}, len(foreignFields))
2020-05-14 07:19:12 +03:00
for i := 0; i < reflectResults.Len(); i++ {
for idx, field := range relForeignFields {
2020-05-23 16:03:28 +03:00
fieldValues[idx], _ = field.ValueOf(reflectResults.Index(i))
2020-05-14 07:19:12 +03:00
}
for _, data := range identityMap[utils.ToStringKey(fieldValues...)] {
reflectFieldValue := reflect.Indirect(rel.Field.ReflectValueOf(data))
switch reflectFieldValue.Kind() {
case reflect.Struct:
rel.Field.Set(data, reflectResults.Index(i).Interface())
2020-05-14 07:19:12 +03:00
case reflect.Slice, reflect.Array:
if reflectFieldValue.Type().Elem().Kind() == reflect.Ptr {
rel.Field.Set(data, reflect.Append(reflectFieldValue, reflectResults.Index(i)).Interface())
2020-05-23 19:52:25 +03:00
} else {
rel.Field.Set(data, reflect.Append(reflectFieldValue, reflectResults.Index(i).Elem()).Interface())
}
2020-05-14 07:19:12 +03:00
}
}
}
2020-05-07 05:03:48 +03:00
}