Go 优雅的 SQL 语句拼接库
自己的需求很明确,不是 ORM 组件,只需一个动态拼接 SQL 语句和参数,不影响实体结构体的定义,最后支持导出 SQL 语句和参数组,这就是一个我心里理想的 SQL 拼接库,自己打算写一个的时候,发现 github 上已经有了,而且比我理想中还要完美和轻量。
sqrl https://github.com/elgris/sqrl 的介绍如:Fluent SQL generation for golang,很符合 Go 的理念。仔细参详了,发现它是 forked 于 https://github.com/Masterminds/squirrel 的,两项目是父子关系,区别在于线程安全和非线程安全。
根据 sqrl 作者的介绍,SQL 拼接库,一般线程安全并不是完全有必要的,所以适当简化提升了 squirrel,构造出一个非线程安全的 squirrel ,并增加了一些有用的属性,最后出来了 sqrl。我最后也是选择了 sqrl 作为研究对象。
查询语句生成如:
import sq "github.com/elgris/sqrl"
users := sq.Select("*").From("users").Join("emails USING (email_id)")
active := users.Where(sq.Eq{"deleted_at": nil}).
Where("sex=?",1).
Where(sq.Eq{"status":1}).
Where(sq.Eq{"username": []string{"moe", "larry", "curly", "shemp"}}).Offset(0).Limit(10)
query, args, err := active.ToSql()
用对象的方式拼接 SQL 语句,出来的结果:
query == "SELECT * FROM users JOIN emails USING (email_id) WHERE deleted_at IS NULL AND sex=? AND status=? AND username in (?,?,?,?) offset 0 limit 10"
args == [1,1,"moe", "larry", "curly", "shemp",0,10]
这是大体的查询语句的使用,动态 where 语句非常灵活。
如果配合 sqlx 使用如下:
list := []model.User{}
err := db.Select(&list,query,args...)
天生完美配合,两者又非常独立。
插入语句生成如:
query, args, err := sq.
Insert("users").Columns("name", "age").
Values("moe", 13).Values("larry", sq.Expr("? + 5", 12)).
ToSql()
生成 SQL 的语句
query == "INSERT INTO users (name,age) VALUES (?,?),(?,? + 5)"
args == ["moe", 13],["larry", 12]
更新语句生成如:
query, args, err := sq.Update("users").
SetMap(sq.Eq{"status": 1, "sex": 1, "updated": time.Now()}).
Set("name", "Jack").
Where("id=?", 1)
生成 SQL 的语句
query == "UPDATE users SET status=?,sex=?,updated=? where id=?"
args == [1,1,"2018-01-01 12:12:11","Jack", 13]
删除语句生成如:
query, args, err := sq.Delete("users").Where("id=?", 1)
生成 SQL 的语句
query == "DELETE users where id=?"
args == [1]
sqrl 对 mysql 做了一些针对性的函数,删除多张表:
sql, args, err := sq.Delete("a1", "a2").
From("z1 AS a1").
JoinClause("INNER JOIN a2 ON a1.id = a2.ref_id").
Where("b = ?", 1).
ToSql()
以上语句是关联删除两张表。
MySQL 是全球最流行的开源关系型数据库,以上的语句生成很明显都是只适应 MySQL 的,但 PostgreSQL 同样是全球最高级的开源关系型数据库,也不容小觑,sqrl 对 PostgreSQL 支持也很友好,比如它们的占位符一个是 ?,一个是$, 我们只需要在原来的 builder 基础上,指定占位符即可,比如:
sq.Select("*").From("users").Where("id=?",1).PlaceholderFormat(sq.Dollar)
同样 Insert Update Delete builder 的使用上 .PlaceholderFormat(sq.Dollar) 同样适用,只需要在一处指定占位符即可,可以搞定占位符$1....$n,顺序带来的困扰。
另外 sqrl 还针对做了一些特殊的函数,适应 PostgreSQL ,比如:json值,数组值的支持:
sql, args, err := sq.Insert("posts").
Columns("content", "tags").
Values("Lorem Ipsum", pg.JSONB([]string{"foo", "bar"})).
ToSql()
sql, args, err := sqrl.Insert("posts").
Columns("content", "tags").
Values("Lorem Ipsum", pg.Array([]string{"foo", "bar"})).
ToSql()
sqrl 原本就是 SQL 生成语句,对数据库层的操作几乎是绝缘的,不要想象她是一个 ORM 组件库,它绝大部分工作只是根据数据库的特征,处理和生成字符串而已。不过也不是和操作数据库绝缘,有一个特殊模块是可以操作数据的,我们可以看看代码使用情况:
stooges := users.Where(sq.Eq{"username": []string{"moe", "larry", "curly", "shemp"}})
three_stooges := stooges.Limit(3)
rows, err := three_stooges.RunWith(db).Query()
实际上以上代码就是完成以下操作:
rows, err := db.Query("SELECT * FROM users WHERE username IN (?,?,?,?) LIMIT 3", "moe", "larry", "curly", "shemp")
我想这个模块,不是很必要的,只是给用户多了一个选择。个人觉得数据库操作上 sqlx 更为专业些,如果你非要图方便使用 sqrl 的数据操作,也无可厚非,选择适合场景的来用。
(完)
哇~~~ 竟然还没有评论!