Skip to content

Commit c0eb3be

Browse files
committed
add template support, and postgresql test
1 parent 968afea commit c0eb3be

File tree

14 files changed

+754
-64
lines changed

14 files changed

+754
-64
lines changed

datasource/postgre_datasource.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,8 @@ func (ds *PostgreDataSource) DriverName() string {
2424
}
2525

2626
func (ds *PostgreDataSource) DriverInfo() string {
27+
if ds.SslMode == "" {
28+
ds.SslMode = "disable"
29+
}
2730
return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s", ds.Host, ds.Port, ds.Username, ds.Password, ds.DBName, ds.SslMode)
2831
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ go 1.11
44

55
require (
66
github.com/go-sql-driver/mysql v1.4.1 // indirect
7+
github.com/lib/pq v1.3.0 // indirect
78
github.com/mattn/go-sqlite3 v1.10.0 // indirect
89
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
22
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
3+
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
4+
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
35
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
46
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=

parsing/dynamics.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ package parsing
1010

1111
import (
1212
"github.com/xfali/gobatis/logging"
13+
"github.com/xfali/gobatis/parsing/sqlparser"
1314
"github.com/xfali/gobatis/reflection"
1415
"reflect"
1516
"strings"
@@ -67,3 +68,9 @@ func (m *DynamicData) ReplaceWithMap(objParams map[string]interface{}) string {
6768
}
6869
return ret
6970
}
71+
72+
func (m *DynamicData) ParseMetadata(driverName string, params ...interface{})(*sqlparser.Metadata, error) {
73+
paramMap := reflection.ParseParams(params...)
74+
sqlStr := m.ReplaceWithMap(paramMap)
75+
return sqlparser.ParseWithParamMap(driverName, sqlStr, paramMap)
76+
}

parsing/sqlparser/parse.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ type Metadata struct {
3030
Params []interface{}
3131
}
3232

33+
type SqlParser interface {
34+
ParseMetadata(driverName string, params ...interface{}) (*Metadata, error)
35+
}
36+
3337
func SimpleParse(sql string) (*Metadata, error) {
3438
ret := Metadata{}
3539
sql = strings.Trim(sql, " ")
@@ -122,7 +126,7 @@ func ParseWithParams(sql string, params ...interface{}) (*Metadata, error) {
122126
return &ret, nil
123127
}
124128

125-
func ParseWithParamMap(sql string, params map[string]interface{}) (*Metadata, error) {
129+
func ParseWithParamMap(driverName, sql string, params map[string]interface{}) (*Metadata, error) {
126130
ret := Metadata{}
127131
sql = strings.Trim(sql, " ")
128132
action := sql[:6]
@@ -133,6 +137,9 @@ func ParseWithParamMap(sql string, params map[string]interface{}) (*Metadata, er
133137
subStr := sql
134138
firstIndex, lastIndex := -1, -1
135139
var c string
140+
var index int = 0
141+
holder := selectHolder(driverName)
142+
136143
for {
137144
firstIndex = strings.Index(subStr, "{")
138145
if firstIndex == -1 || firstIndex == 0 {
@@ -156,7 +163,9 @@ func ParseWithParamMap(sql string, params map[string]interface{}) (*Metadata, er
156163
subStr = strings.Replace(subStr, oldStr, newStr, -1)
157164
} else if c == "#" {
158165
oldStr := "#{" + varName + "}"
159-
ret.PrepareSql = strings.Replace(ret.PrepareSql, oldStr, "?", -1)
166+
index++
167+
h := holder(index)
168+
ret.PrepareSql = strings.Replace(ret.PrepareSql, oldStr, h, -1)
160169
ret.Params = append(ret.Params, value)
161170
}
162171
} else {
@@ -171,6 +180,28 @@ func ParseWithParamMap(sql string, params map[string]interface{}) (*Metadata, er
171180
return &ret, nil
172181
}
173182

183+
type holder func(int) string
184+
185+
var gHolderMap = map[string]holder{
186+
"mysql": mysqlHolder,
187+
"postgres": postgresHolder,
188+
}
189+
190+
func selectHolder(driverName string) holder {
191+
if v, ok := gHolderMap[driverName]; ok {
192+
return v
193+
}
194+
return mysqlHolder
195+
}
196+
197+
func mysqlHolder(int) string {
198+
return "?"
199+
}
200+
201+
func postgresHolder(i int) string {
202+
return "$" + strconv.Itoa(i)
203+
}
204+
174205
func interface2String(i interface{}) string {
175206
return fmt.Sprintf("%v", i)
176207
}

parsing/template/parse.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright (C) 2019-2020, Xiongfa Li.
2+
// @author xiongfa.li
3+
// @version V1.0
4+
// Description:
5+
6+
package template
7+
8+
import (
9+
"github.com/xfali/gobatis/logging"
10+
"github.com/xfali/gobatis/parsing/sqlparser"
11+
"html/template"
12+
"io/ioutil"
13+
"strings"
14+
"sync"
15+
)
16+
17+
type Parser struct {
18+
tpl *template.Template
19+
}
20+
21+
//only use first param
22+
func (p *Parser) ParseMetadata(driverName string, params ...interface{}) (*sqlparser.Metadata, error) {
23+
b := strings.Builder{}
24+
var param interface{} = nil
25+
if len(params) > 0 {
26+
param = params[0]
27+
}
28+
29+
err := p.tpl.Execute(&b, param)
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
ret := &sqlparser.Metadata{}
35+
sql := strings.TrimSpace(b.String())
36+
action := sql[:6]
37+
action = strings.ToLower(action)
38+
ret.Action = action
39+
ret.PrepareSql = sql
40+
ret.Params = nil
41+
42+
return ret, nil
43+
}
44+
45+
func updateSet(sets ... string) string {
46+
b := strings.Builder{}
47+
for _, v := range sets {
48+
if len(v) > 0 {
49+
b.WriteString(strings.TrimSpace(v))
50+
b.WriteString(",")
51+
}
52+
}
53+
setStr := b.String()
54+
if len(setStr) == 0 {
55+
return ""
56+
} else {
57+
return " SET " + setStr[:len(setStr)-1]
58+
}
59+
}
60+
61+
type Manager struct {
62+
sqlMap map[string]*Parser
63+
lock sync.Mutex
64+
}
65+
66+
func NewManager() *Manager {
67+
return &Manager{
68+
sqlMap: map[string]*Parser{},
69+
}
70+
}
71+
72+
func (m *Manager) RegisterData(data []byte) error {
73+
m.lock.Lock()
74+
defer m.lock.Unlock()
75+
76+
tpl := template.New("")
77+
tpl = tpl.Funcs(template.FuncMap{
78+
"updateSet": updateSet,
79+
})
80+
tpl, err := tpl.Parse(string(data))
81+
if err != nil {
82+
logging.Warn("register template data failed: %s err: %v\n", string(data), err)
83+
return err
84+
}
85+
86+
tpls := tpl.Templates()
87+
for _, v := range tpls {
88+
m.sqlMap[v.Name()] = &Parser{v}
89+
}
90+
91+
return nil
92+
}
93+
94+
func (m *Manager) RegisterFile(file string) error {
95+
m.lock.Lock()
96+
defer m.lock.Unlock()
97+
98+
tpl := template.New("")
99+
tpl = tpl.Funcs(template.FuncMap{
100+
"updateSet": updateSet,
101+
})
102+
data, err := ioutil.ReadFile(file)
103+
if err != nil {
104+
logging.Warn("register template file failed: %s err: %v\n", file, err)
105+
return err
106+
}
107+
tpl, err = tpl.Parse(string(data))
108+
if err != nil {
109+
logging.Warn("register template file failed: %s err: %v\n", file, err)
110+
return err
111+
}
112+
113+
tpls := tpl.Templates()
114+
for _, v := range tpls {
115+
m.sqlMap[v.Name()] = &Parser{v}
116+
}
117+
118+
return nil
119+
}
120+
121+
func (m *Manager) FindSql(sqlId string) (*Parser, bool) {
122+
m.lock.Lock()
123+
defer m.lock.Unlock()
124+
125+
v, ok := m.sqlMap[sqlId]
126+
return v, ok
127+
}

sqlmanager.go

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,40 +12,50 @@ import (
1212
"github.com/xfali/gobatis/errors"
1313
"github.com/xfali/gobatis/logging"
1414
"github.com/xfali/gobatis/parsing"
15+
"github.com/xfali/gobatis/parsing/sqlparser"
16+
"github.com/xfali/gobatis/parsing/template"
1517
"github.com/xfali/gobatis/parsing/xml"
1618
"sync"
1719
)
1820

19-
type SqlManager struct {
21+
type dynamicSqlManager struct {
2022
sqlMap map[string]*parsing.DynamicData
2123
lock sync.Mutex
2224
}
2325

24-
var g_sql_mgr = SqlManager{sqlMap: map[string]*parsing.DynamicData{}}
26+
type sqlManager struct {
27+
dynamicSqlMgr *dynamicSqlManager
28+
templateSqlMgr *template.Manager
29+
}
30+
31+
var g_sql_mgr = sqlManager{
32+
dynamicSqlMgr: &dynamicSqlManager{sqlMap: map[string]*parsing.DynamicData{}},
33+
templateSqlMgr: template.NewManager(),
34+
}
2535

2636
func RegisterSql(sqlId string, sql string) error {
27-
g_sql_mgr.lock.Lock()
28-
defer g_sql_mgr.lock.Unlock()
37+
g_sql_mgr.dynamicSqlMgr.lock.Lock()
38+
defer g_sql_mgr.dynamicSqlMgr.lock.Unlock()
2939

30-
if _, ok := g_sql_mgr.sqlMap[sqlId]; ok {
40+
if _, ok := g_sql_mgr.dynamicSqlMgr.sqlMap[sqlId]; ok {
3141
return errors.SQL_ID_DUPLICATES
3242
} else {
3343
dd := &parsing.DynamicData{OriginData: sql}
34-
g_sql_mgr.sqlMap[sqlId] = dd
44+
g_sql_mgr.dynamicSqlMgr.sqlMap[sqlId] = dd
3545
}
3646
return nil
3747
}
3848

3949
func UnregisterSql(sqlId string) {
40-
g_sql_mgr.lock.Lock()
41-
defer g_sql_mgr.lock.Unlock()
50+
g_sql_mgr.dynamicSqlMgr.lock.Lock()
51+
defer g_sql_mgr.dynamicSqlMgr.lock.Unlock()
4252

43-
delete(g_sql_mgr.sqlMap, sqlId)
53+
delete(g_sql_mgr.dynamicSqlMgr.sqlMap, sqlId)
4454
}
4555

4656
func RegisterMapperData(data []byte) error {
47-
g_sql_mgr.lock.Lock()
48-
defer g_sql_mgr.lock.Unlock()
57+
g_sql_mgr.dynamicSqlMgr.lock.Lock()
58+
defer g_sql_mgr.dynamicSqlMgr.lock.Unlock()
4959

5060
mapper, err := xml.Parse(data)
5161
if err != nil {
@@ -57,8 +67,8 @@ func RegisterMapperData(data []byte) error {
5767
}
5868

5969
func RegisterMapperFile(file string) error {
60-
g_sql_mgr.lock.Lock()
61-
defer g_sql_mgr.lock.Unlock()
70+
g_sql_mgr.dynamicSqlMgr.lock.Lock()
71+
defer g_sql_mgr.dynamicSqlMgr.lock.Unlock()
6272

6373
mapper, err := xml.ParseFile(file)
6474
if err != nil {
@@ -72,18 +82,31 @@ func RegisterMapperFile(file string) error {
7282
func formatMapper(mapper *xml.Mapper) error {
7383
ret := mapper.Format()
7484
for k, v := range ret {
75-
if _, ok := g_sql_mgr.sqlMap[k]; ok {
85+
if _, ok := g_sql_mgr.dynamicSqlMgr.sqlMap[k]; ok {
7686
return errors.SQL_ID_DUPLICATES
7787
} else {
78-
g_sql_mgr.sqlMap[k] = v
88+
g_sql_mgr.dynamicSqlMgr.sqlMap[k] = v
7989
}
8090
}
8191
return nil
8292
}
8393

84-
func FindSql(sqlId string) *parsing.DynamicData {
85-
g_sql_mgr.lock.Lock()
86-
defer g_sql_mgr.lock.Unlock()
94+
func FindDynamicSql(sqlId string) (sqlparser.SqlParser, bool) {
95+
g_sql_mgr.dynamicSqlMgr.lock.Lock()
96+
defer g_sql_mgr.dynamicSqlMgr.lock.Unlock()
97+
98+
v, ok := g_sql_mgr.dynamicSqlMgr.sqlMap[sqlId]
99+
return v, ok
100+
}
101+
102+
func RegisterTemplateData(data []byte) error {
103+
return g_sql_mgr.templateSqlMgr.RegisterData(data)
104+
}
105+
106+
func RegisterTemplateFile(file string) error {
107+
return g_sql_mgr.templateSqlMgr.RegisterFile(file)
108+
}
87109

88-
return g_sql_mgr.sqlMap[sqlId]
110+
func FindTemplateSql(sqlId string) (sqlparser.SqlParser, bool) {
111+
return g_sql_mgr.templateSqlMgr.FindSql(sqlId)
89112
}

0 commit comments

Comments
 (0)