preloadEntryPoint enters layer by layer. It will call real preload if it finds the right entry point. If the current relationship is embedded or joined, current query will be ignored. nolint:cyclop
(db *gorm.DB, joins []string, relationships *schema.Relationships, preloads map[string][]interface{}, associationsConds []interface{})
| 88 | // |
| 89 | //nolint:cyclop |
| 90 | func preloadEntryPoint(db *gorm.DB, joins []string, relationships *schema.Relationships, preloads map[string][]interface{}, associationsConds []interface{}) error { |
| 91 | preloadMap := parsePreloadMap(db.Statement.Schema, preloads) |
| 92 | |
| 93 | // avoid random traversal of the map |
| 94 | preloadNames := make([]string, 0, len(preloadMap)) |
| 95 | for key := range preloadMap { |
| 96 | preloadNames = append(preloadNames, key) |
| 97 | } |
| 98 | sort.Strings(preloadNames) |
| 99 | |
| 100 | isJoined := func(name string) (joined bool, nestedJoins []string) { |
| 101 | for _, join := range joins { |
| 102 | if _, ok := relationships.Relations[join]; ok && name == join { |
| 103 | joined = true |
| 104 | continue |
| 105 | } |
| 106 | join0, join1, cut := strings.Cut(join, ".") |
| 107 | if cut { |
| 108 | if _, ok := relationships.Relations[join0]; ok && name == join0 { |
| 109 | joined = true |
| 110 | nestedJoins = append(nestedJoins, join1) |
| 111 | } |
| 112 | } |
| 113 | } |
| 114 | return joined, nestedJoins |
| 115 | } |
| 116 | |
| 117 | for _, name := range preloadNames { |
| 118 | if relations := relationships.EmbeddedRelations[name]; relations != nil { |
| 119 | if err := preloadEntryPoint(db, joins, relations, preloadMap[name], associationsConds); err != nil { |
| 120 | return err |
| 121 | } |
| 122 | } else if rel := relationships.Relations[name]; rel != nil { |
| 123 | if joined, nestedJoins := isJoined(name); joined { |
| 124 | switch rv := db.Statement.ReflectValue; rv.Kind() { |
| 125 | case reflect.Slice, reflect.Array: |
| 126 | if rv.Len() > 0 { |
| 127 | reflectValue := rel.FieldSchema.MakeSlice().Elem() |
| 128 | for i := 0; i < rv.Len(); i++ { |
| 129 | frv := rel.Field.ReflectValueOf(db.Statement.Context, rv.Index(i)) |
| 130 | if frv.Kind() != reflect.Ptr { |
| 131 | reflectValue = reflect.Append(reflectValue, frv.Addr()) |
| 132 | } else { |
| 133 | if frv.IsNil() { |
| 134 | continue |
| 135 | } |
| 136 | reflectValue = reflect.Append(reflectValue, frv) |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | tx := preloadDB(db, reflectValue, reflectValue.Interface()) |
| 141 | if err := preloadEntryPoint(tx, nestedJoins, &tx.Statement.Schema.Relationships, preloadMap[name], associationsConds); err != nil { |
| 142 | return err |
| 143 | } |
| 144 | } |
| 145 | case reflect.Struct, reflect.Pointer: |
| 146 | reflectValue := rel.Field.ReflectValueOf(db.Statement.Context, rv) |
| 147 | tx := preloadDB(db, reflectValue, reflectValue.Interface()) |