Issues (25)

builder.go (20 issues)

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