How to remove duplicated code in Go with Gorm

463 Views Asked by At

I am using gorm package as my database library in golang. I have many database tables like "Hosts" or "Orders". In my CRUD App every Controller has the function setHost / setOrder ....

I can write this set function for each controller. But better way would be to have just a single function, 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. 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 the set function. Is it possible to have this implemented, or should I rather repeat my code?

type Host struct {
  gorm.Model
  name string
}

type Order struct {
  gorm.Model
  RoomSize int
}

func setOrder(c *gin.Context) (order models.Order) {
  db := dbpkg.DBInstance(c)
  id := new(ApplicationController).extractID(c)

  db.First(&order, id)

  if order.ID != id {
    log.Panicf("No Object with the ID: %d", id)
  }
  return
}

func setHost(c *gin.Context) (host models.Host) {
    db := dbpkg.DBInstance(c)
    id := new(ApplicationController).extractID(c)

    db.First(&host, id)

    if host.ID != id {
        log.Panicf("No Object with the ID: %d", id)
    }

    return host
}

func (ctrl ApplicationController) extractID(c *gin.Context) uint64 {
    id, err := strconv.ParseUint(c.Params.ByName("id"), 10, 64)
    if err != nil {
        log.Panicf("ID: %s can not parse to an uint64", c.Params.ByName("id"))
    }
    return id
}
1

There are 1 best solutions below

0
On

Have your Controllers implement an interface that has your extractID function. Then implement that extractID for each of your controllers. Kind of like this example:

package main

import "fmt"

type IDInterface interface {
    ExtractString()
}

type OrderController struct {
    IDInterface
    OrderData string
}

type HostController struct {
    IDInterface
    HostData string
}

func (c OrderController) ExtractString() {
    fmt.Println("Data: " + c.OrderData)
}

func (c HostController) ExtractString() {
    fmt.Println("Data: " + c.HostData)
}

func main() {
    o := OrderController{OrderData: "I'm an order!"}
    h := HostController{HostData: "I'm a host!"}
    printData(o)
    printData(h)
}

func printData(inter IDInterface) {
    inter.ExtractString()
}

Note printData takes in an IDInterface, but in main I'm just passing the controller.