Skip to content

Commit 15280ec

Browse files
authored
Merge pull request #116 from huandu/feature-generate-sql-only-when-value-is-set
Fix #115: Generate SQL only when necessary values are set
2 parents 20d1fd8 + a7c8a3c commit 15280ec

File tree

12 files changed

+190
-108
lines changed

12 files changed

+190
-108
lines changed

args.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func (args *Args) Compile(format string, initialValue ...interface{}) (query str
9797
//
9898
// See doc for `Compile` to learn details.
9999
func (args *Args) CompileWithFlavor(format string, flavor Flavor, initialValue ...interface{}) (query string, values []interface{}) {
100-
buf := &strings.Builder{}
100+
buf := newStringBuilder()
101101
idx := strings.IndexRune(format, '$')
102102
offset := 0
103103
values = initialValue
@@ -160,7 +160,7 @@ func (args *Args) CompileWithFlavor(format string, flavor Flavor, initialValue .
160160
return
161161
}
162162

163-
func (args *Args) compileNamed(buf *strings.Builder, flavor Flavor, format string, values []interface{}) (string, []interface{}) {
163+
func (args *Args) compileNamed(buf *stringBuilder, flavor Flavor, format string, values []interface{}) (string, []interface{}) {
164164
i := 1
165165

166166
for ; i < len(format) && format[i] != '}'; i++ {
@@ -182,7 +182,7 @@ func (args *Args) compileNamed(buf *strings.Builder, flavor Flavor, format strin
182182
return format, values
183183
}
184184

185-
func (args *Args) compileDigits(buf *strings.Builder, flavor Flavor, format string, values []interface{}, offset int) (string, []interface{}, int) {
185+
func (args *Args) compileDigits(buf *stringBuilder, flavor Flavor, format string, values []interface{}, offset int) (string, []interface{}, int) {
186186
i := 1
187187

188188
for ; i < len(format) && '0' <= format[i] && format[i] <= '9'; i++ {
@@ -199,7 +199,7 @@ func (args *Args) compileDigits(buf *strings.Builder, flavor Flavor, format stri
199199
return format, values, offset
200200
}
201201

202-
func (args *Args) compileSuccessive(buf *strings.Builder, flavor Flavor, format string, values []interface{}, offset int) (string, []interface{}, int) {
202+
func (args *Args) compileSuccessive(buf *stringBuilder, flavor Flavor, format string, values []interface{}, offset int) (string, []interface{}, int) {
203203
if offset >= len(args.args) {
204204
return format, values, offset
205205
}
@@ -210,7 +210,7 @@ func (args *Args) compileSuccessive(buf *strings.Builder, flavor Flavor, format
210210
return format, values, offset + 1
211211
}
212212

213-
func (args *Args) compileArg(buf *strings.Builder, flavor Flavor, values []interface{}, arg interface{}) []interface{} {
213+
func (args *Args) compileArg(buf *stringBuilder, flavor Flavor, values []interface{}, arg interface{}) []interface{} {
214214
switch a := arg.(type) {
215215
case Builder:
216216
var s string

cond.go

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type Cond struct {
1414

1515
// Equal represents "field = value".
1616
func (c *Cond) Equal(field string, value interface{}) string {
17-
buf := &strings.Builder{}
17+
buf := newStringBuilder()
1818
buf.WriteString(Escape(field))
1919
buf.WriteString(" = ")
2020
buf.WriteString(c.Args.Add(value))
@@ -28,7 +28,7 @@ func (c *Cond) E(field string, value interface{}) string {
2828

2929
// NotEqual represents "field <> value".
3030
func (c *Cond) NotEqual(field string, value interface{}) string {
31-
buf := &strings.Builder{}
31+
buf := newStringBuilder()
3232
buf.WriteString(Escape(field))
3333
buf.WriteString(" <> ")
3434
buf.WriteString(c.Args.Add(value))
@@ -42,7 +42,7 @@ func (c *Cond) NE(field string, value interface{}) string {
4242

4343
// GreaterThan represents "field > value".
4444
func (c *Cond) GreaterThan(field string, value interface{}) string {
45-
buf := &strings.Builder{}
45+
buf := newStringBuilder()
4646
buf.WriteString(Escape(field))
4747
buf.WriteString(" > ")
4848
buf.WriteString(c.Args.Add(value))
@@ -56,7 +56,7 @@ func (c *Cond) G(field string, value interface{}) string {
5656

5757
// GreaterEqualThan represents "field >= value".
5858
func (c *Cond) GreaterEqualThan(field string, value interface{}) string {
59-
buf := &strings.Builder{}
59+
buf := newStringBuilder()
6060
buf.WriteString(Escape(field))
6161
buf.WriteString(" >= ")
6262
buf.WriteString(c.Args.Add(value))
@@ -70,7 +70,7 @@ func (c *Cond) GE(field string, value interface{}) string {
7070

7171
// LessThan represents "field < value".
7272
func (c *Cond) LessThan(field string, value interface{}) string {
73-
buf := &strings.Builder{}
73+
buf := newStringBuilder()
7474
buf.WriteString(Escape(field))
7575
buf.WriteString(" < ")
7676
buf.WriteString(c.Args.Add(value))
@@ -84,7 +84,7 @@ func (c *Cond) L(field string, value interface{}) string {
8484

8585
// LessEqualThan represents "field <= value".
8686
func (c *Cond) LessEqualThan(field string, value interface{}) string {
87-
buf := &strings.Builder{}
87+
buf := newStringBuilder()
8888
buf.WriteString(Escape(field))
8989
buf.WriteString(" <= ")
9090
buf.WriteString(c.Args.Add(value))
@@ -104,7 +104,7 @@ func (c *Cond) In(field string, value ...interface{}) string {
104104
vs = append(vs, c.Args.Add(v))
105105
}
106106

107-
buf := &strings.Builder{}
107+
buf := newStringBuilder()
108108
buf.WriteString(Escape(field))
109109
buf.WriteString(" IN (")
110110
buf.WriteString(strings.Join(vs, ", "))
@@ -120,7 +120,7 @@ func (c *Cond) NotIn(field string, value ...interface{}) string {
120120
vs = append(vs, c.Args.Add(v))
121121
}
122122

123-
buf := &strings.Builder{}
123+
buf := newStringBuilder()
124124
buf.WriteString(Escape(field))
125125
buf.WriteString(" NOT IN (")
126126
buf.WriteString(strings.Join(vs, ", "))
@@ -130,7 +130,7 @@ func (c *Cond) NotIn(field string, value ...interface{}) string {
130130

131131
// Like represents "field LIKE value".
132132
func (c *Cond) Like(field string, value interface{}) string {
133-
buf := &strings.Builder{}
133+
buf := newStringBuilder()
134134
buf.WriteString(Escape(field))
135135
buf.WriteString(" LIKE ")
136136
buf.WriteString(c.Args.Add(value))
@@ -139,7 +139,7 @@ func (c *Cond) Like(field string, value interface{}) string {
139139

140140
// NotLike represents "field NOT LIKE value".
141141
func (c *Cond) NotLike(field string, value interface{}) string {
142-
buf := &strings.Builder{}
142+
buf := newStringBuilder()
143143
buf.WriteString(Escape(field))
144144
buf.WriteString(" NOT LIKE ")
145145
buf.WriteString(c.Args.Add(value))
@@ -148,23 +148,23 @@ func (c *Cond) NotLike(field string, value interface{}) string {
148148

149149
// IsNull represents "field IS NULL".
150150
func (c *Cond) IsNull(field string) string {
151-
buf := &strings.Builder{}
151+
buf := newStringBuilder()
152152
buf.WriteString(Escape(field))
153153
buf.WriteString(" IS NULL")
154154
return buf.String()
155155
}
156156

157157
// IsNotNull represents "field IS NOT NULL".
158158
func (c *Cond) IsNotNull(field string) string {
159-
buf := &strings.Builder{}
159+
buf := newStringBuilder()
160160
buf.WriteString(Escape(field))
161161
buf.WriteString(" IS NOT NULL")
162162
return buf.String()
163163
}
164164

165165
// Between represents "field BETWEEN lower AND upper".
166166
func (c *Cond) Between(field string, lower, upper interface{}) string {
167-
buf := &strings.Builder{}
167+
buf := newStringBuilder()
168168
buf.WriteString(Escape(field))
169169
buf.WriteString(" BETWEEN ")
170170
buf.WriteString(c.Args.Add(lower))
@@ -175,7 +175,7 @@ func (c *Cond) Between(field string, lower, upper interface{}) string {
175175

176176
// NotBetween represents "field NOT BETWEEN lower AND upper".
177177
func (c *Cond) NotBetween(field string, lower, upper interface{}) string {
178-
buf := &strings.Builder{}
178+
buf := newStringBuilder()
179179
buf.WriteString(Escape(field))
180180
buf.WriteString(" NOT BETWEEN ")
181181
buf.WriteString(c.Args.Add(lower))
@@ -186,7 +186,7 @@ func (c *Cond) NotBetween(field string, lower, upper interface{}) string {
186186

187187
// Or represents OR logic like "expr1 OR expr2 OR expr3".
188188
func (c *Cond) Or(orExpr ...string) string {
189-
buf := &strings.Builder{}
189+
buf := newStringBuilder()
190190
buf.WriteString("(")
191191
buf.WriteString(strings.Join(orExpr, " OR "))
192192
buf.WriteString(")")
@@ -195,7 +195,7 @@ func (c *Cond) Or(orExpr ...string) string {
195195

196196
// And represents AND logic like "expr1 AND expr2 AND expr3".
197197
func (c *Cond) And(andExpr ...string) string {
198-
buf := &strings.Builder{}
198+
buf := newStringBuilder()
199199
buf.WriteString("(")
200200
buf.WriteString(strings.Join(andExpr, " AND "))
201201
buf.WriteString(")")
@@ -204,7 +204,7 @@ func (c *Cond) And(andExpr ...string) string {
204204

205205
// Exists represents "EXISTS (subquery)".
206206
func (c *Cond) Exists(subquery interface{}) string {
207-
buf := &strings.Builder{}
207+
buf := newStringBuilder()
208208
buf.WriteString("EXISTS (")
209209
buf.WriteString(c.Args.Add(subquery))
210210
buf.WriteString(")")
@@ -213,7 +213,7 @@ func (c *Cond) Exists(subquery interface{}) string {
213213

214214
// NotExists represents "NOT EXISTS (subquery)".
215215
func (c *Cond) NotExists(subquery interface{}) string {
216-
buf := &strings.Builder{}
216+
buf := newStringBuilder()
217217
buf.WriteString("NOT EXISTS (")
218218
buf.WriteString(c.Args.Add(subquery))
219219
buf.WriteString(")")
@@ -228,7 +228,7 @@ func (c *Cond) Any(field, op string, value ...interface{}) string {
228228
vs = append(vs, c.Args.Add(v))
229229
}
230230

231-
buf := &strings.Builder{}
231+
buf := newStringBuilder()
232232
buf.WriteString(Escape(field))
233233
buf.WriteString(" ")
234234
buf.WriteString(op)
@@ -246,7 +246,7 @@ func (c *Cond) All(field, op string, value ...interface{}) string {
246246
vs = append(vs, c.Args.Add(v))
247247
}
248248

249-
buf := &strings.Builder{}
249+
buf := newStringBuilder()
250250
buf.WriteString(Escape(field))
251251
buf.WriteString(" ")
252252
buf.WriteString(op)
@@ -264,7 +264,7 @@ func (c *Cond) Some(field, op string, value ...interface{}) string {
264264
vs = append(vs, c.Args.Add(v))
265265
}
266266

267-
buf := &strings.Builder{}
267+
buf := newStringBuilder()
268268
buf.WriteString(Escape(field))
269269
buf.WriteString(" ")
270270
buf.WriteString(op)

createtable.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,20 +100,25 @@ func (ctb *CreateTableBuilder) Build() (sql string, args []interface{}) {
100100
// BuildWithFlavor returns compiled CREATE TABLE string and args with flavor and initial args.
101101
// They can be used in `DB#Query` of package `database/sql` directly.
102102
func (ctb *CreateTableBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
103-
buf := &strings.Builder{}
103+
buf := newStringBuilder()
104104
ctb.injection.WriteTo(buf, createTableMarkerInit)
105-
buf.WriteString(ctb.verb)
105+
106+
if len(ctb.verb) > 0 {
107+
buf.WriteLeadingString(ctb.verb)
108+
}
106109

107110
if ctb.ifNotExists {
108-
buf.WriteString(" IF NOT EXISTS")
111+
buf.WriteLeadingString("IF NOT EXISTS")
112+
}
113+
114+
if len(ctb.table) > 0 {
115+
buf.WriteLeadingString(ctb.table)
109116
}
110117

111-
buf.WriteRune(' ')
112-
buf.WriteString(ctb.table)
113118
ctb.injection.WriteTo(buf, createTableMarkerAfterCreate)
114119

115120
if len(ctb.defs) > 0 {
116-
buf.WriteString(" (")
121+
buf.WriteLeadingString("(")
117122

118123
defs := make([]string, 0, len(ctb.defs))
119124

@@ -128,15 +133,13 @@ func (ctb *CreateTableBuilder) BuildWithFlavor(flavor Flavor, initialArg ...inte
128133
}
129134

130135
if len(ctb.options) > 0 {
131-
buf.WriteRune(' ')
132-
133136
opts := make([]string, 0, len(ctb.options))
134137

135138
for _, opt := range ctb.options {
136139
opts = append(opts, strings.Join(opt, " "))
137140
}
138141

139-
buf.WriteString(strings.Join(opts, ", "))
142+
buf.WriteLeadingString(strings.Join(opts, ", "))
140143
ctb.injection.WriteTo(buf, createTableMarkerAfterOption)
141144
}
142145

delete.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,21 +113,25 @@ func (db *DeleteBuilder) Build() (sql string, args []interface{}) {
113113
// BuildWithFlavor returns compiled DELETE string and args with flavor and initial args.
114114
// They can be used in `DB#Query` of package `database/sql` directly.
115115
func (db *DeleteBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
116-
buf := &strings.Builder{}
116+
buf := newStringBuilder()
117117
db.injection.WriteTo(buf, deleteMarkerInit)
118-
buf.WriteString("DELETE FROM ")
119-
buf.WriteString(db.table)
118+
119+
if len(db.table) > 0 {
120+
buf.WriteLeadingString("DELETE FROM ")
121+
buf.WriteString(db.table)
122+
}
123+
120124
db.injection.WriteTo(buf, deleteMarkerAfterDeleteFrom)
121125

122126
if len(db.whereExprs) > 0 {
123-
buf.WriteString(" WHERE ")
127+
buf.WriteLeadingString("WHERE ")
124128
buf.WriteString(strings.Join(db.whereExprs, " AND "))
125129

126130
db.injection.WriteTo(buf, deleteMarkerAfterWhere)
127131
}
128132

129133
if len(db.orderByCols) > 0 {
130-
buf.WriteString(" ORDER BY ")
134+
buf.WriteLeadingString("ORDER BY ")
131135
buf.WriteString(strings.Join(db.orderByCols, ", "))
132136

133137
if db.order != "" {
@@ -139,7 +143,7 @@ func (db *DeleteBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
139143
}
140144

141145
if db.limit >= 0 {
142-
buf.WriteString(" LIMIT ")
146+
buf.WriteLeadingString("LIMIT ")
143147
buf.WriteString(strconv.Itoa(db.limit))
144148

145149
db.injection.WriteTo(buf, deleteMarkerAfterLimit)

injection.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,13 @@ func (injection *injection) SQL(marker injectionMarker, sql string) {
2929

3030
// WriteTo joins all SQL strings at the same marker value with blank (" ")
3131
// and writes the joined value to buf.
32-
func (injection *injection) WriteTo(buf *strings.Builder, marker injectionMarker) {
32+
func (injection *injection) WriteTo(buf *stringBuilder, marker injectionMarker) {
3333
sqls := injection.markerSQLs[marker]
34-
notEmpty := buf.Len() > 0
3534

3635
if len(sqls) == 0 {
3736
return
3837
}
3938

40-
if notEmpty {
41-
buf.WriteRune(' ')
42-
}
43-
4439
s := strings.Join(sqls, " ")
45-
buf.WriteString(s)
46-
47-
if !notEmpty {
48-
buf.WriteRune(' ')
49-
}
40+
buf.WriteLeadingString(s)
5041
}

insert.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,29 +117,36 @@ func (ib *InsertBuilder) Build() (sql string, args []interface{}) {
117117
// BuildWithFlavor returns compiled INSERT string and args with flavor and initial args.
118118
// They can be used in `DB#Query` of package `database/sql` directly.
119119
func (ib *InsertBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
120-
buf := &strings.Builder{}
120+
buf := newStringBuilder()
121121
ib.injection.WriteTo(buf, insertMarkerInit)
122-
buf.WriteString(ib.verb)
123-
buf.WriteString(" INTO ")
124-
buf.WriteString(ib.table)
122+
123+
if len(ib.table) > 0 {
124+
buf.WriteLeadingString(ib.verb)
125+
buf.WriteString(" INTO ")
126+
buf.WriteString(ib.table)
127+
}
128+
125129
ib.injection.WriteTo(buf, insertMarkerAfterInsertInto)
126130

127131
if len(ib.cols) > 0 {
128-
buf.WriteString(" (")
132+
buf.WriteLeadingString("(")
129133
buf.WriteString(strings.Join(ib.cols, ", "))
130134
buf.WriteString(")")
131135

132136
ib.injection.WriteTo(buf, insertMarkerAfterCols)
133137
}
134138

135-
buf.WriteString(" VALUES ")
136-
values := make([]string, 0, len(ib.values))
139+
if len(ib.values) > 0 {
140+
buf.WriteLeadingString("VALUES ")
141+
values := make([]string, 0, len(ib.values))
142+
143+
for _, v := range ib.values {
144+
values = append(values, fmt.Sprintf("(%v)", strings.Join(v, ", ")))
145+
}
137146

138-
for _, v := range ib.values {
139-
values = append(values, fmt.Sprintf("(%v)", strings.Join(v, ", ")))
147+
buf.WriteString(strings.Join(values, ", "))
140148
}
141149

142-
buf.WriteString(strings.Join(values, ", "))
143150
ib.injection.WriteTo(buf, insertMarkerAfterValues)
144151

145152
return ib.args.CompileWithFlavor(buf.String(), flavor, initialArg...)

0 commit comments

Comments
 (0)