• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

huandu / go-sqlbuilder / 13257642920

11 Feb 2025 07:10AM UTC coverage: 96.743% (-0.1%) from 96.879%
13257642920

push

github

web-flow
Merge pull request #190 from huandu/feature/prevent-syntax-error-with-zero-values

Ignore empty values and expressions to prevent syntax error

44 of 46 new or added lines in 5 files covered. (95.65%)

4 existing lines in 1 file now uncovered.

3475 of 3592 relevant lines covered (96.74%)

1.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.06
/cond.go
1
// Copyright 2018 Huan Du. All rights reserved.
2
// Licensed under the MIT license that can be found in the LICENSE file.
3

4
package sqlbuilder
5

6
const (
7
        lparen = "("
8
        rparen = ")"
9
        opOR   = " OR "
10
        opAND  = " AND "
11
        opNOT  = "NOT "
12
)
13

14
const minIndexBase = 256
15

16
// Cond provides several helper methods to build conditions.
17
type Cond struct {
18
        Args *Args
19
}
20

21
// NewCond returns a new Cond.
22
func NewCond() *Cond {
1✔
23
        return &Cond{
1✔
24
                Args: &Args{
1✔
25
                        // Based on the discussion in #174, users may call this method to create
1✔
26
                        // `Cond` for building various conditions, which is a misuse, but we
1✔
27
                        // cannot completely prevent this error. To facilitate users in
1✔
28
                        // identifying the issue when they make mistakes and to avoid
1✔
29
                        // unexpected stackoverflows, the base index for `Args` is
1✔
30
                        // deliberately set to a larger non-zero value here. This can
1✔
31
                        // significantly reduce the likelihood of issues and allows for
1✔
32
                        // timely error notification to users.
1✔
33
                        indexBase: minIndexBase,
1✔
34
                },
1✔
35
        }
1✔
36
}
1✔
37

38
// Equal is used to construct the expression "field = value".
39
func (c *Cond) Equal(field string, value interface{}) string {
1✔
40
        if len(field) == 0 {
2✔
41
                return ""
1✔
42
        }
1✔
43

44
        return c.Var(condBuilder{
1✔
45
                Builder: func(ctx *argsCompileContext) {
2✔
46
                        ctx.WriteString(field)
1✔
47
                        ctx.WriteString(" = ")
1✔
48
                        ctx.WriteValue(value)
1✔
49
                },
1✔
50
        })
51
}
52

53
// E is an alias of Equal.
54
func (c *Cond) E(field string, value interface{}) string {
1✔
55
        return c.Equal(field, value)
1✔
56
}
1✔
57

58
// EQ is an alias of Equal.
59
func (c *Cond) EQ(field string, value interface{}) string {
1✔
60
        return c.Equal(field, value)
1✔
61
}
1✔
62

63
// NotEqual is used to construct the expression "field <> value".
64
func (c *Cond) NotEqual(field string, value interface{}) string {
1✔
65
        if len(field) == 0 {
2✔
66
                return ""
1✔
67
        }
1✔
68

69
        return c.Var(condBuilder{
1✔
70
                Builder: func(ctx *argsCompileContext) {
2✔
71
                        ctx.WriteString(field)
1✔
72
                        ctx.WriteString(" <> ")
1✔
73
                        ctx.WriteValue(value)
1✔
74
                },
1✔
75
        })
76
}
77

78
// NE is an alias of NotEqual.
79
func (c *Cond) NE(field string, value interface{}) string {
1✔
80
        return c.NotEqual(field, value)
1✔
81
}
1✔
82

83
// NEQ is an alias of NotEqual.
84
func (c *Cond) NEQ(field string, value interface{}) string {
1✔
85
        return c.NotEqual(field, value)
1✔
86
}
1✔
87

