How do I use a TypeConverter in Gorp?

huangapple go评论95阅读模式
英文:

How do I use a TypeConverter in Gorp?

问题

我想使用Gorp从数据库中加载和保存包含特殊类型的结构体。其中之一是用于枚举字符串(如角色):

type Role string

type Account struct {
    User string
    Role Role
}

这在“开箱即用”情况下无法正常工作。会引发错误消息,例如:

panic: sql: converting Exec argument #0's type: unsupported type user.Role, a string

我怀疑我需要使用gorp.TypeConverter来解决这个问题,但是没有关于如何做到这一点的文档。

你能帮忙吗?

英文:

I would like to use Gorp to load and save structs from the DB that contain specialised types. Amongst other things, this is useful for enumerated strings such as roles:

type Role string

type Account struct {
    User string
    Role Role
}

This doesn't work "out of the box". An error message is raised such as

panic: sql: converting Exec argument #0's type: unsupported type user.Role, a string

I suspect I need to use a gorp.TypeConverter to solve this, but there is no documentation on how to do this.

Can you help?

答案1

得分: 2

ValuerScanner接口可以实现你想要的功能。以下是一个可工作的示例:

package roleGorp

import (
	"gopkg.in/gorp.v1"
	"github.com/DATA-DOG/go-sqlmock"
	"fmt"
	"testing"
	"database/sql/driver"
)

type Role string

func (r *Role) Scan(value interface{}) error { *r = Role(value.(string)); return nil }
func (r Role) Value() (driver.Value, error)  { return string(r), nil }

type Account struct {
	User string `db:"user"`
	Role Role `db:"role"`
}

func TestRoleGorp(t *testing.T) {
	db, err := sqlmock.New()
	if err != nil {
		panic(err)
	}
	dbMap := gorp.DbMap{
		Db: db,
		Dialect: gorp.MySQLDialect{
			Engine: "InnoDB",
		},
	}

	rows := sqlmock.NewRows([]string{"user", "role"}).AddRow("user1", "admin")

	sqlmock.ExpectQuery(`SELECT * FROM account LIMIT 1`).WillReturnRows(rows)

	dbMap.AddTableWithName(Account{}, "account")

	result := &Account{}
	err = dbMap.SelectOne(result, "SELECT * FROM account LIMIT 1")
	if err != nil {
		panic(err)
	}

	fmt.Printf("%+v\n", *result)

	result2 := &Account{
		User: "user2",
		Role: Role("moderator"),
	}

	sqlmock.ExpectExec("insert into `account` (`user`,`role`) values (?,?);").WithArgs("user2", "moderator").WillReturnResult(sqlmock.NewResult(1, 1))

	err = dbMap.Insert(result2)
	if err != nil {
		panic(err)
	}
}
英文:

Valuer and Scanner interfaces will do what you want. Here is a working example :

package roleGorp
import (
"gopkg.in/gorp.v1"
"github.com/DATA-DOG/go-sqlmock"
"fmt"
"testing"
"database/sql/driver"
)
type Role string
func (r *Role) Scan(value interface{}) error { *r = Role(value.(string)); return nil }
func (r Role) Value() (driver.Value, error)  { return string(r), nil }
type Account struct {
User string `db:"user"`
Role Role `db:"role"`
}
func TestRoleGorp(t *testing.T) {
db, err := sqlmock.New()
if err != nil {
panic(err)
}
dbMap := gorp.DbMap{
Db: db,
Dialect: gorp.MySQLDialect{
Engine: "InnoDB",
},
}
rows := sqlmock.NewRows([]string{"user", "role"}).AddRow("user1", "admin")
sqlmock.ExpectQuery(`SELECT \* FROM account LIMIT 1`).WillReturnRows(rows)
dbMap.AddTableWithName(Account{}, "account")
result := &Account{}
err = dbMap.SelectOne(result, "SELECT * FROM account LIMIT 1")
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", *result)
result2 := &Account{
User: "user2",
Role: Role("moderator"),
}
sqlmock.ExpectExec("insert into `account` \\(`user`,`role`\\) values \\(\\?,\\?\\);").WithArgs("user2", "moderator").WillReturnResult(sqlmock.NewResult(1, 1))
err = dbMap.Insert(result2)
if err != nil {
panic(err)
}
}

huangapple
  • 本文由 发表于 2015年6月17日 19:31:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/30890315.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定