Как использовать тип отражения для gorm для обобщения функции API

Я разрабатываю API с большим количеством моделей, использующих go-gorm. До сих пор для функции "GetAll" я использовал следующее (упрощенное):

func GetAllUsers(w,r){
//... get params and do some check 
pages := []*models.User{} //<-main problem I have to give the full type 
models.GetDB().Model(&models.User{}).Offset(offset).Limit(pagesize).Find(&pages)
//do the http response(w,pages)
}

Но я бы хотел избежать копирования / вставки функции, чтобы просто изменить тип (здесь models.User), чтобы получить все модели из db.

Я пробовал другой подход с использованием отражения или интерфейса, но, похоже, ни один из них не работает так:

func GenericGetAll(w http.ResponseWriter, r *http.Request, data interface{}) {
    dtype := reflect.TypeOf(data)
    pages := reflect.New(reflect.SliceOf(dtype)).Elem().Interface()
    log.Printf("%+v", pages)
    //reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(data)), 0, 20)
    //new([]gorm.Model)
    GetDB().LogMode(true).Model(data).Offset(offset).Limit(pagesize).Find(&pages)

utils.Respond(w, pages)

}

Так что я мог бы использовать это прямо в своих обработчиках:

GenericGetAll(w,r,&models.User{}) for user
GenericGetAll(w,r,&models.Product{}) for Product
GenericGetAll(w,r,&models.Company{}) for Company

Это было бы чище, чем копирование / вставка другой функции только для изменения типа ...

Но использование этого другого подхода создает проблемы:

  • [] * interface {}, я теряю имя таблицы и получаю ошибку sql, потому что имя таблицы '' не существует
  • new ([] gorm.Model) он теряет мое имя таблицы и использует имя таблицы по умолчанию gorm.model: /
  • Reflect.New (lect.SliceOf (dtype)). Elem (). Interface (), и я получаю сообщение об ошибке: неподдерживаемый пункт назначения, должен быть срез или структура, даже если он действительно создал срез: / log.printf () дает пустой множество []

Как мне использовать отражение, чтобы получить фрагмент из аргумента типа в функции?

Это возможно только с Голангом? Я знаю, что полиморфизм не существует в голанге, но ... это обязательные функции или есть что-то волшебное, чего я не знаю о голанге? ^^.

Спасибо


person LZR    schedule 11.09.2019    source источник
comment
Рассматривали ли вы возможность передачи как экземпляра одного типа, так и экземпляра среза в общую функцию? Тогда вы сможете избежать использования рефлексии.   -  person mkopriva    schedule 11.09.2019
comment
golang.org/pkg/reflect/#MakeSlice, т.е. play.golang.org/p/p_hOGik5jqD   -  person mh-cbon    schedule 11.09.2019
comment
К сожалению, когда я использую: Reflect.MakeSlice (lect.SliceOf (Reflect.TypeOf (data)), 0, 20) .Interface (): - или я получаю: reflection.flag.mustBeAssignable с использованием неадресуемого значения - или это не рассматривается как фрагмент или интерфейс В зависимости от того, используется ли указатель или нет при вызове: GetDB (). LogMode (true) .Model (данные) .Offset (смещение) .Limit (размер страницы) .Find (pages) Если я использую [] interface { } в аргументе моей функции я не могу передать [] & models.User {}   -  person LZR    schedule 12.09.2019


Ответы (1)


Я нашел решение !!

func GenericGetAll(w http.ResponseWriter, r *http.Request, data interface{}) {
    dtype := reflect.TypeOf(data)
    pages := reflect.New(reflect.SliceOf(dtype)).Interface()
    offset, pagesize, order := GetAllFromDb(r)
    err := error(nil)
    if offset <= 0 && pagesize <= 0 {
        err = errors.New(order)
    }

    if order != "" {
        err = GetDB().LogMode(true).Model(data).Order(order).Offset(offset).Limit(pagesize).Find(pages).Error
    } else {
        err = GetDB().LogMode(true).Model(data).Offset(offset).Limit(pagesize).Find(pages).Error
    }
    if err != nil {
        utils.Respond(w, utils.Message(false, fmt.Sprintf("Error while retrieving data")))
        return
    }
    resp := utils.Message(true, "data returned")
    resp["data"] = pages
    utils.Respond(w, resp)

}

Вместо получения интерфейса Elem ()

reflect.New(reflect.SliceOf(dtype)).Elem().Interface()

Которые возвращают [] * models.User

Решением было использовать непосредственно интерфейс:

pages := reflect.New(reflect.SliceOf(dtype)).Interface()

Которые возвращают * [] * models.User, принятый интерфейсом gorm :)

person LZR    schedule 12.09.2019