88
// GreaterThan is used to construct the expression "field > value".
89
func (c *Cond) GreaterThan(field string, value interface{}) string {
1✔
90
        if len(field) == 0 {
2✔
91
                return ""
1✔
92
        }
1✔
93

94
        return c.Var(condBuilder{
1✔
95
                Builder: func(ctx *argsCompileContext) {
2✔
96
                        ctx.WriteString(field)
1✔
97
                        ctx.WriteString(" > ")
1✔
98
                        ctx.WriteValue(value)
1✔
99
                },
1✔
100
        })
101
}
102

103
// G is an alias of GreaterThan.
104
func (c *Cond) G(field string, value interface{}) string {
1✔
105
        return c.GreaterThan(field, value)
1✔
106
}
1✔
107

108
// GT is an alias of GreaterThan.
109
func (c *Cond) GT(field string, value interface{}) string {
1✔
110
        return c.GreaterThan(field, value)
1✔
111
}
1✔
112

113
// GreaterEqualThan is used to construct the expression "field >= value".
114
func (c *Cond) GreaterEqualThan(field string, value interface{}) string {
1✔
115
        if len(field) == 0 {
2✔
116
                return ""
1✔
117
        }
1✔
118

119
        return c.Var(condBuilder{
1✔
120
                Builder: func(ctx *argsCompileContext) {
2✔
121
                        ctx.WriteString(field)
1✔
122
                        ctx.WriteString(" >= ")
1✔
123
                        ctx.WriteValue(value)
1✔
124
                },
1✔
125
        })
126
}
127

128
// GE is an alias of GreaterEqualThan.
129
func (c *Cond) GE(field string, value interface{}) string {
1✔
130
        return c.GreaterEqualThan(field, value)
1✔
131
}
1✔
132

133
// GTE is an alias of GreaterEqualThan.
134
func (c *Cond) GTE(field string, value interface{}) string {
1✔
135
        return c.GreaterEqualThan(field, value)
1✔
136
}
1✔
137

138
// LessThan is used to construct the expression "field < value".
139
func (c *Cond) LessThan(field string, value interface{}) string {
1✔
140
        if len(field) == 0 {
2✔
141
                return ""
1✔
142
        }
1✔
143

144
        return c.Var(condBuilder{
1✔
145
                Builder: func(ctx *argsCompileContext) {
2✔
146
                        ctx.WriteString(field)
1✔
147
                        ctx.WriteString(" < ")
1✔
148
                        ctx.WriteValue(value)
1✔
149
                },
1✔
150
        })
151
}
152

153
// L is an alias of LessThan.
154
func (c *Cond) L(field string, value interface{}) string {
1✔
155
        return c.LessThan(field, value)
1✔
156
}
1✔
157

158
// LT is an alias of LessThan.
159
func (c *Cond) LT(field string, value interface{}) string {
1✔
160
        return c.LessThan(field, value)
1✔
161
}
1✔
162

163
// LessEqualThan is used to construct the expression "field <= value".
164
func (c *Cond) LessEqualThan(field string, value interface{}) string {
1✔
165
        if len(field) == 0 {
2✔
166
                return ""
1✔
167
        }
1✔
168
        return c.Var(condBuilder{
1✔
169
                Builder: func(ctx *argsCompileContext) {
2✔
170
                        ctx.WriteString(field)
1✔
171
                        ctx.WriteString(" <= ")
1✔
172
                        ctx.WriteValue(value)
1✔
173
                },
1✔
174
        })
175
}
176

177
// LE is an alias of LessEqualThan.
178
func (c *Cond) LE(field string, value interface{}) string {
1✔
179
        return c.LessEqualThan(field, value)
1✔
180
}
1✔
181

182
// LTE is an alias of LessEqualThan.
183
func (c *Cond) LTE(field string, value interface{}) string {
1✔
184
        return c.LessEqualThan(field, value)
1✔
185
}
1✔
186

