-
Notifications
You must be signed in to change notification settings - Fork 25
/
functions.go
411 lines (340 loc) · 11.3 KB
/
functions.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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
// Copyright 2019 Yunion
//
// Licensed 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 sqlchemy
import (
"fmt"
"strings"
)
// IFunctionQueryField is a special type of field that is an aggregate function
type IFunctionQueryField interface {
IQueryField
// is this an aggregate function?
IsAggregate() bool
}
// IFunction is the interface for a SQL embedded function, such as MIN, MAX, NOW, etc.
type IFunction interface {
expression() string
variables() []interface{}
database() *SDatabase
queryFields() []IQueryField
}
// NewFunction creates a field with SQL function
// for example: SUM(count) as total
func NewFunction(ifunc IFunction, name string, isAggre bool) IQueryField {
return &SFunctionFieldBase{
IFunction: ifunc,
alias: name,
aggregate: isAggre,
}
}
// SFunctionFieldBase is a query field that is the result of a SQL embedded function, e.g. COUNT(*) as count
type SFunctionFieldBase struct {
IFunction
alias string
aggregate bool
}
func (ff *SFunctionFieldBase) getQuoteChar() string {
qChar := ""
if ff.database() != nil {
qChar = ff.database().backend.QuoteChar()
}
return qChar
}
// Reference implementation of SFunctionFieldBase for IQueryField
func (ff *SFunctionFieldBase) Reference() string {
if len(ff.alias) == 0 {
// log.Warningf("reference a function field without alias! %s", ff.expression())
return ff.expression()
}
qChar := ff.getQuoteChar()
return fmt.Sprintf("%s%s%s", qChar, ff.alias, qChar)
}
// Expression implementation of SFunctionFieldBase for IQueryField
func (ff *SFunctionFieldBase) Expression() string {
return ff.expression()
}
// Name implementation of SFunctionFieldBase for IQueryField
func (ff *SFunctionFieldBase) Name() string {
if len(ff.alias) > 0 {
return ff.alias
}
return ff.expression()
}
// Label implementation of SFunctionFieldBase for IQueryField
func (ff *SFunctionFieldBase) Label(label string) IQueryField {
if len(label) > 0 {
ff.alias = label
}
return ff
}
// Variables implementation of SFunctionFieldBase for IQueryField
func (ff *SFunctionFieldBase) Variables() []interface{} {
return ff.variables()
}
func (ff *SFunctionFieldBase) IsAggregate() bool {
return ff.aggregate
}
type sExprFunction struct {
fields []IQueryField
function string
}
func (ff *sExprFunction) expression() string {
fieldRefs := make([]interface{}, 0)
for _, f := range ff.fields {
fieldRefs = append(fieldRefs, f.Expression())
}
return fmt.Sprintf(ff.function, fieldRefs...)
}
func (ff *sExprFunction) variables() []interface{} {
vars := make([]interface{}, 0)
for _, f := range ff.fields {
fromVars := f.Variables()
vars = append(vars, fromVars...)
}
return vars
}
func (ff *sExprFunction) database() *SDatabase {
for i := range ff.fields {
db := ff.fields[i].database()
if db != nil {
return db
}
}
// if ff.function != "COUNT(*)" {
// log.Debugf("no fields function? %s", ff.expression())
// }
return nil
}
func (ff *sExprFunction) queryFields() []IQueryField {
return ff.fields
}
// NewFunctionField returns an instance of query field by calling a SQL embedded function
func NewFunctionField(name string, isAggr bool, funcexp string, fields ...IQueryField) IQueryField {
funcBase := &sExprFunction{
fields: fields,
function: funcexp,
}
return &SFunctionFieldBase{
IFunction: funcBase,
alias: name,
aggregate: isAggr,
}
}
// COUNT represents the SQL function COUNT
func COUNT(name string, field ...IQueryField) IQueryField {
return getFieldBackend(field...).COUNT(name, field...)
}
// MAX represents the SQL function MAX
func MAX(name string, field IQueryField) IQueryField {
return getFieldBackend(field).MAX(name, field)
}
// MIN represents the SQL function MIN
func MIN(name string, field IQueryField) IQueryField {
return getFieldBackend(field).MIN(name, field)
}
// SUM represents the SQL function SUM
func SUM(name string, field IQueryField) IQueryField {
return getFieldBackend(field).SUM(name, field)
}
// AVG represents the SQL function SUM
func AVG(name string, field IQueryField) IQueryField {
return getFieldBackend(field).AVG(name, field)
}
// LOWER represents the SQL function SUM
func LOWER(name string, field IQueryField) IQueryField {
return getFieldBackend(field).LOWER(name, field)
}
// UPPER represents the SQL function SUM
func UPPER(name string, field IQueryField) IQueryField {
return getFieldBackend(field).UPPER(name, field)
}
// DISTINCT represents the SQL function DISTINCT
func DISTINCT(name string, field IQueryField) IQueryField {
return getFieldBackend(field).DISTINCT(name, field)
}
// GROUP_CONCAT represents the SQL function GROUP_CONCAT
func GROUP_CONCAT(name string, field IQueryField) IQueryField {
return GROUP_CONCAT2(name, ",", field)
}
// GROUP_CONCAT2 represents the SQL function GROUP_CONCAT
func GROUP_CONCAT2(name string, sep string, field IQueryField) IQueryField {
// return NewFunctionField(name, "GROUP_CONCAT(%s)", field)
return getFieldBackend(field).GROUP_CONCAT2(name, sep, field)
}
// REPLACE represents the SQL function REPLACE
func REPLACE(name string, field IQueryField, old string, new string) IQueryField {
return getFieldBackend(field).REPLACE(name, field, old, new)
}
// SConstField is a query field of a constant
type SConstField struct {
constVar interface{}
alias string
}
// Expression implementation of SConstField for IQueryField
func (s *SConstField) Expression() string {
return s.Reference()
}
// Name implementation of SConstField for IQueryField
func (s *SConstField) Name() string {
return s.alias
}
// Reference implementation of SConstField for IQueryField
func (s *SConstField) Reference() string {
return getQuoteStringValue(s.constVar)
}
// Label implementation of SConstField for IQueryField
func (s *SConstField) Label(label string) IQueryField {
if len(label) > 0 {
s.alias = label
}
return s
}
// database implementation of SConstField for IQueryField
func (s *SConstField) database() *SDatabase {
return nil
}
// Variables implementation of SConstField for IQueryField
func (s *SConstField) Variables() []interface{} {
return nil
}
// IsAggregate implementation of SConstField for IFunctionQueryField
func (s *SConstField) IsAggregate() bool {
return true
}
// NewConstField returns an instance of SConstField
func NewConstField(variable interface{}) *SConstField {
return &SConstField{constVar: variable}
}
// SStringField is a query field of a string constant
type SStringField struct {
strConst string
alias string
}
// Expression implementation of SStringField for IQueryField
func (s *SStringField) Expression() string {
return s.Reference()
}
// Name implementation of SStringField for IQueryField
func (s *SStringField) Name() string {
return s.alias
}
// Reference implementation of SStringField for IQueryField
func (s *SStringField) Reference() string {
return getQuoteStringValue(s.strConst)
}
// Label implementation of SStringField for IQueryField
func (s *SStringField) Label(label string) IQueryField {
if len(label) > 0 {
s.alias = label
}
return s
}
// database implementation of SStringField for IQueryField
func (s *SStringField) database() *SDatabase {
return nil
}
// Variables implementation of SStringField for IQueryField
func (s *SStringField) Variables() []interface{} {
return nil
}
// IsAggregate implementation of SStringField for IFunctionQueryField
func (s *SStringField) IsAggregate() bool {
return true
}
// NewStringField returns an instance of SStringField
func NewStringField(strConst string) *SStringField {
return &SStringField{strConst: strConst}
}
// CONCAT represents a SQL function CONCAT
func CONCAT(name string, fields ...IQueryField) IQueryField {
return getFieldBackend(fields...).CONCAT(name, fields...)
}
// SubStr represents a SQL function SUBSTR
// Deprecated
func SubStr(name string, field IQueryField, pos, length int) IQueryField {
return SUBSTR(name, field, pos, length)
}
// SUBSTR represents a SQL function SUBSTR
func SUBSTR(name string, field IQueryField, pos, length int) IQueryField {
return getFieldBackend(field).SUBSTR(name, field, pos, length)
}
// OR_Val represents a SQL function that does binary | operation on a field
func OR_Val(name string, field IQueryField, v interface{}) IQueryField {
return getFieldBackend(field).OR_Val(name, field, v)
}
// AND_Val represents a SQL function that does binary & operation on a field
func AND_Val(name string, field IQueryField, v interface{}) IQueryField {
return getFieldBackend(field).AND_Val(name, field, v)
}
// INET_ATON represents a SQL function INET_ATON
func INET_ATON(field IQueryField) IQueryField {
return getFieldBackend(field).INET_ATON(field)
}
// TimestampAdd represents a SQL function TimestampAdd
func TimestampAdd(name string, field IQueryField, offsetSeconds int) IQueryField {
return TIMESTAMPADD(name, field, offsetSeconds)
}
// TIMESTAMPADD represents a SQL function TimestampAdd
func TIMESTAMPADD(name string, field IQueryField, offsetSeconds int) IQueryField {
return getFieldBackend(field).TIMESTAMPADD(name, field, offsetSeconds)
}
// DATE_FORMAT represents a SQL function DATE_FORMAT
func DATE_FORMAT(name string, field IQueryField, format string) IQueryField {
return getFieldBackend(field).DATE_FORMAT(name, field, format)
}
// CAST represents a SQL function cast types
func CAST(field IQueryField, typeStr string, fieldname string) IQueryField {
return getFieldBackend(field).CAST(field, typeStr, fieldname)
}
// CASTString represents a SQL function cast any type to String
func CASTString(field IQueryField, fieldname string) IQueryField {
return getFieldBackend(field).CASTString(field, fieldname)
}
// CASTInt represents a SQL function cast any type to Integer
func CASTInt(field IQueryField, fieldname string) IQueryField {
return getFieldBackend(field).CASTInt(field, fieldname)
}
// CASTFloat represents a SQL function cast any type to Float
func CASTFloat(field IQueryField, fieldname string) IQueryField {
return getFieldBackend(field).CASTFloat(field, fieldname)
}
// LENGTH represents a SQL function of LENGTH
func LENGTH(name string, field IQueryField) IQueryField {
return getFieldBackend(field).LENGTH(name, field)
}
func bc(name, op string, fields ...IQueryField) IQueryField {
exps := []string{}
for i := 0; i < len(fields); i++ {
exps = append(exps, "%s")
}
return NewFunctionField(name, false, strings.Join(exps, fmt.Sprintf(" %s ", op)), fields...)
}
func ADD(name string, fields ...IQueryField) IQueryField {
return bc(name, "+", fields...)
}
func SUB(name string, fields ...IQueryField) IQueryField {
return bc(name, "-", fields...)
}
func MUL(name string, fields ...IQueryField) IQueryField {
return bc(name, "*", fields...)
}
func DIV(name string, fields ...IQueryField) IQueryField {
return bc(name, "/", fields...)
}
func DATEDIFF(unit string, field1, field2 IQueryField) IQueryField {
return getFieldBackend(field1).DATEDIFF(unit, field1, field2)
}
func ABS(name string, field IQueryField) IQueryField {
return NewFunctionField(name, false, "ABS(%s)", field)
}