Passed
Push — master ( b769f5...17bc27 )
by DEATH
01:50
created

builder.go (20 issues)

Severity
1
package sqlbuilder
2
3
import (
4
	"reflect"
5
	"strconv"
6
)
7
8
type Builder struct {
0 ignored issues
show
exported type Builder should have comment or be unexported
Loading history...
9
	//The query value bindings
10
	bindings
11
12
	//The Columns that should be return
13
	columns []string
14
15
	//The table which the query is targeting
16
	table string
17
18
	//Update columns
19
	update []interface{}
20
21
	//Insert columns
22
	insert []string
23
24
	//Indicates is delete sql.
25
	delete bool
26
27
	//Indicates if the query return district results.
28
	district bool
29
30
	//The where constraints for the query.
31
	wheres []*where
32
33
	//The groupings for the query.
34
	groups []string
35
36
	//The havings constraints for the query.
37
	havings []*where
38
39
	//The table joins for the query.
40
	joins []*join
41
42
	//The orderings for the query.
43
	orders []*order
44
45
	//The maximum number of records to return.
46
	limit string
47
48
	//The number of records to skip.
49
	offset string
50
}
51
52
type bindings struct {
53
	selected []string
54
	insert   []string
55
	update   []string
56
	from     []string
57
	join     []string
58
	where    []string
59
	having   []string
60
	order    []string
61
}
62
63
//Expression for raw sql
64
type Expression struct {
65
	Value string
66
}
67
68
type where struct {
69
	column   string
70
	operator string
71
	value    interface{}
72
	boolean  string
73
}
74
75
type join struct {
76
	table     string
77
	condition string
78
	joinType  string // inner left right
79
}
80
81
type order struct {
82
	column    string
83
	direction string
84
}
85
86
//All of the available clause operators.
87
var operators = []string{"=", "<", ">", "<=", ">=", "<>", "!=", "<=>", "like", "like binary", "not like", "ilike",
88
	"&", "|", "^", "<<", ">>", "rlike", "regexp", "not regexp", "~", "~*", "!~", "!~*", "similar to", "not similar to",
89
	"not ilike", "~~*", "!~~*", "in", "not in",
90
}
91
92
//Is val in array
93
func in_array(val interface{}, array interface{}) (exists bool, index int) {
0 ignored issues
show
don't use underscores in Go names; func in_array should be inArray
Loading history...
94
	exists = false
95
	index = -1
96
97
	switch reflect.TypeOf(array).Kind() {
98
	case reflect.Slice:
99
		s := reflect.ValueOf(array)
100
101
		for i := 0; i < s.Len(); i++ {
102
			if reflect.DeepEqual(val, s.Index(i).Interface()) == true {
103
				index = i
104
				exists = true
105
				return
106
			}
107
		}
108
	}
109
110
	return
111
}
112
113
func (b *Builder) invalidOperator(operator string) bool {
114
	exists, _ := in_array(operator, operators)
115
	return exists
116
}
117
118
func (b *Builder) Select(columns []string) *Builder {
0 ignored issues
show
exported method Builder.Select should have comment or be unexported
Loading history...
119
	b.columns = columns
120
	return b
121
}
122
123
func (b *Builder) From(table string) *Builder {
0 ignored issues
show
exported method Builder.From should have comment or be unexported
Loading history...
124
	b.table = table
125
	return b
126
}
127
128
/*
0 ignored issues
show
comment on exported method Builder.Where should be of the form "Where ..."
Loading history...
129
Where("column", "1")
130
Where("column", "=","1")
131
Where("column", "in", []string{"1","2","3"})
132
Where("column", "=", "1", "or")
133
Where(map[string]string{column1:"1", column2: "2"})
134
*/
135
func (b *Builder) Where(column interface{}, args ...interface{}) *Builder {
136
	switch column.(type) {
137
	case string:
138
		operator := "="
139
		value := ""
140
		booll := "and"
141
		lenArgs := len(args)
142
		if lenArgs == 1 {
143
			value = args[0].(string)
144
		} else if lenArgs >= 2 {
145
			operator = args[0].(string)
146
147
			if lenArgs >= 3 {
148
				booll = args[2].(string)
149
			}
150
151
			switch args[1].(type) {
152
			case string:
153
				value = args[1].(string)
154
155
			case []string:
156
				//支持 where in 操作
157
				if !b.invalidOperator(operator) {
158
					operator = "="
159
				}
160
				condition := &where{column.(string), operator, args[1], booll}
161
				b.wheres = append(b.wheres, condition)
162
				b.bindings.where = append(b.bindings.where, args[1].([]string)...)
163
				goto end
164
			}
165
		}
166
167
		if !b.invalidOperator(operator) {
168
			operator = "="
169
		}
170
171
		condition := &where{column.(string), operator, value, booll}
172
		b.wheres = append(b.wheres, condition)
173
		b.bindings.where = append(b.bindings.where, value)
174
	case map[string]string:
175
		return b.addArrayOfWheres(column.(map[string]string), "and")
176
	}
177
178
end:
179
	return b
180
}
181
182
func (b *Builder) addArrayOfWheres(wheres map[string]string, boolean string) *Builder {
183
	for k, v := range wheres {
184
		condition := &where{k, "=", v, boolean}
185
		b.wheres = append(b.wheres, condition)
186
		b.bindings.where = append(b.bindings.where, v)
187
	}
188
	return b
189
}
190
191
/*
0 ignored issues
show
comment on exported method Builder.Join should be of the form "Join ..."
Loading history...
192
Join("tableB", "tableB.id = tableA.bId")
193
*/
194
func (b *Builder) Join(table string, condition string, args ...string) *Builder {
195
	joinType := "inner"
196
	lenArgs := len(args)
197
	if lenArgs > 0 {
198
		joinType = args[0]
199
	}
200
	j := &join{table, condition, joinType}
201
	b.joins = append(b.joins, j)
202
	return b
203
}
204
205
func (b *Builder) LeftJoin(table string, condition string) *Builder {
0 ignored issues
show
exported method Builder.LeftJoin should have comment or be unexported
Loading history...
206
207
	return b.Join(table, condition, "left")
208
}
209
210
func (b *Builder) RightJoin(table string, condition string) *Builder {
0 ignored issues
show
exported method Builder.RightJoin should have comment or be unexported
Loading history...
211
	return b.Join(table, condition, "right")
212
}
213
214
func (b *Builder) GroupBy(group interface{}) *Builder {
0 ignored issues
show
exported method Builder.GroupBy should have comment or be unexported
Loading history...
215
	switch group.(type) {
216
	case []string:
217
		b.groups = append(b.groups, group.([]string)...)
218
	case string:
219
		b.groups = append(b.groups, group.(string))
220
	}
221
	return b
222
}
223
224
/*
0 ignored issues
show
comment on exported method Builder.Having should be of the form "Having ..."
Loading history...
225
Having("column", "1")
226
Having("column", "=","1")
227
Having("column", "=", "1", "or")
228
Having(map[string]string{column1:"1", column2: "2"})
229
*/
230
func (b *Builder) Having(column interface{}, operator string, args ...string) *Builder {
231
	switch column.(type) {
232
	case string:
233
		value := ""
234
		booll := "and"
235
		lenArgs := len(args)
236
		if lenArgs == 0 {
237
			value = operator
238
		} else if lenArgs >= 1 {
239
			value = args[0]
240
		} else if lenArgs >= 2 {
241
			booll = args[1]
242
		}
243
244
		if !b.invalidOperator(operator) {
245
			operator = "="
246
		}
247
248
		condition := &where{column.(string), operator, value, booll}
249
		b.havings = append(b.havings, condition)
250
		b.bindings.having = append(b.bindings.having, value)
251
	case map[string]string:
252
		return b.addArrayOfHavings(column.(map[string]string), "and")
253
	}
254
255
	return b
256
}
257
258
func (b *Builder) addArrayOfHavings(wheres map[string]string, boolean string) *Builder {
259
	for k, v := range wheres {
260
		condition := &where{k, "=", v, boolean}
261
		b.havings = append(b.wheres, condition)
262
		b.bindings.having = append(b.bindings.having, v)
263
	}
264
	return b
265
}
266
267
func (b *Builder) OrderBy(column string, direction string) *Builder {
0 ignored issues
show
exported method Builder.OrderBy should have comment or be unexported
Loading history...
268
	b.orders = append(b.orders, &order{column, direction})
269
	return b
270
}
271
272
func (b *Builder) OrderByAsc(column string) *Builder {
0 ignored issues
show
exported method Builder.OrderByAsc should have comment or be unexported
Loading history...
273
	return b.OrderBy(column, "asc")
274
}
275
276
func (b *Builder) OrderByDesc(column string) *Builder {
0 ignored issues
show
exported method Builder.OrderByDesc should have comment or be unexported
Loading history...
277
	return b.OrderBy(column, "desc")
278
}
279
280
func (b *Builder) Offset(offset interface{}) *Builder {
0 ignored issues
show
exported method Builder.Offset should have comment or be unexported
Loading history...
281
	switch offset.(type) {
282
	case string:
283
		b.offset = offset.(string)
284
	case int:
285
		b.offset = strconv.Itoa(offset.(int))
286
	}
287
	return b
288
}
289
290
func (b *Builder) Limit(limit interface{}) *Builder {
0 ignored issues
show
exported method Builder.Limit should have comment or be unexported
Loading history...
291
	switch limit.(type) {
292
	case string:
293
		b.limit = limit.(string)
294
	case int:
295
		b.limit = strconv.Itoa(limit.(int))
296
	}
297
	return b
298
}
299
300
func (b *Builder) Insert(table string, info map[string]string) *Builder {
0 ignored issues
show
exported method Builder.Insert should have comment or be unexported
Loading history...
301
	b.table = table
302
303
	for column, value := range info {
304
		b.insert = append(b.insert, column)
305
		b.bindings.insert = append(b.bindings.insert, value)
306
	}
307
	return b
308
}
309
310
func (b *Builder) Update(table string, info map[string]interface{}) *Builder {
0 ignored issues
show
exported method Builder.Update should have comment or be unexported
Loading history...
311
	b.table = table
312
	for column, value := range info {
313
314
		switch value.(type) {
315
		case string:
316
			b.update = append(b.update, column)
317
			b.bindings.update = append(b.bindings.update, value.(string))
318
		case *Expression:
319
			//表达式: 如 a = a + 1
320
			b.update = append(b.update, value)
321
		}
322
	}
323
	return b
324
}
325
326
func (b *Builder) Delete(table string) *Builder {
0 ignored issues
show
exported method Builder.Delete should have comment or be unexported
Loading history...
327
	b.table = table
328
	b.delete = true
329
	return b
330
}
331
332
func (b *Builder) ToSql() (sql string, bindings []string) {
0 ignored issues
show
exported method Builder.ToSql should have comment or be unexported
Loading history...
method ToSql should be ToSQL
Loading history...
333
	if b.delete {
334
		return CompileDelete(b)
335
	} else if len(b.insert) > 0 {
336
		return CompileInsert(b)
337
	} else if len(b.update) > 0 {
338
		return CompileUpdate(b)
339
	} else {
340
		return CompileSelect(b)
341
	}
342
}
343