preload.go 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package rest_gorm
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strings"
  6. "git.ali33.ru/fcg-xvii/rest"
  7. "gorm.io/gorm"
  8. )
  9. func Preload(obj any, fields rest.FieldList, q *gorm.DB) (*gorm.DB, error) {
  10. return preloadPrefix(obj, fields, q, "")
  11. }
  12. func preloadPrefix(obj any, fields rest.FieldList, q *gorm.DB, prefix string) (*gorm.DB, error) {
  13. val := reflect.ValueOf(obj)
  14. names, err := namesExt(val)
  15. if err != nil {
  16. return nil, err
  17. }
  18. for _, name := range names {
  19. if f, check := fields.Field(name.eName); check {
  20. q = q.Preload(prefix + name.eName)
  21. if f.IsObject() {
  22. if q, err = preloadPrefix(name.eValue, f.Names, q, prefix+name.eName+"."); err != nil {
  23. return nil, err
  24. }
  25. }
  26. }
  27. }
  28. return q, nil
  29. }
  30. type eExtName struct {
  31. eName string
  32. eValue any
  33. }
  34. func fElemType(t reflect.Type) reflect.Type {
  35. switch t.Kind() {
  36. case reflect.Ptr, reflect.Interface, reflect.Slice:
  37. return fElemType(t.Elem())
  38. }
  39. return t
  40. }
  41. func namesExt(val reflect.Value) (res []eExtName, err error) {
  42. k := val.Kind()
  43. switch k {
  44. case reflect.Ptr, reflect.Interface, reflect.Slice:
  45. return namesExt(val.Elem())
  46. }
  47. if k != reflect.Struct {
  48. return nil, fmt.Errorf("type [ %v ] is not a struct", k)
  49. }
  50. t := reflect.TypeOf(val.Interface())
  51. for i := 0; i < t.NumField(); i++ {
  52. fType := t.Field(i)
  53. tag := fType.Tag.Get("rest")
  54. if len(tag) > 0 && strings.Contains(tag, "ext") {
  55. rVal := reflect.New(fElemType(fType.Type))
  56. res = append(
  57. res,
  58. eExtName{
  59. eName: fType.Name,
  60. eValue: rVal.Interface(),
  61. },
  62. )
  63. }
  64. }
  65. return
  66. }