0

I am using gorm package (https://github.com/jinzhu/gorm) as my database library in golang. I have many classes (database tables) like "Hotel" or "Package". Duplicating code is not good programming practice. As a silly example - lets assume I want to get first object from each table. I can write this method (GetFirstHotel, GetFirstPackage...) for each object. But better way would be to have just a single method GetFirstItem, where I would use first param to create object with same class as parameter, then pass it to gorm, which will fill it with data from database, then return it as interface{}. I tried to use reflect for that, but failed, because I probably don't understand it much.

Maybe I just didn't discover some function in gorm library, or I can't use reflect package properly. How should I implement GetFirstItem function. Is it possible to have this implemented, or should I rather repeat my code?

package main

import (
    "github.com/jinzhu/gorm"
)

var db gorm.DB

type Hotel struct {
    ID   int64
    Name string
    Lat  float64
    Lon  float64
}

type Package struct {
    ID   int64
    Name string
    Text string
}

func GetFirstHotel() (hotel Hotel) {
    db.First(&hotel)
}

func GetFirstPackage() (pack Package) {
    db.First(&pack)
}

func main() {
    var firstHotel, firstPackage interface{}

    //first method
    firstHotel = GetFirstHotel()
    firstPackage = GetFirstPackage()

    //method i want to use
    firstHotel = GetFirstItem(Hotel{})
    firstPackage = GetFirstItem(Package{})
}

func GetFirstItem(item interface{}) interface{} {
    //how to implement this?
    //probably with some use of reflect package
}
Ondra
  • 3,100
  • 5
  • 37
  • 44

1 Answers1

2

The db.First method returns db reference and hydrates the row into the passed structure.

The closest to your desired method is

func GetFirstItem(item interface{}) error {
    return db.First(item).Error
}

This simply requires you keep a reference to the parameter

var firstHotel &Hotel{}
err := GetFirstItem(firstHotel)

Returning the hydrated object for all types would required type parameters (generics). I think you'll find the current situation is workable within limits.

see also: Why no generics in Go?

Community
  • 1
  • 1
foo
  • 701
  • 4
  • 8