• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

gendry: Gendry是一个用于辅助操作数据库的Go包。基于go-sql-driver/mysql,它提供了 ...

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称:

gendry

开源软件地址:

https://gitee.com/didiopensource/gendry

开源软件介绍:

Gendry

Build StatusGitterHex.pmGoDoc

gendry is a Go library that helps you operate database. Based on go-sql-driver/mysql, it provides a series of simple but useful tools to prepare parameters for calling methods in standard library database/sql.

The name gendry comes from the role in the hottest drama The Game of Throne, in which Gendry is not only the bastardy of the late king Robert Baratheon but also a skilled blacksmith. Like the one in drama, this library also forge something which is called SQL.

gendry consists of three isolated parts, and you can use each one of them partially:

Translation

Manager

manager is used for initializing database connection pool(i.e sql.DB),you can set almost all parameters for those mysql driver supported.For example, initializing a database connection pool:

var db *sql.DBvar err errordb, err = manager		.New(dbName, user, password, host)		.Set(			manager.SetCharset("utf8"),			manager.SetAllowCleartextPasswords(true),			manager.SetInterpolateParams(true),			manager.SetTimeout(1 * time.Second),			manager.SetReadTimeout(1 * time.Second)		).Port(3302).Open(true)

In fact, all things manager does is just for concatting the dataSourceName

the format of a dataSourceName is:

[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]

manager is based on go-mysql-driver/mysql, and if you don't know some of the manager.SetXXX series functions, see it on mysql driver's github home page.And for more details see manager's doc

Builder

builder as its name says, is for building sql.Writing sql manually is intuitive but somewhat difficult to maintain.And for `where in`, if you have huge amount of elements in the `in` set, it's very hard to write.

builder isn't an ORM, in fact one of the most important reasons we create Gendry is we don't like ORM. So Gendry just provides some simple APIs to help you building sqls:

where := map[string]interface{}{	"city in": []string{"beijing", "shanghai"},	"score": 5,	"age >": 35,	"address": builder.IsNotNull,	"_orderby": "bonus desc",	"_groupby": "department",}table := "some_table"selectFields := []string{"name", "age", "sex"}cond, values, err := builder.BuildSelect(table, where, selectFields)//cond = SELECT name, age, sex FROM some_table WHERE (score=? AND city IN (?, ?) AND age>? AND address IS NOT NULL) GROUP BY department ORDER BY bonus DESC//values = []interface{}{"beijing", "shanghai", 5, 35}rows, err := db.Query(cond, values...)

And, the library provide a useful API for executing aggregate queries like count, sum, max, min, avg

where := map[string]interface{}{    "score > ": 100,    "city in": []interface{}{"Beijing", "Shijiazhuang", }}// AggregateSum, AggregateMax, AggregateMin, AggregateCount, AggregateAvg are supportedresult, err := AggregateQuery(ctx, db, "tableName", where, AggregateSum("age"))sumAge := result.Int64()result, err = AggregateQuery(ctx, db, "tableName", where, AggregateCount("*")) numberOfRecords := result.Int64()result, err = AggregateQuery(ctx, db, "tableName", where, AggregateAvg("score"))averageScore := result.Float64()

For complex queries, NamedQuery may be helpful:

cond, vals, err := builder.NamedQuery("select * from tb where name={{name}} and id in (select uid from anothertable where score in {{m_score}})", map[string]interface{}{	"name": "caibirdme",	"m_score": []float64{3.0, 5.8, 7.9},})assert.Equal("select * from tb where name=? and id in (select uid from anothertable where score in (?,?,?))", cond)assert.Equal([]interface{}{"caibirdme", 3.0, 5.8, 7.9}, vals)

slice type can be expanded automatically according to its length, thus these sqls are very convenient for DBA to review.
For critical system, this is recommended

For more detail, see builder's doc or just use godoc

Scanner

For each response from mysql, you want to map it with your well-defined structure.Scanner provides a very easy API to do this, it's based on reflection:
standard library
type Person struct {	Name string	Age int}rows, err := db.Query("SELECT age as m_age, name from g_xxx where xxx")defer rows.Close()var students []Personfor rows.Next() {	var student Person	rows.Scan(student.Age, student.Name)	students = append(students, student)}
using scanner
type Person struct {	Name string `ddb:"name"`	Age int `ddb:"m_age"`}rows, err := db.Query("SELECT age as m_age, name from g_xxx where xxx")defer rows.Close()var students []Personscanner.Scan(rows, &students)

Types which implement the interface

type ByteUnmarshaler interface {	UnmarshalByte(data []byte) error}

will take over the corresponding unmarshal work.

type human struct {	Age   int       `ddb:"ag"`	Extra *extraInfo `ddb:"ext"`}type extraInfo struct {	Hobbies     []string `json:"hobbies"`	LuckyNumber int      `json:"ln"`}func (ext *extraInfo) UnmarshalByte(data []byte) error {	return json.Unmarshal(data, ext)}//if the type of ext column in a table is varchar(stored legal json string) or json(mysql5.7)var student humanerr := scanner.Scan(rows, &student)// ...

The extra tag of the struct will be used by scanner resolve data from response.The default tag name is ddb:"tagname", but you can specify your own such as:

scanner.SetTagName("json")type Person struct {	Name string `json:"name"`	Age int `json:"m_age"`}// ...var student Personscanner.Scan(rows, &student)

scanner.SetTagName is a global setting and it can be invoked only once

ScanMap

rows, _ := db.Query("select name, age as m_age from person")result, err := scanner.ScanMap(rows)for _, record := range result {	fmt.Println(record["name"], record["m_age"])}

ScanMap scans data from rows and returns a []map[string]interface{}
int, float, string type may be stored as []uint8 by mysql driver, ScanMap just copy those value into the map. If you're sure that there's no binary data type in your mysql table(in most cases, this is true), you can use ScanMapDecode instead which will convert []uint8 to int, float64 or string

For more detail, see scanner's doc

PS:

  • Don't forget close rows if you don't use ScanXXXClose
  • The second parameter of Scan must be a reference

Tools

Besides APIs above, Gendry provide a [CLI tool](https://github.com/caibirdme/gforge) to help generating codes.

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap