2016-02-27 75 views
5

我刚开始尝试Go,我正在重新实现一个使用它编写节点的API服务器。Go和杜松子酒:传递数据库上下文的结构?

我试图使用依赖注入传递数据库上下文作为杜松子酒中间件时遇到了障碍。到目前为止,我已经将它设置成这样:

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 CPUs\n", 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") 
} 

型号/ db.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 
     } 
} 

因此,对于上述所有内容,我想将models.DataSource作为中间件传递,以便可以像这样访问它:

公共/ 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) 
} 

但是我得到public\public.go:10: db.GetVotePack undefined (type interface {} is interface with no methods)

当我在调试器中检查(使用Webstorm与插件)的数据库是一个空的对象。我试图做的很好,并避免全局变量使用

回答

6

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 

Effective Go对这个部分。

+0

完美,这似乎解决了它。 –

+0

虽然这解决了这个问题,但它看起来对我来说设计非常糟糕。依赖于将接口{}结构放在通用上下文中的人看起来不像正确的强类型设计。我想大多数的错误是因为杜松子酒预期的处理方法,而不是一个接口函数 –

+0

@SnoProblem它是通过上下文传递数据库连接的好方法吗?有没有其他方法&? –

相关问题