package rest_gorm import ( "fmt" "reflect" "strings" "git.ali33.ru/fcg-xvii/rest" "gorm.io/gorm" ) func Preload(obj any, fields rest.FieldList, q *gorm.DB) (*gorm.DB, error) { return preloadPrefix(obj, fields, q, "") } func preloadPrefix(obj any, fields rest.FieldList, q *gorm.DB, prefix string) (*gorm.DB, error) { val := reflect.ValueOf(obj) names, err := namesExt(val) if err != nil { return nil, err } for _, name := range names { if f, check := fields.Field(name.eName); check { q = q.Preload(prefix + name.eName) if f.IsObject() { if q, err = preloadPrefix(name.eValue, f.Names, q, prefix+name.eName+"."); err != nil { return nil, err } } } } return q, nil } type eExtName struct { eName string eValue any } func fElemType(t reflect.Type) reflect.Type { switch t.Kind() { case reflect.Ptr, reflect.Interface, reflect.Slice: return fElemType(t.Elem()) } return t } func namesExt(val reflect.Value) (res []eExtName, err error) { k := val.Kind() switch k { case reflect.Ptr, reflect.Interface, reflect.Slice: return namesExt(val.Elem()) } if k != reflect.Struct { return nil, fmt.Errorf("type [ %v ] is not a struct", k) } t := reflect.TypeOf(val.Interface()) for i := 0; i < t.NumField(); i++ { fType := t.Field(i) tag := fType.Tag.Get("rest") if len(tag) > 0 && strings.Contains(tag, "ext") { rVal := reflect.New(fElemType(fType.Type)) res = append( res, eExtName{ eName: fType.Name, eValue: rVal.Interface(), }, ) } } return }