187
// In is used to construct the expression "field IN (value...)".
188
func (c *Cond) In(field string, values ...interface{}) string {
1✔
189
        if len(field) == 0 {
2✔
190
                return ""
1✔
191
        }
1✔
192

193
        // Empty values means "false".
194
        if len(values) == 0 {
2✔
195
                return "0 = 1"
1✔
196
        }
1✔
197

198
        return c.Var(condBuilder{
1✔
199
                Builder: func(ctx *argsCompileContext) {
2✔
200
                        ctx.WriteString(field)
1✔
201
                        ctx.WriteString(" IN (")
1✔
202
                        ctx.WriteValues(values, ", ")
1✔
203
                        ctx.WriteString(")")
1✔
204
                },
1✔
205
        })
206
}
207

208
// NotIn is used to construct the expression "field NOT IN (value...)".
209
func (c *Cond) NotIn(field string, values ...interface{}) string {
1✔
210
        if len(field) == 0 || len(values) == 0 {
2✔
211
                return ""
1✔
212
        }
1✔
213

214
        return c.Var(condBuilder{
1✔
215
                Builder: func(ctx *argsCompileContext) {
2✔
216
                        ctx.WriteString(field)
1✔
217
                        ctx.WriteString(" NOT IN (")
1✔
218
                        ctx.WriteValues(values, ", ")
1✔
219
                        ctx.WriteString(")")
1✔
220
                },
1✔
221
        })
222
}
223

224
// Like is used to construct the expression "field LIKE value".
225
func (c *Cond) Like(field string, value interface{}) string {
1✔
226
        if len(field) == 0 {
2✔
227
                return ""
1✔
228
        }
1✔
229

230
        return c.Var(condBuilder{
1✔
231
                Builder: func(ctx *argsCompileContext) {
2✔
232
                        ctx.WriteString(field)
1✔
233
                        ctx.WriteString(" LIKE ")
1✔
234
                        ctx.WriteValue(value)
1✔
235
                },
1✔
236
        })
237
}
238

239
// ILike is used to construct the expression "field ILIKE value".
240
//
241
// When the database system does not support the ILIKE operator,
242
// the ILike method will return "LOWER(field) LIKE LOWER(value)"
243
// to simulate the behavior of the ILIKE operator.
244
func (c *Cond) ILike(field string, value interface{}) string {
1✔
245
        if len(field) == 0 {
2✔
246
                return ""
1✔
247
        }
1✔
248

249
        return c.Var(condBuilder{
1✔
250
                Builder: func(ctx *argsCompileContext) {
2✔
251
                        switch ctx.Flavor {
1✔
252
                        case PostgreSQL, SQLite:
1✔
253
                                ctx.WriteString(field)
1✔
254
                                ctx.WriteString(" ILIKE ")
1✔
255
                                ctx.WriteValue(value)
1✔
256

257
                        default:
1✔
258
                                // Use LOWER to simulate ILIKE.
1✔
259
                                ctx.WriteString("LOWER(")
1✔
260
                                ctx.WriteString(field)
1✔
261
                                ctx.WriteString(") LIKE LOWER(")
1✔
262
                                ctx.WriteValue(value)
1✔
263
                                ctx.WriteString(")")
1✔
264
                        }
265
                },
266
        })
267
}
268

269
// NotLike is used to construct the expression "field NOT LIKE value".
270
func (c *Cond) NotLike(field string, value interface{}) string {
1✔
271
        if len(field) == 0 {
2✔
272
                return ""
1✔
273
        }
1✔
274

275
        return c.Var(condBuilder{
1✔
276
                Builder: func(ctx *argsCompileContext) {
2✔
277
                        ctx.WriteString(field)
1✔
278
                        ctx.WriteString(" NOT LIKE ")
1✔
279
                        ctx.WriteValue(value)
1✔
280
                },
1✔
281
        })
282
}
283

