Skip to content

Commit 0048a49

Browse files
committed
增加直接执行sql以go template方式解析
1 parent 6e44b0b commit 0048a49

File tree

7 files changed

+147
-51
lines changed

7 files changed

+147
-51
lines changed

README.md

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,10 @@ func Run() {
115115
}
116116
```
117117

118-
### 5、说明
118+
### 5、解析说明
119+
#### 5.1、内置动态解析
119120

121+
内置动态解析是gobatis类Mybatis的解析方案(目前是xml mapper文件和直接执行sql的默认解析方式):
120122
1. ${}表示直接替换,#{}防止sql注入
121123
2. 与Mybatis类似,语句中${0}、${1}、${2}...${n} 对应的是Param方法中对应的不定参数,最终替换和调用底层Driver
122124
3. Param方法接受简单类型的不定参数(string、int、time、float等)、struct、map,底层自动解析获得参数,用法为:
@@ -140,7 +142,33 @@ session.Select("select * from test_table where username = #{TestTable.username}"
140142

141143
对应sql参数中的#{StructName.Field1}、#{StructName.Field2}...
142144

145+
#### 5.2、go template解析
143146

147+
使用go template解析,遵循template解析规则,是template mapper文件的解析方式。
148+
149+
如要要修改直接执行sql的默认解析方式,可通过:
150+
```cassandraql
151+
sessionManager.SetParserFactory(gobatis.TemplateParserFactory)
152+
```
153+
或者
154+
```cassandraql
155+
session.SetParserFactory(gobatis.TemplateParserFactory)
156+
```
157+
调用后可使用template的方式直接解析执行sql:
158+
```cassandraql
159+
session.Select("SELECT * FROM test_table WHERE id = {{.}}").Param(2).Result(&ret)
160+
```
161+
gobatis内置where、set、arg自定义函数,用于智能生成动态sql
162+
163+
arg用于将对象动态转换为占位符,并保存为sql参数,如:
164+
```cassandraql
165+
SELECT * FROM TABLE_NAME WHERE name = {{arg .Name}}
166+
```
167+
以mysql为例,将解析为:
168+
```cassandraql
169+
SELECT * FROM TABLE_NAME WHERE name = ?
170+
```
171+
同时Name的值将自动保存为SQL参数,自动传入,起到类似内置动态解析中#{MODEL.Name}的效果。
144172
### 6、事务
145173

146174
使用
@@ -292,17 +320,6 @@ DELETE FROM test_table
292320
{{where .Id "AND" "id = " (arg .Id) "" | where .Username "AND" "username = " (arg .Username) | where .Password "AND" "password = " (arg .Password) | where .Createtime "AND" "createtime = " (arg .Createtime)}}
293321
{{end}}
294322
```
295-
其中where、set、arg是gobatis的自定义函数,用于智能生成动态sql
296-
297-
arg用于将对象动态转换为占位符,并保存为SQL参数,如:
298-
```cassandraql
299-
SELECT * FROM TABLE_NAME WHERE name = {{arg .Name}}
300-
```
301-
以mysql为例,将解析为:
302-
```cassandraql
303-
SELECT * FROM TABLE_NAME WHERE name = ?
304-
```
305-
同时Name的值将自动保存为SQL参数,自动传入,起到类似xml中#{MODEL.Name}的效果。
306323

307324
### 9、gobatis-cmd生成文件使用示例
308325

