-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathquery_builder.go
166 lines (136 loc) · 4.09 KB
/
query_builder.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
package sqlm
import (
"fmt"
"strings"
"time"
)
// Any thing can be converted to a sql and its arguments is an expression
type Expression interface {
ToSql() (string, []interface{})
}
// Raw expression just a wrapper of a sql and relative arguments
type Raw struct {
Sql string
Arguments []interface{}
}
func (s Raw) ToSql() (string, []interface{}) {
return s.Sql, s.Arguments
}
func NewRaw(sql string, arguments ...interface{}) Raw {
if len(arguments) == 0 {
return Raw{Sql: sql, Arguments: arguments}
} else if len(arguments) == 1 {
return Raw{Sql: sql, Arguments: flat([]interface{}{}, arguments[0])}
}
return Raw{Sql: sql, Arguments: flat([]interface{}{}, arguments)}
}
// formatter is a generic helper, which provide the way to join several expressions
// together.
type formatter struct {
expressions []Expression
sep string
prefix string
suffix string
}
func (s formatter) ToSql() (string, []interface{}) {
sql := make([]string, len(s.expressions))
arguments := make([]interface{}, 0, len(s.expressions))
for i, expression := range s.expressions {
expSql, expArgs := expression.ToSql()
sql[i] = expSql
arguments = append(arguments, expArgs...)
}
sql[0] = s.prefix + sql[0]
sql[len(sql) - 1] = sql[len(sql) - 1] + s.suffix
return strings.Join(sql, s.sep), arguments
}
func G(components ...interface{}) Expression {
return F("(1 2)", components...)
}
func And(components ...interface{}) Expression {
return F("(1 AND 2)", components...)
}
func Or(components ...interface{}) Expression {
return F("(1 OR 2)", components...)
}
func Not(exp interface{}) Expression {
return F("NOT 12", exp)
}
// sep format, like dateformatter, we use magic numbers to split
// (1,2) => prefix:( sep:, suffix:)
// 1,2 => prefix: sep:, suffix:
// If the sep has three letters, then the first is prefix, last is suffix and middle is the sep
func F(sepFormat string, components ...interface{}) Expression {
var prefix, sep, suffix string
formatComponents := strings.Split(sepFormat, "1")
prefix = formatComponents[0]
secondHalfComponents := strings.Split(formatComponents[1], "2")
sep = secondHalfComponents[0]
suffix = secondHalfComponents[1]
return formatter{
// When expression passed in as [[1,2,3]], we prefer it converts to [1,2,3]
expressions: componentsToExpressions(components),
prefix: prefix,
sep: sep,
suffix: suffix,
}
}
func Build(expressions ...interface{}) (string, []interface{}) {
sql, args := Exp(expressions...).ToSql()
return sql, args
}
// Convert all components to Value expression
// E.g, 1 => 1
// "what" => "?" args: "what"
// Time => "?" args: "Time"
func P(components ...interface{}) []Expression {
components = flat([]interface{}{}, components)
expressions := make([]Expression, len(components))
for i := 0; i < len(components); i++ {
c := components[i]
var exp Expression
switch v := c.(type) {
case Expression:
exp = v
case string, *string, []byte, time.Time, *[]byte, *time.Time:
exp = NewRaw("?", v)
default:
exp = NewRaw(fmt.Sprintf("%v", deRef(v)))
}
expressions[i] = exp
}
return expressions
}
// Exp("SELECT", "a, b", "FROM", tableName) => "SELECT a, b FROM table". Use space to join all expressions
func Exp(components ...interface{}) Expression {
return F("1 2", components...)
}
// Apply to non-value sql expression. convert arbitrary types to string and arguments
func componentsToExpressions(components []interface{}) []Expression {
expressions := []Expression{}
for _, component := range components {
if v, ok := component.([]Expression); ok {
expressions = append(expressions, v...)
} else {
flatted := flat(make([]interface{}, 0), component)
for i := 0; i < len(flatted); i++ {
c := flatted[i]
var exp Expression
switch v := c.(type) {
case Expression:
exp = v
case string:
exp = NewRaw(v)
case *string:
exp = NewRaw(*v)
case []byte, time.Time, *[]byte, *time.Time:
exp = NewRaw("?", c)
default:
exp = NewRaw(fmt.Sprintf("%v", deRef(v)))
}
expressions = append(expressions, exp)
}
}
}
return expressions
}