284
// NotILike is used to construct the expression "field NOT ILIKE value".
285
//
286
// When the database system does not support the ILIKE operator,
287
// the NotILike method will return "LOWER(field) NOT LIKE LOWER(value)"
288
// to simulate the behavior of the ILIKE operator.
289
func (c *Cond) NotILike(field string, value interface{}) string {
1✔
290
        if len(field) == 0 {
2✔
291
                return ""
1✔
292
        }
1✔
293

294
        return c.Var(condBuilder{
1✔
295
                Builder: func(ctx *argsCompileContext) {
2✔
296
                        switch ctx.Flavor {
1✔
297
                        case PostgreSQL, SQLite:
1✔
298
                                ctx.WriteString(field)
1✔
299
                                ctx.WriteString(" NOT ILIKE ")
1✔
300
                                ctx.WriteValue(value)
1✔
301

302
                        default:
1✔
303
                                // Use LOWER to simulate ILIKE.
1✔
304
                                ctx.WriteString("LOWER(")
1✔
305
                                ctx.WriteString(field)
1✔
306
                                ctx.WriteString(") NOT LIKE LOWER(")
1✔
307
                                ctx.WriteValue(value)
1✔
308
                                ctx.WriteString(")")
1✔
309
                        }
310
                },
311
        })
312
}
313

314
// IsNull is used to construct the expression "field IS NULL".
315
func (c *Cond) IsNull(field string) string {
1✔
316
        if len(field) == 0 {
2✔
317
                return ""
1✔
318
        }
1✔
319

320
        return c.Var(condBuilder{
1✔
321
                Builder: func(ctx *argsCompileContext) {
2✔
322
                        ctx.WriteString(field)
1✔
323
                        ctx.WriteString(" IS NULL")
1✔
324
                },
1✔
325
        })
326
}
327

328
// IsNotNull is used to construct the expression "field IS NOT NULL".
329
func (c *Cond) IsNotNull(field string) string {
1✔
330
        if len(field) == 0 {
2✔
331
                return ""
1✔
332
        }
1✔
333
        return c.Var(condBuilder{
1✔
334
                Builder: func(ctx *argsCompileContext) {
2✔
335
                        ctx.WriteString(field)
1✔
336
                        ctx.WriteString(" IS NOT NULL")
1✔
337
                },
1✔
338
        })
339
}
340

341
// Between is used to construct the expression "field BETWEEN lower AND upper".
342
func (c *Cond) Between(field string, lower, upper interface{}) string {
1✔
343
        if len(field) == 0 {
2✔
344
                return ""
1✔
345
        }
1✔
346

347
        return c.Var(condBuilder{
1✔
348
                Builder: func(ctx *argsCompileContext) {
2✔
349
                        ctx.WriteString(field)
1✔
350
                        ctx.WriteString(" BETWEEN ")
1✔
351
                        ctx.WriteValue(lower)
1✔
352
                        ctx.WriteString(" AND ")
1✔
353
                        ctx.WriteValue(upper)
1✔
354
                },
1✔
355
        })
356
}
357

358
// NotBetween is used to construct the expression "field NOT BETWEEN lower AND upper".
359
func (c *Cond) NotBetween(field string, lower, upper interface{}) string {
1✔
360
        if len(field) == 0 {
2✔
361
                return ""
1✔
362
        }
1✔
363

364
        return c.Var(condBuilder{
1✔
365
                Builder: func(ctx *argsCompileContext) {
2✔
366
                        ctx.WriteString(field)
1✔
367
                        ctx.WriteString(" NOT BETWEEN ")
1✔
368
                        ctx.WriteValue(lower)
1✔
369
                        ctx.WriteString(" AND ")
1✔
370
                        ctx.WriteValue(upper)
1✔
371
                },
1✔
372
        })
373
}
374

