borm final
序
风和日丽,这次也有日子没写博客了。
主要原因吧,就是因为 ↓↓↓
上次整个搞定数据迭代之后,我就知道,是时候整合一下所有我们写好的功能了。
毕竟写了这么多,咋样也得出个1.0可用版不是?
接口封装
这部分,我们除了基础的sql操作之外,还要整合进去我们sqlbuilder的功能
所以定义了如下接口
BormExecutor interface {
Exec() (sql.Result, error)
}
Updater interface {
BormExecutor
Set(key string, value interface{}) Updater
Where(sql string, value ...interface{}) Updater
And(sql string, value ...interface{}) Updater
Or(sql string, value ...interface{}) Updater
}
Deleter interface {
BormExecutor
Where(sql string, value ...interface{}) Deleter
And(sql string, value ...interface{}) Deleter
Or(sql string, value ...interface{}) Deleter
}
Inserter interface {
BormExecutor
Values(interface{}) Inserter
}
Selector interface {
iterator.Iterator
Where(sql string, value ...interface{}) Selector
AutoWhere(i interface{}) Selector
And(sql string, value ...interface{}) Selector
Or(sql string, value ...interface{}) Selector
From(tableName string) Selector
Select(...string) Selector
OrderBy(string) Selector
GroupBy(string) Selector
Limit(int64) Selector
Offset(int64) Selector
}
然后抽象一下数据库相关的操作,开放出来对外的基础接口
SqlExecutor interface {
Exec(sql string, args ...interface{}) (sql.Result, error)
Query(sql string, args ...interface{}) (*sql.Rows, error)
QueryRow(sql string, args ...interface{}) *sql.Row
}
Executor interface {
SqlExecutor
InsertInto(t string) Inserter
AutoInsert(t interface{}) (sql.Result, error)
UpdateFrom(tableName string) Updater
AutoUpdate(i interface{}) (sql.Result, error)
DeleteFrom(tableName string) Deleter
AutoDelete(i interface{}) (sql.Result, error)
Select(...string) Selector
SelectFrom(string) Selector
Count(i interface{}) (int64, error)
}
DataBase interface {
Executor
SetMaxOpenConns(n int)
Close() error
Begin() (Tx, error)
}
Tx interface {
Executor
Comment() error
RollBack() error
}
最终,我们再加入一个 sql驱动接口
Connector interface {
DriverName() string
ConnStr() string
GetPoolSize() int
}
这里我们的基础接口定义基本上就完成了
接口实现
从简到难,我们先挑代码少的来说
inserter
inserter部分是最简单的,基本上就是引用的sqlbuilder的insert生成sql
type (
inserter struct {
sb sqlbuilder.InsertBuilder
exec SqlExecutor
}
)
func (i *inserter) Exec() (sql.Result, error) {
sb := i.sb
return i.exec.Exec(sb.Sql(), sb.Args()...)
}
func (i *inserter) Values(i2 interface{}) Inserter {
i.sb.Values(i2)
return i
}
func NewInserter(exec SqlExecutor, sb sqlbuilder.InsertBuilder) Inserter {
return &inserter{
sb: sb,
exec: exec,
}
}
deleter
自动删除这部分,基本是对于自动化where的一个处理,耽美逻辑部分也比较简单,就不多赘述了。
type (
deleter struct {
sb sqlbuilder.DeleteBuilder
exec SqlExecutor
}
)
func (i *deleter) Or(sql string, value ...interface{}) Deleter {
i.sb.Or(sql, value...)
return i
}
func (i *deleter) Where(sql string, value ...interface{}) Deleter {
i.sb.Where(sql, value...)
return i
}
func (i *deleter) And(sql string, value ...interface{}) Deleter {
i.sb.And(sql, value...)
return i
}
func (i *deleter) Exec() (sql.Result, error) {
sb := i.sb
return i.exec.Exec(sb.Sql(), sb.Args()...)
}
func NewDeleter(exec SqlExecutor, sb sqlbuilder.DeleteBuilder) Deleter {
return &deleter{
sb: sb,
exec: exec,
}
}
updater
自动修改这里,除了基础的where条件构造,还多了一个修改条件的添加。
代码如下:
type (
updater struct {
sb sqlbuilder.UpdateBuilder
exec SqlExecutor
}
)
func (i *updater) Set(key string, value interface{}) Updater {
i.sb.Set(key, value)
return i
}
func (i *updater) Or(sql string, value ...interface{}) Updater {
i.sb.Or(sql, value...)
return i
}
func (i *updater) Where(sql string, value ...interface{}) Updater {
i.sb.Where(sql, value...)
return i
}
func (i *updater) And(sql string, value ...interface{}) Updater {
i.sb.And(sql, value...)
return i
}
func (i *updater) Exec() (sql.Result, error) {
sb := i.sb
return i.exec.Exec(sb.Sql(), sb.Args()...)
}
func NewUpdate(exec SqlExecutor, sb sqlbuilder.UpdateBuilder) Updater {
return &updater{
sb: sb,
exec: exec,
}
}
selector
selector这里,分位了两个部分,一个部分是对于sql的构造,另一部分是对于执行好了的结果进行迭代。
基础结构定义
type (
selector struct {
sb sqlbuilder.Selector
exec SqlExecutor
}
)
func NewSelector(exec SqlExecutor, sb sqlbuilder.Selector) Selector {
return &selector{
sb: sb,
exec: exec,
}
}
sql构造
func (s *selector) AutoWhere(i interface{}) Selector {
if !reflectx.IsNull(i) {
if where := sqlbuilder.AutoWhere(i); where != nil {
s.sb.Where(where.Sql(), where.Args()...)
}
}
return s
}
func (s *selector) Where(sql string, value ...interface{}) Selector {
s.sb.Where(sql, value...)
return s
}
func (s *selector) And(sql string, value ...interface{}) Selector {
s.sb.And(sql, value...)
return s
}
func (s *selector) Or(sql string, value ...interface{}) Selector {
s.sb.Or(sql, value...)
return s
}
func (s *selector) From(tableName string) Selector {
s.sb.From(tableName)
return s
}
func (s *selector) Select(s2 ...string) Selector {
s.sb.Select(s2...)
return s
}
func (s *selector) OrderBy(s2 string) Selector {
s.sb.OrderBy(s2)
return s
}
func (s *selector) GroupBy(s2 string) Selector {
s.sb.GroupBy(s2)
return s
}
func (s *selector) Limit(i int64) Selector {
s.sb.Limit(i)
return s
}
func (s *selector) Offset(i int64) Selector {
s.sb.Offset(i)
return s
}
以上也可以基本的认为是对于sqlbuilder包下的查询语句生成器的封装
接下来是第二部分
迭代
func (s *selector) All(i interface{}) error {
rows, err := s.exec.Query(s.sb.Sql(), s.sb.Args()...)
if err != nil {
return err
}
iter := iterator.New(rows)
return iter.All(i)
}
func (s *selector) One(i interface{}) error {
sb := s.sb.Limit(1)
rows, err := s.exec.Query(sb.Sql(), sb.Args()...)
if err != nil {
return err
}
iter := iterator.New(rows)
return iter.One(i)
}
接口整合
光实现基础接口还是不够,还要整合到一起方便使用。
看到上面实现代码,不难发现,我们这里基于了一个接口叫SqlExecutor,他的基本职责就是相当于处理sql的最终运行。
我们这里涉及到到的SqlExecutor 只有两个
- 原生sql.DB
- 原生sql.Tx
然后基于SqlExecutor,我们实现了我们自己的 executor
executor
executor的职责很简单
- 就是根据当前的SqlExecutor来执行语句
- 根据当前的SqlExecutor创建我们之间定义的几个sql处理器
- 临时补上的一个比较常用的Count函数
type (
executor struct {
exec SqlExecutor
}
)
func (d *executor) Exec(sql string, args ...interface{}) (sql.Result, error) {
return d.exec.Exec(sql, args...)
}
func (d *executor) Query(sql string, args ...interface{}) (*sql.Rows, error) {
return d.exec.Query(sql, args...)
}
func (d *executor) QueryRow(sql string, args ...interface{}) *sql.Row {
return d.exec.QueryRow(sql, args...)
}
func (d *executor) Select(s ...string) Selector {
return NewSelector(d.exec, sqlbuilder.Select(s...))
}
func (d *executor) SelectFrom(s string) Selector {
return NewSelector(d.exec, sqlbuilder.SelectFrom(s))
}
func (d *executor) DeleteFrom(tableName string) Deleter {
return NewDeleter(d.exec, sqlbuilder.DeleteFrom(tableName))
}
func (d *executor) AutoDelete(i interface{}) (sql.Result, error) {
sb, err := sqlbuilder.AutoDelete(i)
if err != nil {
return nil, err
}
return NewDeleter(d.exec, sb).Exec()
}
func (d *executor) UpdateFrom(tableName string) Updater {
return NewUpdate(d.exec, sqlbuilder.UpdateFrom(tableName))
}
func (d *executor) AutoUpdate(i interface{}) (sql.Result, error) {
sb, err := sqlbuilder.AutoUpdate(i)
if err != nil {
return nil, err
}
return NewUpdate(d.exec, sb).Exec()
}
func (d *executor) InsertInto(t string) Inserter {
return NewInserter(d.exec, sqlbuilder.InsertInto(t))
}
func (d *executor) AutoInsert(t interface{}) (sql.Result, error) {
return NewInserter(d.exec, sqlbuilder.AutoInsert(t)).Exec()
}
func (d *executor) Count(i interface{}) (int64, error) {
var (
tb = sqlbuilder.TableName(i)
sb = sqlbuilder.Select("count(*) as c").From(tb)
tmp struct {
C int64
}
err error
)
err = NewSelector(d.exec, sb).AutoWhere(i).One(&tmp)
return tmp.C, err
}
func newExec(db SqlExecutor) *executor {
return &executor{exec: db}
}
dataBase
搞定executor之后,至于dataBase的封装,就更加的简单了。
他只的职责只有3个
- 关闭链接
- 打开一个Tx
- 设置当前链接的连接池数量
type (
dataBase struct {
*executor
db *sql.DB
}
)
func (d *dataBase) Close() error {
return d.db.Close()
}
func (d *dataBase) SetMaxOpenConns(n int) {
d.db.SetMaxOpenConns(n)
}
func (d *dataBase) Begin() (Tx, error) {
sqlTx, err := d.db.Begin()
if err != nil {
return nil, err
}
return newTx(sqlTx), nil
}
当然这里没提到dataBase是怎么初始化的,这个稍后再驱动部分会补上。
Tx
dataBase有个开启Tx的功能来实现事物,但是Tx的实现基础上跟dataBase差不多,只是扩展的函数只包含提交/回滚。
type (
tx struct {
*executor
db *sql.Tx
}
)
func (d *tx) Comment() error {
return d.db.Commit()
}
func (d *tx) RollBack() error {
return d.db.Rollback()
}
func newTx(db *sql.Tx) Tx {
return &tx{
executor: newExec(db),
db: db,
}
}
driver
最后呢,我们还有个根据driver来创建dataBase的函数。
整合以后的全局入口,就在这里了
func NewDB(driver, connStr string) (DataBase, error) {
db, err := sql.Open(driver, connStr)
if err != nil {
return nil, err
}
if err := db.Ping(); err != nil {
return nil, err
}
return &dataBase{
executor: newExec(db),
db: db,
}, nil
}
杂项
db相关的代码已经写完了,眼睛比较贼的小伙伴应该发现,我们还有一个接口没有用到。
就是 Connector
这个接口是用在我们db统一初始化的地方,db包内部无需关心这些参数的问题,只需要基于最基本的sql包进行操作即可
我们在最外层的入口定义了一个borm.New函数
func New(conn db.Connector) (db.DataBase, error) {
if reflectx.IsNull(conn) {
return nil, errors.New("nil connector")
}
db, err := db.NewDB(conn.DriverName(), conn.ConnStr())
if err == nil {
db.SetMaxOpenConns(conn.GetPoolSize())
}
return db, err
}
这个函数搞定以后,下一步我提供了一个原生的mysql接口实现,方便大家直接设置
type MySQLConfig struct {
User string `yaml:"user" json:"user" xml:"user"`
Pwd string `yaml:"pwd" json:"pwd" xml:"pwd"`
Db string `yaml:"db" json:"db" xml:"db"`
Host string `yaml:"host" json:"host" xml:"host"`
Port int `yaml:"port" json:"port" xml:"port"`
PoolSize int `yaml:"pool_size" json:"pool_size" xml:"pool_size"`
Charset string `yaml:"charset" json:"charset" xml:"charset"`
Loc string `yaml:"loc" json:"loc" xml:"loc"`
}
func (mc *MySQLConfig) DriverName() string {
return "mysql"
}
func (mc *MySQLConfig) ConnStr() string {
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=%s", mc.User, mc.Pwd, mc.Host, mc.defPort(), mc.Db, mc.defCharset(), mc.defLoc())
}
func (mc *MySQLConfig) defPort() int {
if mc.Port == 0 {
mc.Port = 3306
}
return mc.Port
}
func (mc *MySQLConfig) GetPoolSize() int {
if mc.PoolSize == 0 {
mc.PoolSize = 10
}
return mc.PoolSize
}
func (mc *MySQLConfig) defCharset() string {
if len(mc.Charset) == 0 {
mc.Charset = "utf8"
}
return mc.Charset
}
func (mc *MySQLConfig) defLoc() string {
if len(mc.Loc) == 0 {
mc.Loc = "Asia%2FShanghai"
}
return mc.Loc
}
基础设置与默认值也都在里面了,基本上开箱即用
其他
borm的使用也比较简单
go get github.com/luanruisong/borm
安装之后开始初始化链接,以mysql为例(其他的我还没写。。)
cfg := &borm.MySQLConfig{
User: "root",
Pwd: "123456",
Db: "test",
Host: "127.0.0.1",
}
db, err := borm.New(cfg)
if err != nil {
panic(err)
}
后面就可以进行直接的操作了(简单举几个例子)
type TestStruct struct {
Id uint64 `dbw:"gt"`
TString string
TBool bool
TTime time.Time
}
db.AutoInsert(TestStruct{
TString: "test_insert",
TBool: true,
TTime: time.Now(),
})
db.AutoDelete(DelTestStruct{Id: 1})//大于1的删除
list := []TestStruct{}
db.SelectFrom("test_struct").All(&list)
后记
关于borm的整合,基本上就在这里了。
拖拖拉拉写了好久,这一个系列搞完,对于个人提升还是蛮大的。
尤其对于golang的reflect包使用,sql驱动包的使用,还有一些go语言设计上的认知,都有明显的提升。
写博客的过程,有利于深入挖掘自己所用过的东西,也在于总结归纳自己接触过的知识。
总体来讲,我虽然菜,没准博客写着写着就变成大神了呢~