-
Notifications
You must be signed in to change notification settings - Fork 1
/
serializer.go
192 lines (152 loc) · 4.47 KB
/
serializer.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
package sqlbuilder
import (
"strings"
)
type Serializer struct {
d Dialect
bits []string
vals []*BoundVariable
vpos map[*BoundVariable]int
}
func NewSerializer(d Dialect) *Serializer {
return &Serializer{
d: d,
vpos: make(map[*BoundVariable]int),
}
}
type BoundVariable struct {
value interface{}
}
func Bind(value interface{}) *BoundVariable {
return &BoundVariable{value: value}
}
// BindAllAsExpr binds multiple variables at once, returning them as []AsExpr.
// This is most useful for In and NotIn conditions.
func BindAllAsExpr(vals ...interface{}) []AsExpr {
l := make([]AsExpr, len(vals))
for i, val := range vals {
l[i] = Bind(val)
}
return l
}
// BindAllStringsAsExpr binds multiple variables at once, returning them as
// []AsExpr. This is most useful for In and NotIn conditions.
func BindAllStringsAsExpr(vals ...string) []AsExpr {
l := make([]AsExpr, len(vals))
for i, val := range vals {
l[i] = Bind(val)
}
return l
}
// BindAllIntsAsExpr binds multiple variables at once, returning them as
// []AsExpr. This is most useful for In and NotIn conditions.
func BindAllIntsAsExpr(vals ...int) []AsExpr {
l := make([]AsExpr, len(vals))
for i, val := range vals {
l[i] = Bind(val)
}
return l
}
func (b *BoundVariable) AsExpr(s *Serializer) {
s.V(b)
}
func (b *BoundVariable) As(alias string) *ColumnAlias {
return AliasColumn(b, alias)
}
// Bind binds a variable to this serializer - this can be used for e.g.
// symbolic representation of user input.
func (s *Serializer) Bind(val interface{}) *BoundVariable {
b, ok := val.(*BoundVariable)
if !ok {
b = Bind(val)
}
if _, ok := s.vpos[b]; !ok {
s.vals = append(s.vals, b)
s.vpos[b] = len(s.vals)
}
return b
}
// BindAllAsExpr binds multiple variables to this serializer at once,
// returning them as []AsExpr. This is most useful for In and NotIn
// conditions.
func (s *Serializer) BindAllAsExpr(vals ...interface{}) []AsExpr {
l := make([]AsExpr, len(vals))
for i, val := range vals {
l[i] = s.Bind(val)
}
return l
}
// BindAllStringsAsExpr binds multiple variables to this serializer at once,
// returning them as []AsExpr. This is most useful for In and NotIn
// conditions.
func (s *Serializer) BindAllStringsAsExpr(vals ...string) []AsExpr {
l := make([]AsExpr, len(vals))
for i, val := range vals {
l[i] = s.Bind(val)
}
return l
}
// BindAllIntsAsExpr binds multiple variables to this serializer at once,
// returning them as []AsExpr. This is most useful for In and NotIn
// conditions.
func (s *Serializer) BindAllIntsAsExpr(vals ...int) []AsExpr {
l := make([]AsExpr, len(vals))
for i, val := range vals {
l[i] = s.Bind(val)
}
return l
}
// SetDialect sets the dialect for this serializer
func (s *Serializer) SetDialect(d Dialect) {
s.d = d
}
// ToSQL serializes the whole query, returning the query itself and any
// variables requred to execute it
func (s *Serializer) ToSQL() (string, []interface{}, error) {
var vars []interface{}
for _, v := range s.vals {
vars = append(vars, v.value)
}
return strings.Join(s.bits, ""), vars, nil
}
// N adds a "name" value to the query, which should be quoted as per the
// dialect
func (s *Serializer) N(name string) *Serializer { return s.NC(name, true) }
// NC adds a "name" value to the query, which should be quoted as per the
// dialect, only if "w" is true
func (s *Serializer) NC(name string, w bool) *Serializer {
if w {
s.bits = append(s.bits, dialect(s.d).QuoteName(name))
}
return s
}
// D adds string data to the query
func (s *Serializer) D(data string) *Serializer { return s.DC(data, true) }
// DC adds string data to the query, only if "w" is true
func (s *Serializer) DC(data string, w bool) *Serializer {
if w {
s.bits = append(s.bits, data)
}
return s
}
// V adds a value to the query, where the value should be replaced with a
// placeholder
func (s *Serializer) V(val interface{}) *Serializer { return s.VC(val, true) }
// VC adds a value to the query, where the value should be replaced with a
// placeholder, only if "w" is true
func (s *Serializer) VC(val interface{}, w bool) *Serializer {
if w {
s.bits = append(s.bits, dialect(s.d).Bind(s.vpos[s.Bind(val)]))
}
return s
}
// F runs a function taking the Serializer as its only argument
func (s *Serializer) F(f func(s *Serializer)) *Serializer { return s.FC(f, true) }
// FC runs a function taking the Serializer as its only argument, only if "w"
// is true
func (s *Serializer) FC(f func(s *Serializer), w bool) *Serializer {
if w {
f(s)
}
return s
}