375
// Or is used to construct the expression OR logic like "expr1 OR expr2 OR expr3".
376
func (c *Cond) Or(orExpr ...string) string {
1✔
377
        orExpr = filterEmptyStrings(orExpr)
1✔
378

1✔
379
        if len(orExpr) == 0 {
2✔
380
                return ""
1✔
381
        }
1✔
382

383
        exprByteLen := estimateStringsBytes(orExpr)
1✔
384
        if exprByteLen == 0 {
1✔
UNCOV
385
                return ""
×
UNCOV
386
        }
×
387

388
        buf := newStringBuilder()
1✔
389

1✔
390
        // Ensure that there is only 1 memory allocation.
1✔
391
        size := len(lparen) + len(rparen) + (len(orExpr)-1)*len(opOR) + exprByteLen
1✔
392
        buf.Grow(size)
1✔
393

1✔
394
        buf.WriteString(lparen)
1✔
395
        buf.WriteStrings(orExpr, opOR)
1✔
396
        buf.WriteString(rparen)
1✔
397
        return buf.String()
1✔
398
}
399

400
// And is used to construct the expression AND logic like "expr1 AND expr2 AND expr3".
401
func (c *Cond) And(andExpr ...string) string {
1✔
402
        andExpr = filterEmptyStrings(andExpr)
1✔
403

1✔
404
        if len(andExpr) == 0 {
2✔
405
                return ""
1✔
406
        }
1✔
407

408
        exprByteLen := estimateStringsBytes(andExpr)
1✔
409
        if exprByteLen == 0 {
1✔
UNCOV
410
                return ""
×
UNCOV
411
        }
×
412

413
        buf := newStringBuilder()
1✔
414

1✔
415
        // Ensure that there is only 1 memory allocation.
1✔
416
        size := len(lparen) + len(rparen) + (len(andExpr)-1)*len(opAND) + exprByteLen
1✔
417
        buf.Grow(size)
1✔
418

1✔
419
        buf.WriteString(lparen)
1✔
420
        buf.WriteStrings(andExpr, opAND)
1✔
421
        buf.WriteString(rparen)
1✔
422
        return buf.String()
1✔
423
}
424

425
// Not is used to construct the expression "NOT expr".
426
func (c *Cond) Not(notExpr string) string {
1✔
427
        if len(notExpr) == 0 {
2✔
428
                return ""
1✔
429
        }
1✔
430
        buf := newStringBuilder()
1✔
431

1✔
432
        // Ensure that there is only 1 memory allocation.
1✔
433
        size := len(opNOT) + len(notExpr)
1✔
434
        buf.Grow(size)
1✔
435

1✔
436
        buf.WriteString(opNOT)
1✔
437
        buf.WriteString(notExpr)
1✔
438
        return buf.String()
1✔
439
}
440

441
// Exists is used to construct the expression "EXISTS (subquery)".
442
func (c *Cond) Exists(subquery interface{}) string {
1✔
443
        return c.Var(condBuilder{
1✔
444
                Builder: func(ctx *argsCompileContext) {
2✔
445
                        ctx.WriteString("EXISTS (")
1✔
446
                        ctx.WriteValue(subquery)
1✔
447
                        ctx.WriteString(")")
1✔
448
                },
1✔
449
        })
450
}
451

452
// NotExists is used to construct the expression "NOT EXISTS (subquery)".
453
func (c *Cond) NotExists(subquery interface{}) string {
1✔
454
        return c.Var(condBuilder{
1✔
455
                Builder: func(ctx *argsCompileContext) {
2✔
456
                        ctx.WriteString("NOT EXISTS (")
1✔
457
                        ctx.WriteValue(subquery)
1✔
458
                        ctx.WriteString(")")
1✔
459
                },
1✔
460
        })
461
}
462

