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