I'm developping an API with lots of models using go-gorm. So far for the "GetAll" function, i've been using the following (simplified) :
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)
}
But I'd like to avoid copying/pasting the function to just modify the type (here models.User) to get all models from db.
I did try different approach using reflect or interface but none seems to work like :
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)
}
So I could use this directly in my handlers :
GenericGetAll(w,r,&models.User{}) for user
GenericGetAll(w,r,&models.Product{}) for Product
GenericGetAll(w,r,&models.Company{}) for Company
This would be cleaner than copying/pasting the other function just to modify the type ...
But using those different approach give problems :
How should I use reflect to get a slice from the type in argument of the function ?
Is this only doable with Golang ? I know that polymorphism doesn't exist in golang but ... this is a required features or is there something magic I don't know about golang ? ^^.
Thanks
I found the solution !!
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)
}
Instead of getting an interface of an Elem()
reflect.New(reflect.SliceOf(dtype)).Elem().Interface()
Which return []*models.User
The solution was to use directly an Interface :
pages := reflect.New(reflect.SliceOf(dtype)).Interface()
Which return *[]*models.User that is accepted by gorm's interface :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With