在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:gendry开源软件地址:https://gitee.com/didiopensource/gendry开源软件介绍:Gendrygendry is a Go library that helps you operate database. Based on The name gendry comes from the role in the hottest drama gendry consists of three isolated parts, and you can use each one of them partially: TranslationManagermanager is used for initializing database connection pool(i.e 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 the format of a [username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN] manager is based on Builderbuilder 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, 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 more detail, see builder's doc or just use ScannerFor 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 librarytype 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 scannertype 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 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 ScanMaprows, _ := 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 For more detail, see scanner's doc PS:
ToolsBesides APIs above, Gendry provide a [CLI tool](https://github.com/caibirdme/gforge) to help generating codes. |
请发表评论