Go and Gin: передача структуры для контекста базы данных?

Я только начал пробовать Go, и я ищу, чтобы повторно реализовать сервер API, написанный в узле с ним.

я столкнулся с препятствием, пытаясь использовать инъекцию зависимостей для передачи контекста базы данных в качестве промежуточного программного обеспечения gin. До сих пор я настроил его так:

main.go:

package main

import (
        "fmt"
        "runtime"
        "log"
        "github.com/gin-gonic/gin"
        "votesforschools.com/api/public"
        "votesforschools.com/api/models"
)

type DB struct {
        models.DataStore
}

func main() {
        ConfigRuntime()
        ConfigServer()
}

func Database(connectionString string) gin.HandlerFunc {
        dbInstance, err := models.NewDB(connectionString)
        if err != nil {
                log.Panic(err)
        }

        db := &DB{dbInstance}

        return func(c *gin.Context) {
                c.Set("DB", db)
                c.Next()
        }
}


func ConfigRuntime() {
        nuCPU := runtime.NumCPU()
        runtime.GOMAXPROCS(nuCPU)
        fmt.Printf("Running with %d CPUsn", nuCPU)
}

func ConfigServer() {

        gin.SetMode(gin.ReleaseMode)

        router := gin.New()
        router.Use(Database("<connectionstring>"))
        router.GET("/public/current-vote-pack", public.GetCurrentVotePack)
        router.Run(":1000")
}

моделей/дБ.go

package models

import (
        "database/sql"
        _ "github.com/go-sql-driver/mysql"
)

type DataStore interface {
        GetVotePack(id string) (*VotePack, error)
}

type DB struct {
        *sql.DB
}

func NewDB(dataSource string) (*DB, error) {
        db, err := sql.Open("mysql", dataSource)
        if err != nil {
                return nil, err
        }
        if err = db.Ping(); err != nil {
                return nil, err
        }
        return &DB{db}, nil
}

модели / votepack.go

package models

import (
        "time"
        "database/sql"
)

type VotePack struct {
        id string
        question string
        description string
        startDate time.Time
        endDate time.Time
        thankYou string
        curriculum []string
}

func (db *DB) GetVotePack(id string) (*VotePack, error) {

        var votePack *VotePack

        err := db.QueryRow(
                "SELECT id, question, description, start_date AS startDate, end_date AS endDate, thank_you AS thankYou, curriculum WHERE id = ?", id).Scan(
                &votePack.id, &votePack.question, &votePack.description, &votePack.startDate, &votePack.endDate, &votePack.thankYou, &votePack.curriculum)

        switch {
        case err == sql.ErrNoRows:
                return nil, err
        case err != nil:
                return nil, err
         default:
                return votePack, nil
        }
}

Итак, со всем вышеперечисленным, я хочу передать модели.Источник в middleware, чтобы его можно было получить следующим образом:

public / public.go

package public

import (
        "github.com/gin-gonic/gin"
)

func GetCurrentVotePack(context *gin.Context) {
        db := context.Keys["DB"]

        votePack, err := db.GetVotePack("c5039ecd-e774-4c19-a2b9-600c2134784d")
        if err != nil{
                context.String(404, "Votepack Not Found")
        }
        context.JSON(200, votePack)
}
Я publicpublic.go:10: db.GetVotePack undefined (type interface {} is interface with no methods)

когда я проверяю в отладчике (с помощью Webstorm с плагином) БД-это просто пустой объект. Я пытаюсь быть хорошим и избегать использования глобальных переменных

2 ответов


значения в context.Keys все типа interface{}, Так что db не сможет вызывать методы типа *DB пока он не будет преобразован обратно в этот тип.

безопасный путь:

db, ok := context.Keys["DB"].(*DB)
if !ok {
        //Handle case of no *DB instance
}
// db is now a *DB value

менее безопасный способ, который будет паники, если context.Keys["DB"] не является значением типа *DB:

db := context.Keys["DB"].(*DB)
// db is now a *DB value

Эффективный Go есть раздел об этом.


вам понадобится утверждение типа для преобразования интерфейса (db: = context.Ключи ["DB"]) во что-то полезное. См., например, этот пост:преобразовать интерфейс{} в int в Golang