-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathFinder.go
242 lines (221 loc) · 8.57 KB
/
Finder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package zorm
import (
"encoding/json"
"errors"
"strings"
)
// Finder 查询数据库的载体,所有的sql语句都要通过Finder执行.
// Finder To query the database carrier, all SQL statements must be executed through Finder
type Finder struct {
// 拼接SQL
// Splicing SQL.
sqlBuilder strings.Builder
// SQL的参数值
// SQL parameter values.
values []interface{}
// 注入检查,默认true 不允许SQL注入的 ' 单引号
// Injection check, default true does not allow SQL injection single quote
InjectionCheck bool `json:"injectionCheck"`
// CountFinder 自定义的查询总条数'Finder',使用指针默认为nil.主要是为了在'group by'等复杂情况下,为了性能,手动编写总条数语句
// CountFinder The total number of custom queries is'Finder', and the pointer is nil by default. It is mainly used to manually write the total number of statements for performance in complex situations such as'group by'
CountFinder *Finder `json:"countFinder,omitempty"`
// 是否自动查询总条数,默认true.同时需要Page不为nil,才查询总条数
// Whether to automatically query the total number of entries, the default is true. At the same time, the Page is not nil to query the total number of entries
SelectTotalCount bool `json:"selectTotalCount"`
// SQL语句
// SQL statement
sqlstr string
}
// NewFinder 初始化一个Finder,生成一个空的Finder
// NewFinder Initialize a Finder and generate an empty Finder
func NewFinder() *Finder {
finder := Finder{}
finder.sqlBuilder.Grow(stringBuilderGrowLen)
finder.SelectTotalCount = true
finder.InjectionCheck = true
// slice扩容会生成新的slice,最后要值复制接收
finder.values = make([]interface{}, 0, 3)
return &finder
}
// NewSelectFinder 根据表名初始化查询的Finder,strs 只取第一个字符串,用数组类型是为了可以不传入,默认为 * | Finder that initializes the query based on the table name
// NewSelectFinder("tableName") SELECT * FROM tableName
// NewSelectFinder("tableName", "id,name") SELECT id,name FROM tableName
func NewSelectFinder(tableName string, strs ...string) *Finder {
strsLen := len(strs)
if strsLen > 1 { // 不支持多个参数
return nil
}
finder := NewFinder()
finder.sqlBuilder.WriteString("SELECT ")
if strsLen == 1 { // 只取值第一个字符串
finder.sqlBuilder.WriteString(strs[0])
} else {
finder.sqlBuilder.WriteByte('*')
}
finder.sqlBuilder.WriteString(" FROM ")
finder.sqlBuilder.WriteString(tableName)
return finder
}
// NewUpdateFinder 根据表名初始化更新的Finder, UPDATE tableName SET
// NewUpdateFinder Initialize the updated Finder according to the table name, UPDATE tableName SET
func NewUpdateFinder(tableName string) *Finder {
finder := NewFinder()
finder.sqlBuilder.WriteString("UPDATE ")
finder.sqlBuilder.WriteString(tableName)
finder.sqlBuilder.WriteString(" SET ")
return finder
}
// NewDeleteFinder 根据表名初始化删除的'Finder', DELETE FROM tableName
// NewDeleteFinder Finder for initial deletion based on table name. DELETE FROM tableName
func NewDeleteFinder(tableName string) *Finder {
finder := NewFinder()
finder.sqlBuilder.WriteString("DELETE FROM ")
finder.sqlBuilder.WriteString(tableName)
// 所有的 WHERE 都不加,规则统一,好记
// No WHERE is added, the rules are unified, easy to remember
// finder.sqlBuilder.WriteString(" WHERE ")
return finder
}
// Append 添加SQL和参数的值,第一个参数是语句,后面的参数[可选]是参数的值,顺序要正确
// 例如: finder.Append(" and id=? and name=? ",23123,"abc")
// 只拼接SQL,例如: finder.Append(" and name=123 ")
// Append:Add SQL and parameter values, the first parameter is the statement, and the following parameter (optional) is the value of the parameter, in the correct order
// E.g: finder.Append(" and id=? and name=? ",23123,"abc")
// Only splice SQL, E.g: finder.Append(" and name=123 ")
func (finder *Finder) Append(s string, values ...interface{}) *Finder {
// 不要自己构建finder,使用NewFinder()方法
// Don't build finder by yourself, use NewFinder() method
if finder == nil || finder.values == nil {
return nil
}
if s != "" {
if finder.sqlstr != "" {
finder.sqlstr = ""
}
// 默认加一个空格,避免手误两个字符串连接再一起
// A space is added by default to avoid hand mistakes when connecting two strings together
finder.sqlBuilder.WriteByte(' ')
finder.sqlBuilder.WriteString(s)
}
if values == nil || len(values) < 1 {
return finder
}
finder.values = append(finder.values, values...)
return finder
}
// AppendFinder 添加另一个Finder finder.AppendFinder(f)
// AppendFinder Add another Finder . finder.AppendFinder(f)
func (finder *Finder) AppendFinder(f *Finder) (*Finder, error) {
if finder == nil {
return finder, errors.New("->finder-->AppendFinder()finder对象为nil")
}
if f == nil {
return finder, errors.New("->finder-->AppendFinder()参数是nil")
}
// 不要自己构建finder,使用NewFinder()方法
// Don't build finder by yourself, use NewFinder() method
if finder.values == nil {
return finder, errors.New("->finder-->AppendFinder()不要自己构建finder,使用NewFinder()方法")
}
// 添加f的SQL
// SQL to add f
sqlstr, err := f.GetSQL()
if err != nil {
return finder, err
}
finder.sqlstr = ""
finder.sqlBuilder.WriteString(sqlstr)
// 添加f的值
// Add the value of f
finder.values = append(finder.values, f.values...)
return finder, nil
}
// GetSQL 返回Finder封装的SQL语句
// GetSQL Return the SQL statement encapsulated by the Finder
func (finder *Finder) GetSQL() (string, error) {
// 不要自己构建finder,使用NewFinder方法
// Don't build finder by yourself, use NewFinder method
if finder == nil || finder.values == nil {
return "", errors.New("->finder-->GetSQL()不要自己构建finder,使用NewFinder()方法")
}
if finder.sqlstr != "" {
return finder.sqlstr, nil
}
sqlstr := finder.sqlBuilder.String()
// 包含单引号,属于非法字符串
// Contains single quotes, which are illegal strings
if finder.InjectionCheck && (strings.Contains(sqlstr, "'")) {
return "", errors.New(`->finder-->GetSQL()SQL语句请不要直接拼接字符串参数,容易注入!!!请使用问号占位符,例如 finder.Append("and id=?","stringId"),如果必须拼接字符串,请设置 finder.InjectionCheck = false `)
}
finder.sqlstr = sqlstr
return sqlstr, nil
}
// GetValues 返回Finder封装的values值
func (finder *Finder) GetValues() ([]interface{}, error) {
// 不要自己构建finder,使用NewFinder方法
// Don't build finder by yourself, use NewFinder method
if finder == nil || finder.values == nil {
return nil, errors.New("->finder-->GetValues()不要自己构建finder,使用NewFinder()方法")
}
return finder.values, nil
}
func (finder *Finder) MarshalJSON() ([]byte, error) {
if finder == nil {
return nil, errors.New("->finder-->MarshalJSON()finder对象为nil")
}
sqlstr, err := finder.GetSQL()
if err != nil {
return nil, err
}
values, err := finder.GetValues()
if err != nil {
return nil, err
}
type FinderJSON Finder
data := struct {
*FinderJSON
SQLStr string `json:"sqlstr,omitempty"`
Values []interface{} `json:"values,omitempty"`
}{
FinderJSON: (*FinderJSON)(finder),
SQLStr: sqlstr,
Values: values,
}
return json.Marshal(data)
}
func (finder *Finder) UnmarshalJSON(data []byte) error {
if finder == nil {
return errors.New("->finder-->UnmarshalJSON()finder对象为nil")
}
type FinderJSON Finder
finderJson := &struct {
*FinderJSON
SQLStr string `json:"sqlstr,omitempty"`
Values []interface{} `json:"values,omitempty"`
}{
FinderJSON: (*FinderJSON)(finder),
Values: make([]interface{}, 0),
}
if err := json.Unmarshal(data, finderJson); err != nil {
return err
}
finder.Append(finderJson.SQLStr, finderJson.Values...)
return nil
}