errors/errcode.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ var (
3232
PARSE_SQL_VAR_ERROR = New("12001", "SQL PARSE ERROR")
3333
PARSE_SQL_PARAM_ERROR = New("12002", "SQL PARSE parameter error")
3434
PARSE_SQL_PARAM_VAR_NUMBER_ERROR = New("12003", "SQL PARSE parameter var number error")
35+
PARSE_PARSER_NIL_ERROR = New("12004", "Dynamic sql parser is nil error")
3536
PARSE_DYNAMIC_SQL_ERROR = New("12010", "Parse dynamic sql error")
37+
PARSE_TEMPLATE_NIL_ERROR = New("12101", "Parse template is nil")
3638
EXECUTOR_COMMIT_ERROR = New("21001", "executor was closed when transaction commit")
3739
EXECUTOR_BEGIN_ERROR = New("21002", "executor was closed when transaction begin")
3840
EXECUTOR_QUERY_ERROR = New("21003", "executor was closed when exec sql")

parsing/template/dynamic.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ const (
1717
argPlaceHolder = "_xfali_Arg_Holder"
1818
argPlaceHolderLen = 17
1919
argPlaceHolderFormat = "%s%08d"
20+
21+
FuncNameSet = "set"
22+
FuncNameWhere = "where"
23+
FuncNameArg = "arg"
24+
FuncNameAdd = "add"
2025
)
2126

2227
type Dynamic interface {
@@ -34,8 +39,9 @@ func dummyWhere(b interface{}, cond, column string, value interface{}, origin st
3439
return origin
3540
}
3641

42+
//return as fast as possible
3743
func dummyParam(p interface{}) string {
38-
return fmt.Sprint(p)
44+
return ""
3945
}
4046

4147
func dummyNil(p interface{}) bool {
@@ -49,11 +55,11 @@ func commonAdd(a, b int) int {
4955
type DummyDynamic struct{}
5056

5157
var dummyFuncMap = template.FuncMap{
52-
"set": dummyUpdateSet,
53-
"where": dummyWhere,
54-
"arg": dummyParam,
58+
FuncNameSet: dummyUpdateSet,
59+
FuncNameWhere: dummyWhere,
60+
FuncNameArg: dummyParam,
5561

56-
"add": commonAdd,
62+
FuncNameAdd: commonAdd,
5763
}
5864

5965
var gDummyDynamic = &DummyDynamic{}
@@ -79,11 +85,11 @@ type CommonDynamic struct {
7985

8086
func (d *CommonDynamic) getFuncMap() template.FuncMap {
8187
return template.FuncMap{
82-
"set": d.UpdateSet,
83-
"where": d.Where,
84-
"arg": d.Param,
88+
FuncNameSet: d.UpdateSet,
89+
FuncNameWhere: d.Where,
90+
FuncNameArg: d.Param,
8591

86-
"add": commonAdd,
92+
FuncNameAdd: commonAdd,
8793
}
8894
}
8995

parsing/template/parse.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package template
77

88
import (
9+
"github.com/xfali/gobatis/errors"
910
"github.com/xfali/gobatis/logging"
1011
"github.com/xfali/gobatis/parsing/sqlparser"
1112
"io/ioutil"
@@ -18,8 +19,21 @@ type Parser struct {
1819
tpl *template.Template
1920
}
2021

22+
func CreateParser(data []byte) (*Parser, error) {
23+
tpl := template.New("")
24+
tpl = tpl.Funcs(dummyFuncMap)
25+
tpl, err := tpl.Parse(string(data))
26+
if err != nil {
27+
return nil, err
28+
}
29+
return &Parser{tpl: tpl}, nil
30+
}
31+
2132
//only use first param
2233
func (p *Parser) ParseMetadata(driverName string, params ...interface{}) (*sqlparser.Metadata, error) {
34+
if p.tpl == nil {
35+
return nil, errors.PARSE_TEMPLATE_NIL_ERROR
36+
}
2337
b := strings.Builder{}
2438
var param interface{} = nil
2539
if len(params) > 0 {

sqlmanager.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,12 @@ func FindTemplateSqlParser(sqlId string) (sqlparser.SqlParser, bool) {
5757
return g_sql_mgr.templateSqlMgr.FindSqlParser(sqlId)
5858
}
5959

60-
func FindSqlParser(sqlId string) sqlparser.SqlParser {
61-
ret, ok := FindDynamicSqlParser(sqlId)
62-
if !ok {
63-
ret, ok = FindTemplateSqlParser(sqlId)
64-
}
65-
//FIXME: 当没有查找到sqlId对应的sql语句,则尝试使用sqlId直接操作数据库
66-
//该设计可能需要设计一个更合理的方式
67-
if !ok {
68-
return &parsing.DynamicData{OriginData: sqlId}
69-
}
70-
return ret
60+
type ParserFactory func(sql string) (sqlparser.SqlParser, error)
61+
62+
func DynamicParserFactory(sql string) (sqlparser.SqlParser, error) {
63+
return &parsing.DynamicData{OriginData: sql}, nil
7164
}
65+
66+
func TemplateParserFactory(sql string) (sqlparser.SqlParser, error) {
67+
return template.CreateParser([]byte(sql))
68+
}

sqlrunner.go

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,15 @@ import (
1919
)
2020

2121
type SessionManager struct {
22-
factory factory.Factory
22+
factory factory.Factory
23+
ParserFactory ParserFactory
2324
}
2425

2526
func NewSessionManager(factory factory.Factory) *SessionManager {
26-
return &SessionManager{factory: factory}
27+
return &SessionManager{
28+
factory: factory,
29+
ParserFactory: DynamicParserFactory,
30+
}
2731
}
2832

2933
type Runner interface {
@@ -41,10 +45,11 @@ type Runner interface {
4145
}
4246

4347
type Session struct {
44-
ctx context.Context
45-
log logging.LogFunc
46-
session session.SqlSession
47-
driver string
48+
ctx context.Context
49+
log logging.LogFunc
50+
session session.SqlSession
51+
driver string
52+
ParserFactory ParserFactory
4853
}
4954

5055
type BaseRunner struct {
@@ -79,13 +84,19 @@ type DeleteRunner struct {
7984
//使用一个session操作数据库
8085
func (this *SessionManager) NewSession() *Session {
8186
return &Session{
82-
ctx: context.Background(),
83-
log: this.factory.LogFunc(),
84-
session: this.factory.CreateSession(),
85-
driver: this.factory.GetDataSource().DriverName(),
87+
ctx: context.Background(),
88+
log: this.factory.LogFunc(),
89+
session: this.factory.CreateSession(),
90+
driver: this.factory.GetDataSource().DriverName(),
91+
ParserFactory: this.ParserFactory,
8692
}
8793
}
8894

95+
//修改sql解析器创建者
96+
func (this *SessionManager) SetParserFactory(fac ParserFactory) {
97+
this.ParserFactory = fac
98+
}
99+
89100
func (this *Session) SetContext(ctx context.Context) *Session {
90101
this.ctx = ctx
91102
return this
@@ -95,6 +106,11 @@ func (this *Session) GetContext() context.Context {
95106
return this.ctx
96107
}
97108

109+
//修改sql解析器创建者
110+
func (this *Session) SetParserFactory(fac ParserFactory) {
111+
this.ParserFactory = fac
112+
}
113+
98114
//开启事务执行语句
99115
//返回nil则提交,返回error回滚
100116
//抛出异常错误触发回滚
@@ -115,19 +131,19 @@ func (this *Session) Tx(txFunc func(session *Session) error) {
115131
}
116132

117133
func (this *Session) Select(sql string) Runner {
118-
return this.createSelect(FindSqlParser(sql))
134+
return this.createSelect(this.findSqlParser(sql))
119135
}
120136

121137
func (this *Session) Update(sql string) Runner {
122-
return this.createUpdate(FindSqlParser(sql))
138+
return this.createUpdate(this.findSqlParser(sql))
123139
}
124140

125141
func (this *Session) Delete(sql string) Runner {
126-
return this.createDelete(FindSqlParser(sql))
142+
return this.createDelete(this.findSqlParser(sql))
127143
}
128144

129145
func (this *Session) Insert(sql string) Runner {
130-
return this.createInsert(FindSqlParser(sql))
146+
return this.createInsert(this.findSqlParser(sql))
131147
}
132148

133149
func (this *BaseRunner) Param(params ...interface{}) Runner {
@@ -143,6 +159,11 @@ func (this *BaseRunner) Param(params ...interface{}) Runner {
143159
// }
144160
//}
145161

162+
if this.sqlParser == nil {
163+
this.log(logging.WARN, errors.PARSE_PARSER_NIL_ERROR.Error())
164+
return this
165+
}
166+
146167
md, err := this.sqlParser.ParseMetadata(this.driver, params...)
147168

148169
if err == nil {
@@ -152,7 +173,7 @@ func (this *BaseRunner) Param(params ...interface{}) Runner {
152173
this.log(logging.WARN, "sql action not match expect %s get %s", this.action, md.Action)
153174
}
154175
} else {
155-
this.log(logging.WARN, "%s", err.Error())
176+
this.log(logging.WARN, err.Error())
156177
}
157178
return this.this
158179
}
@@ -232,7 +253,7 @@ func (this *BaseRunner) LastInsertId() int64 {
232253
return -1
233254
}
234255

235-
func (this *Session)createSelect(parser sqlparser.SqlParser) Runner {
256+
func (this *Session) createSelect(parser sqlparser.SqlParser) Runner {
236257
ret := &SelectRunner{}
237258
ret.action = sqlparser.SELECT
238259
ret.log = this.log
@@ -244,7 +265,7 @@ func (this *Session)createSelect(parser sqlparser.SqlParser) Runner {
244265
return ret
245266
}
246267

247-
func (this *Session)createUpdate(parser sqlparser.SqlParser) Runner {
268+
func (this *Session) createUpdate(parser sqlparser.SqlParser) Runner {
248269
ret := &UpdateRunner{}
249270
ret.action = sqlparser.UPDATE
250271
ret.log = this.log
@@ -256,7 +277,7 @@ func (this *Session)createUpdate(parser sqlparser.SqlParser) Runner {
256277
return ret
257278
}
258279

259-
func (this *Session)createDelete(parser sqlparser.SqlParser) Runner {
280+
func (this *Session) createDelete(parser sqlparser.SqlParser) Runner {
260281
ret := &DeleteRunner{}
261282
ret.action = sqlparser.DELETE
262283
ret.log = this.log
@@ -268,7 +289,7 @@ func (this *Session)createDelete(parser sqlparser.SqlParser) Runner {
268289
return ret
269290
}
270291

271-
func (this *Session)createInsert(parser sqlparser.SqlParser) Runner {
292+
func (this *Session) createInsert(parser sqlparser.SqlParser) Runner {
272293
ret := &InsertRunner{}
273294
ret.action = sqlparser.INSERT
274295
ret.log = this.log
@@ -279,3 +300,21 @@ func (this *Session)createInsert(parser sqlparser.SqlParser) Runner {
279300
ret.this = ret
280301
return ret
281302
}
303+
304+
func (this *Session) findSqlParser(sqlId string) sqlparser.SqlParser {
305+
ret, ok := FindDynamicSqlParser(sqlId)
306+
if !ok {
307+
ret, ok = FindTemplateSqlParser(sqlId)
308+
}
309+
//FIXME: 当没有查找到sqlId对应的sql语句,则尝试使用sqlId直接操作数据库
310+
//该设计可能需要设计一个更合理的方式
311+
if !ok {
312+
d, err := this.ParserFactory(sqlId)
313+
if err != nil {
314+
this.log(logging.WARN, err.Error())
315+
return nil
316+
}
317+
return d
318+
}
319+
return ret
320+
}

test/postgresql/runner_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,24 @@ func TestTx3(t *testing.T) {
250250
return nil
251251
})
252252
}
253+
254+
func TestSession(t *testing.T) {
255+
t.Run("default", func(t *testing.T) {
256+
mgr := gobatis.NewSessionManager(connect())
257+
var ret []TestTable
258+
mgr.NewSession().Select("SELECT * FROM test_table WHERE id = #{0}").Param(2).Result(&ret)
259+
t.Log(ret)
260+
})
261+
262+
t.Run("default", func(t *testing.T) {
263+
mgr := gobatis.NewSessionManager(connect())
264+
mgr.SetParserFactory(gobatis.TemplateParserFactory)
265+
var ret1 []TestTable
266+
mgr.NewSession().Select("SELECT * FROM test_table WHERE id = {{arg .}}").Param(2).Result(&ret1)
267+
t.Log(ret1)
268+
269+
var ret2 []TestTable
270+
mgr.NewSession().Select("SELECT * FROM test_table WHERE id = {{.}}").Param(2).Result(&ret2)
271+
t.Log(ret2)
272+
})
273+
}

0 commit comments

Comments
 (0)