463
// Any is used to construct the expression "field op ANY (value...)".
464
func (c *Cond) Any(field, op string, values ...interface{}) string {
1✔
465
        if len(field) == 0 || len(op) == 0 {
2✔
466
                return ""
1✔
467
        }
1✔
468

469
        // Empty values means "false".
470
        if len(values) == 0 {
2✔
471
                return "0 = 1"
1✔
472
        }
1✔
473

474
        return c.Var(condBuilder{
1✔
475
                Builder: func(ctx *argsCompileContext) {
2✔
476
                        ctx.WriteString(field)
1✔
477
                        ctx.WriteString(" ")
1✔
478
                        ctx.WriteString(op)
1✔
479
                        ctx.WriteString(" ANY (")
1✔
480
                        ctx.WriteValues(values, ", ")
1✔
481
                        ctx.WriteString(")")
1✔
482
                },
1✔
483
        })
484
}
485

486
// All is used to construct the expression "field op ALL (value...)".
487
func (c *Cond) All(field, op string, values ...interface{}) string {
1✔
488
        if len(field) == 0 || len(op) == 0 {
2✔
489
                return ""
1✔
490
        }
1✔
491

492
        // Empty values means "false".
493
        if len(values) == 0 {
2✔
494
                return "0 = 1"
1✔
495
        }
1✔
496

497
        return c.Var(condBuilder{
1✔
498
                Builder: func(ctx *argsCompileContext) {
2✔
499
                        ctx.WriteString(field)
1✔
500
                        ctx.WriteString(" ")
1✔
501
                        ctx.WriteString(op)
1✔
502
                        ctx.WriteString(" ALL (")
1✔
503
                        ctx.WriteValues(values, ", ")
1✔
504
                        ctx.WriteString(")")
1✔
505
                },
1✔
506
        })
507
}
508

509
// Some is used to construct the expression "field op SOME (value...)".
510
func (c *Cond) Some(field, op string, values ...interface{}) string {
1✔
511
        if len(field) == 0 || len(op) == 0 {
2✔
512
                return ""
1✔
513
        }
1✔
514

515
        // Empty values means "false".
516
        if len(values) == 0 {
2✔
517
                return "0 = 1"
1✔
518
        }
1✔
519

520
        return c.Var(condBuilder{
1✔
521
                Builder: func(ctx *argsCompileContext) {
2✔
522
                        ctx.WriteString(field)
1✔
523
                        ctx.WriteString(" ")
1✔
524
                        ctx.WriteString(op)
1✔
525
                        ctx.WriteString(" SOME (")
1✔
526
                        ctx.WriteValues(values, ", ")
1✔
527
                        ctx.WriteString(")")
1✔
528
                },
1✔
529
        })
530
}
531

532
// IsDistinctFrom is used to construct the expression "field IS DISTINCT FROM value".
533
//
534
// When the database system does not support the IS DISTINCT FROM operator,
535
// the NotILike method will return "NOT field <=> value" for MySQL or a
536
// "CASE ... WHEN ... ELSE ... END" expression to simulate the behavior of
537
// the IS DISTINCT FROM operator.
538
func (c *Cond) IsDistinctFrom(field string, value interface{}) string {
1✔
539
        if len(field) == 0 {
2✔
540
                return ""
1✔
541
        }
1✔
542

543
        return c.Var(condBuilder{
1✔
544
                Builder: func(ctx *argsCompileContext) {
2✔
545
                        switch ctx.Flavor {
1✔
546
                        case PostgreSQL, SQLite, SQLServer:
1✔
547
                                ctx.WriteString(field)
1✔
548
                                ctx.WriteString(" IS DISTINCT FROM ")
1✔
549
                                ctx.WriteValue(value)
1✔
550

551
                        case MySQL:
1✔
552
                                ctx.WriteString("NOT ")
1✔
553
                                ctx.WriteString(field)
1✔
554
                                ctx.WriteString(" <=> ")
1✔
555
                                ctx.WriteValue(value)
1✔
556

557
                        default:
1✔
558
                                // CASE
1✔
559
                                //     WHEN field IS NULL AND value IS NULL THEN 0
1✔
560
                                //     WHEN field IS NOT NULL AND value IS NOT NULL AND field = value THEN 0
1✔
561
                                //     ELSE 1
1✔
562
                                // END = 1
1✔
563
                                ctx.WriteString("CASE WHEN ")
1✔
564
                                ctx.WriteString(field)
1✔
565
                                ctx.WriteString(" IS NULL AND ")
1✔
566
                                ctx.WriteValue(value)
1✔
567
                                ctx.WriteString(" IS NULL THEN 0 WHEN ")
1✔
568
                                ctx.WriteString(field)
1✔
569
                                ctx.WriteString(" IS NOT NULL AND ")
1✔
570
                                ctx.WriteValue(value)
1✔
571
                                ctx.WriteString(" IS NOT NULL AND ")
1✔
572
                                ctx.WriteString(field)
1✔
573
                                ctx.WriteString(" = ")
1✔
574
                                ctx.WriteValue(value)
1✔
575
                                ctx.WriteString(" THEN 0 ELSE 1 END = 1")
1✔
576
                        }
577
                },
578
        })
579
}
580

