Can't define receiver from another package in Go

Issue

I’m a beginner in Golang and can’t understand some concepts in this language. I like it very much, but every examples on the web are very simple and not explain the correct way of developing.
I want to configure db connection with MySQL. I create a package dbconfig with file dbconfig.go and package dastructure with interfaces files and another package entity with entities files.
This is the structure:
[1]

main.go:

import (
    y "github.com/danyalov/shebeke/dbconfig"
    "github.com/danyalov/shebeke/routes"
    _ "github.com/go-sql-driver/mysql"
    "github.com/labstack/gommon/log"
)

func main() {
    db, err := y.InitDB("mysql", "root:root@tcp(localhost:3306)/dbtest?parseTime=true")
    if err != nil {
        log.Fatal(err)
    }
    e := routes.NewConnection(db)
    e.Logger.Fatal(e.Start(":9898"))
}

routes.go:

import (
    "github.com/danyalov/shebeke/datastructure"
    y "github.com/danyalov/shebeke/dbconfig"
    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
)

func NewConnection(db *y.DB) *echo.Echo {
    e := echo.New()
    env := Env{db}
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())

    e.GET("/contracts", env.GetContracts)
    e.GET("/contract/:id", env.GetContractByID)

    return e
}

type Env struct {
    contract datastructure.Contract
}

services.go:

import (
    "github.com/labstack/echo"
    "log"
    "net/http"
    "strconv"
)

func (env *Env) GetContracts(c echo.Context) error {
    contracts, err := env.contract.GetContracts()
    if err != nil {
        log.Fatal(err)
    }
    return c.JSON(http.StatusOK, &contracts)
}

dbconfig.go:

import (
    "database/sql"
    "fmt"
    "github.com/labstack/gommon/log"
)

type DB struct {
    *sql.DB
}

//InitDB initialize mysql database
func InitDB(driver, path string) (*DB, error) {
    db, err := sql.Open(driver, path)
    if err != nil {
        log.Fatal(err)
    }
    err = db.Ping()
    if err != nil {
        log.Fatal(err)
    } else {
        fmt.Println("Connected to DB")
    }
    return &DB{db}, err
}

datastructure/contract.go:

import y "github.com/danyalov/shebeke/datastructure/entity"

type Contract interface {
    GetContracts() (y.Contracts, error)
    GetContractByID(id int) (y.Contract, error)
}

datastructure/entity/contract.go:

import (
    "github.com/labstack/gommon/log"
    "time"
)

type Contract struct {
    ID         int       `json:"id"`
    State      string    `json:"state"`
    StartDate  time.Time `json:"start_date"`
    FinishDate time.Time `json:"finish_date"`
}

type Contracts []Contract

func (db *DB) GetContracts() (c Contracts, err error) {
    rows, err := db.Query("select * from contract")
    if err != nil {
        log.Fatal(err)
    }

    contract := Contract{}
    for rows.Next() {
        err = rows.Scan(&contract.ID, &contract.State, &contract.StartDate, &contract.FinishDate)
        c = append(c, contract)
    }
    return c, err
}

Why can’t I import DB type from dbconfig package into entity package as a method receiver? I get Unresolved type 'DB' error.

This is my working copy(Git) of this project, I put dbconfig.go inside the entity, but I don’t like it, I think it’s incorrect place for dbconfig file.

What is the correct file structure for configuring db in Go? Maybe you have your own examples in Git or some tutorial?

Solution

You can only define methods on a type defined in that same package. Your DB type, in this case, is defined within your dbconfig package, so your entity package can’t define methods on it.

In this case, your options are to make GetContracts a function instead of a method and hand it the *dbconfig.DB as an argument, or to invert the dependency by importing your entity package in dbconfig and write GetContracts there (as a method or function, works either way). This second one may actually be the better option, because, from a design perspective, it breaks abstraction to have packages other than your database package creating SQL query strings.

Answered By – Kaedys

Answer Checked By – Robin (GoLangFix Admin)

Leave a Reply

Your email address will not be published.