2016-02-27 19 views
5

Gitmeye yeni başladık ve düğümde yazılı bir API sunucusunu yeniden uygulamak istiyorum.Git ve Cin: Veritabanı bağlamı için yapının etrafından mı geçiyorsun?

Gine katman yazılımı olarak bir veritabanı bağlamından geçmek için bağımlılık enjeksiyonu kullanmaya çalışırken bir engel yaşadım.

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") 
} 

modelleri/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 
} 

modeller/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 
     } 
} 

Şimdiye kadar bu gibi kurdum Yukarıdakilerin hepsiyle birlikte, models.DataSource'u bir ara katman yazılımı olarak geçmek istiyorum, bu nedenle şu şekilde erişilebilir:

/kamu public.go db sadece boş amacı, (eklentisi ile WebStorm kullanılarak) ayıklayıcısında incelemek zaman

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) 
} 

Ancak

public\public.go:10: db.GetVotePack undefined (type interface {} is interface with no methods) alır. İyi olmaya çalışıyorum ve global değişken kullanımından kaçınmaya çalışıyorum

cevap

6

değerleri tip interface{} tümü, bu yüzden db tip *DB gelen yöntemleri çağırmak mümkün olmayacaktır.

güvenli yolu:

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

Effective Go bu konuda bir bölüm vardır:

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

az güvenli yolu, context.Keys["DB"] eğer panik olur tip *DB bir değer değil.

+0

Mükemmel, bunu çözmek için görünüyordu. –

+0

Bu sorunu çözerken, bana çok kötü bir tasarım gibi görünüyor. Arabirim {} yapıları genel bir bağlamda koyarak birisine güvenmek, güçlü bir şekilde yazılan tasarıma benzemiyor. Ben hata çoğu çoğunu gin bir arabirim yerine tanıtıcı yöntemi için bir işlev bekler çünkü –

+0

@SnoProblem Bağlam üzerinden veritabanı bağlantısı geçmek için iyi bir yol mu? Başka bir yolu var mı? –

1

Arabirimi (db: = context.Keys ["DB"]) dönüştürmek için, kullanışlı bir şeye dönüştürmeniz gerekir. Örneğin bu yayını bakınız: geri bu tür geçirilmeleri kadar context.Keys içinde convert interface{} to int in Golang