581
// IsNotDistinctFrom is used to construct the expression "field IS NOT DISTINCT FROM value".
582
//
583
// When the database system does not support the IS NOT DISTINCT FROM operator,
584
// the NotILike method will return "field <=> value" for MySQL or a
585
// "CASE ... WHEN ... ELSE ... END" expression to simulate the behavior of
586
// the IS NOT DISTINCT FROM operator.
587
func (c *Cond) IsNotDistinctFrom(field string, value interface{}) string {
1✔
588
        if len(field) == 0 {
2✔
589
                return ""
1✔
590
        }
1✔
591

592
        return c.Var(condBuilder{
1✔
593
                Builder: func(ctx *argsCompileContext) {
2✔
594
                        switch ctx.Flavor {
1✔
595
                        case PostgreSQL, SQLite, SQLServer:
1✔
596
                                ctx.WriteString(field)
1✔
597
                                ctx.WriteString(" IS NOT DISTINCT FROM ")
1✔
598
                                ctx.WriteValue(value)
1✔
599

600
                        case MySQL:
1✔
601
                                ctx.WriteString(field)
1✔
602
                                ctx.WriteString(" <=> ")
1✔
603
                                ctx.WriteValue(value)
1✔
604

605
                        default:
1✔
606
                                // CASE
1✔
607
                                //     WHEN field IS NULL AND value IS NULL THEN 1
1✔
608
                                //     WHEN field IS NOT NULL AND value IS NOT NULL AND field = value THEN 1
1✔
609
                                //     ELSE 0
1✔
610
                                // END = 1
1✔
611
                                ctx.WriteString("CASE WHEN ")
1✔
612
                                ctx.WriteString(field)
1✔
613
                                ctx.WriteString(" IS NULL AND ")
1✔
614
                                ctx.WriteValue(value)
1✔
615
                                ctx.WriteString(" IS NULL THEN 1 WHEN ")
1✔
616
                                ctx.WriteString(field)
1✔
617
                                ctx.WriteString(" IS NOT NULL AND ")
1✔
618
                                ctx.WriteValue(value)
1✔
619
                                ctx.WriteString(" IS NOT NULL AND ")
1✔
620
                                ctx.WriteString(field)
1✔
621
                                ctx.WriteString(" = ")
1✔
622
                                ctx.WriteValue(value)
1✔
623
                                ctx.WriteString(" THEN 1 ELSE 0 END = 1")
1✔
624
                        }
625
                },
626
        })
627
}
628

629
// Var returns a placeholder for value.
630
func (c *Cond) Var(value interface{}) string {
1✔
631
        return c.Args.Add(value)
1✔
632
}
1✔
633

634
type condBuilder struct {
635
        Builder func(ctx *argsCompileContext)
636
}
637

638
func estimateStringsBytes(strs []string) (n int) {
1✔
639
        for _, s := range strs {
2✔
640
                n += len(s)
1✔
641
        }
1✔
642

643
        return
1✔
644
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc