使用单独的数据库类和单独的模型和服务包 [英] Using a singleton database class with separate models and services packages
问题描述
我的问题类似于如何创建单例DB类在GoLang 中,但是我无法使它与单独的模型和服务包一起工作。
project / lib / database / mysql.go:>
包数据库
导入(
fmt
_ github.com/go-sql-driver/mysql
github.com/jinzhu/gorm
)
类型经理struct {
* gorm。 DB
var Mgr * Manager
func init(){
dsn:= MysqlConnectionString(parseTime = true)
tablePrefix:=demo
var err error
gorm.DefaultTableNameHandler = func(db * gorm.DB,defaultTableName string)string {
return fmt.Sprintf(%v_ %v,tablePrefix,defaultTableName)
}
db,err:= gorm.Open(mysql,dsn)
if err!= nil {
恐慌(错误)
}
Mgr =& Manager {db}
}
project / lib / models / retailer_keys.go
包装模型
导入(
fmt
project / lib / database
time
)
类型RetailerKeysInterface接口{
RetailerKeys()([] * RetailerKey ,错误)
}
类型DB结构{
database.Manager
}
类型RetailerKey结构{
Id int `json:id`
RetailerId int`json:retailer_id`
键字符串`json:key`
启用* bool`json:enabled`
CreatedAt * time.Time`json:created_at`
UpdatedAt * time.Time`json:updated_at`
}
func(db * DB)RetailerKeys( )([] * RetailerKey,错误){
var key [] * RetailerKey
if err:= db.Find(& keys).Error; err!= nil {
return nil,err
}
return key,nil
}
项目/ lib / services / retailer_keys.go
导入(
fmt
字符串
github.com/aws/aws-sdk-go/aws
github.com/aws/aws-sdk-go/aws / session
github.com/aws/aws-sdk-go/service/apigateway
gopkg.in/volatiletech/null.v6
项目/ lib / models
project / lib / services / api_keys
)
func GetKeys()([] * models.RetailerKey,error){
var q models.RetailerKeysInterface
keys,err:= q.RetailerKeys()
if err!= nil {
return nil,err
}
return键,零
}
func CreateKey(id int)(models.RetailerKey,error){
...
}
$ b然后可以在我的主包中使用它:
包主
导入(
上下文
encoding / json
//反映
fmt
github.com/aws/aws-lambda-go/events
github .com / aws / aws-lambda-go / lambda
_project / lib / config
project / lib / services
)
func Handler(ctx context.Context,request events.APIGatewayProxyRequest)(events.APIGatewayProxyResponse,error){
statusCode:= 200
keys,err:= services.GetKeys()
if err!= nil {
statusCode = 400
}
body,_:= json.Marshal(键)
返回events.APIGatewayProxyResponse {
Body:string(body),
StatusCode:statusCode,
},nil
}
...
$ c
$ b我希望能够在我的模型中嵌入Manager类型的相关子集。
编辑:
根据评论中的反馈编辑问题/代码。
这给我一个错误:
运行时错误:无效的内存地址或零指针解引用
。解决方案我绝对误解了界面。经过A Tour of Go之后,它开始变得更加清晰,它是如何融合在一起的。
这是我最终为所有经历过同样事情的人做的。
project / lib / database / mysql.go:
包数据库
导入(
fmt
log
_ github.com/go-sql-driver/mysql//需要gorm
github.com/jinzhu/gorm
)
var Manager * gorm.DB
func init(){
var err error
$ b dsn:= MysqlConnectionString(parseTime = true)
tablePrefix:=qcommerce
gorm.DefaultTableNameHandler = func(db * gorm.DB,defaultTableName string)string {
return fmt.Sprintf(%v_%v,tablePrefix,defaultTableName)
}
经理,err = gorm.Open(mysql,dsn)
if err!= nil {
log.Fatal(err)
}
if err:= Manager.DB().Ping(); err!= nil {
log.Fatal(err)
}
}
project / lib / models / retailer_keys.go
包模型
导入(
project / lib / database
time
)
类型QRetailerKeys接口{
Insert()错误
Find()错误
}
$ b $类型RetailerKey结构{
ID int`json:id`
RetailerID int`json:retailer_id`
零售商零售商` json:retailer
键字符串`json:键
启用bool`json:启用gorm:DEFAULT:true`
CreatedAt * time.Time`json :created_at`
UpdatedAt * time.Time`json:updated_at`
}
// RetailerKeys返回表中所有键的切片
func RetailerKeys()([] * RetailerKey,error){
var keys [] * RetailerKey
if err:= database.Manager.Find(&键).Error; err!= nil {
return nil,err
}
return key,nil
}
func(r * RetailerKey)Find()error {
...
}
//创建一个新键
func(r * RetailerKey)Create()错误{
return database.Manager。创建(& r).Error
}
project / lib / services / retailer_keys。 go
包服务
导入(
github.com/aws/aws- sdk-go / aws
github.com/aws/aws-sdk-go/aws/session
//github.com/aws/aws-sdk-go/service/apigateway
partners.drinks.com/lib/models
partners.drinks.com/lib/services/api_keys
)
func sessionBuilder()* session.Session {
config:=& aws.Config {
Region:aws.String(us-west-2),
}
session := session.Must(session.NewSession(config))
return session
}
func GetKeys()([] * models.RetailerKey,error){
键,err:= models.RetailerKeys()
if err!= nil {
return nil,err
}
返回键,零
}
func CreateKey(id int)(models.RetailerKey,error){
apikeys:=& api_keys.ApiKeyBuilder {}
base64Key:= apikeys.GenUUID().GenKey()。Base64
var key = models.RetailerKey {
RetailerID:id,
Key:base64Key,
启用:func(b bool)
}
如果err:= key.Create(); err!= nil {
return models.RetailerKey {},err
}
...
返回键,零
}
我使用它:
package main
import(
context
encoding / json
github.com/aws/aws-lambda -go / events
github.com/aws/aws-lambda-go/lambda
_partners.drinks.com/lib/config
合作伙伴.drinks.com / lib / services
)
func Handler(ctx context.Context,request events.APIGatewayProxyRequest)(events.APIGatewayProxyResponse,error){
statusCode:= 200
key,err:= services.GetKeys()
if err!= nil {
statusCode = 400
}
body ,_:= json.Marshal(键)
返回events.APIGatewayProxyResponse {
正文:string(body),
StatusCode:statusCode,
},nil
}
...
感谢@m kopriva为注释中的链接资源。
My question is similar to How to create singleton DB class in GoLang but I'm having trouble getting it to work with separate models and services packages.
project/lib/database/mysql.go:
package database import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jinzhu/gorm" ) type Manager struct { *gorm.DB } var Mgr *Manager func init() { dsn := MysqlConnectionString("parseTime=true") tablePrefix := "demo" var err error gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string { return fmt.Sprintf("%v_%v", tablePrefix, defaultTableName) } db, err := gorm.Open("mysql", dsn) if err != nil { panic(err) } Mgr = &Manager{db} }
project/lib/models/retailer_keys.go
package models import ( "fmt" "project/lib/database" "time" ) type RetailerKeysInterface interface { RetailerKeys() ([]*RetailerKey, error) } type DB struct { database.Manager } type RetailerKey struct { Id int `json:"id"` RetailerId int `json:"retailer_id"` Key string `json:"key"` Enabled *bool `json:"enabled"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` } func (db *DB) RetailerKeys() ([]*RetailerKey, error) { var keys []*RetailerKey if err := db.Find(&keys).Error; err != nil { return nil, err } return keys, nil }
project/lib/services/retailer_keys.go
import ( "fmt" "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/apigateway" "gopkg.in/volatiletech/null.v6" "project/lib/models" "project/lib/services/api_keys" ) func GetKeys() ([]*models.RetailerKey, error) { var q models.RetailerKeysInterface keys, err := q.RetailerKeys() if err != nil { return nil, err } return keys, nil } func CreateKey(id int) (models.RetailerKey, error) { ... }
Then be able to use it in my main package like:
package main import ( "context" "encoding/json" // "reflect" "fmt" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" _ "project/lib/config" "project/lib/services" ) func Handler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { statusCode := 200 keys, err := services.GetKeys() if err != nil { statusCode = 400 } body, _ := json.Marshal(keys) return events.APIGatewayProxyResponse{ Body: string(body), StatusCode: statusCode, }, nil } ...
I'd like to be able to embed the relevant subset of the Manager type in my models.
EDIT: Edited the question/code based on feedback in comments.
This gives me an error:
runtime error: invalid memory address or nil pointer dereference
.解决方案I was definitely misunderstanding interfaces in go. After going through A Tour of Go it started to become clearer how it all fits together.
This is that I ended up doing for anyone that is going through the same thing. I'll leave the original question up so you can see the differences.
project/lib/database/mysql.go:
package database import ( "fmt" "log" _ "github.com/go-sql-driver/mysql" // Needed for gorm "github.com/jinzhu/gorm" ) var Manager *gorm.DB func init() { var err error dsn := MysqlConnectionString("parseTime=true") tablePrefix := "qcommerce" gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string { return fmt.Sprintf("%v_%v", tablePrefix, defaultTableName) } Manager, err = gorm.Open("mysql", dsn) if err != nil { log.Fatal(err) } if err := Manager.DB().Ping(); err != nil { log.Fatal(err) } }
project/lib/models/retailer_keys.go
package models import ( "project/lib/database" "time" ) type QRetailerKeys interface { Insert() error Find() error } type RetailerKey struct { ID int `json:"id"` RetailerID int `json:"retailer_id"` Retailer Retailer `json:"retailer"` Key string `json:"key"` Enabled bool `json:"enabled" gorm:"DEFAULT:true"` CreatedAt *time.Time `json:"created_at"` UpdatedAt *time.Time `json:"updated_at"` } // RetailerKeys returns a slice of all keys in table func RetailerKeys() ([]*RetailerKey, error) { var keys []*RetailerKey if err := database.Manager.Find(&keys).Error; err != nil { return nil, err } return keys, nil } func (r *RetailerKey) Find() error { ... } // Create a new key func (r *RetailerKey) Create() error { return database.Manager.Create(&r).Error }
project/lib/services/retailer_keys.go
package services import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" // "github.com/aws/aws-sdk-go/service/apigateway" "partners.drinks.com/lib/models" "partners.drinks.com/lib/services/api_keys" ) func sessionBuilder() *session.Session { config := &aws.Config{ Region: aws.String("us-west-2"), } session := session.Must(session.NewSession(config)) return session } func GetKeys() ([]*models.RetailerKey, error) { keys, err := models.RetailerKeys() if err != nil { return nil, err } return keys, nil } func CreateKey(id int) (models.RetailerKey, error) { apikeys := &api_keys.ApiKeyBuilder{} base64Key := apikeys.GenUUID().GenKey().Base64 var key = models.RetailerKey{ RetailerID: id, Key: base64Key, Enabled: func(b bool) } if err := key.Create(); err != nil { return models.RetailerKey{}, err } ... return key, nil }
I use it like:
package main import ( "context" "encoding/json" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" _ "partners.drinks.com/lib/config" "partners.drinks.com/lib/services" ) func Handler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { statusCode := 200 keys, err := services.GetKeys() if err != nil { statusCode = 400 } body, _ := json.Marshal(keys) return events.APIGatewayProxyResponse{ Body: string(body), StatusCode: statusCode, }, nil } ...
Thanks to @mkopriva for the linked resources in the comments.
这篇关于使用单独的数据库类和单独的模型和服务包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!