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

stephenafamo / bob / 21748217733

06 Feb 2026 11:01AM UTC coverage: 42.633% (-0.1%) from 42.739%
21748217733

push

github

web-flow
Merge pull request #622 from manhrev/feat/sub-query-expression

Add EXISTS, ALL, SOME, ANY expressions

0 of 58 new or added lines in 4 files covered. (0.0%)

9989 of 23430 relevant lines covered (42.63%)

598.13 hits per line

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

46.74
/expr/builder.go
1
package expr
2

3
import (
4
        "github.com/stephenafamo/bob"
5
)
6

7
type builder[B any] interface {
8
        New(bob.Expression) B
9
}
10

11
// Build an expression
12
func X[T bob.Expression, B builder[T]](exp bob.Expression, others ...bob.Expression) T {
666✔
13
        var b B
666✔
14

666✔
15
        // Easy chain. For example:
666✔
16
        // X("a", "=", "b")
666✔
17
        if len(others) > 0 {
666✔
18
                exp = Join{Exprs: append([]bob.Expression{exp}, others...)}
×
19
        }
×
20

21
        // Wrap in parenthesis if not a raw string or string in quotes
22
        switch t := exp.(type) {
666✔
23
        case Clause, Raw, rawString, quoted:
268✔
24
                // expected to be printed as it is
268✔
25
                break
268✔
26
        case args:
242✔
27
                // Often initialized in a context that includes
242✔
28
                // its own parenthesis such as VALUES(...)
242✔
29
                break
242✔
30
        case group:
8✔
31
                // Already has its own parentheses
8✔
32
                break
8✔
33
        case T:
6✔
34
                return t
6✔
35
        default:
142✔
36
                exp = group{exp}
142✔
37
        }
38

39
        return b.New(exp)
660✔
40
}
41

42
// prefix the expression with a NOT
43
func Not[T bob.Expression, B builder[T]](exp bob.Expression) T {
×
44
        var b B
×
45
        return b.New(Join{Exprs: []bob.Expression{not, X[T, B](exp)}})
×
46
}
×
47

48
// Exists expression
NEW
49
func Exists[T bob.Expression, B builder[T]](exp bob.Expression) T {
×
NEW
50
        var b B
×
NEW
51
        return b.New(Join{Exprs: []bob.Expression{exists, group{exp}}})
×
NEW
52
}
×
53

54
// prefix the expression with a - (minus)
NEW
55
func Minus[T bob.Expression, B builder[T]](exp bob.Expression) T {
×
NEW
56
        var b B
×
NEW
57
        return b.New(Join{Exprs: []bob.Expression{minus, X[T, B](exp)}})
×
NEW
58
}
×
59

60
// ANY expression
NEW
61
func Any[T bob.Expression, B builder[T]](exp bob.Expression) T {
×
NEW
62
        var b B
×
NEW
63
        return b.New(Join{Exprs: []bob.Expression{anyOp, group{exp}}})
×
NEW
64
}
×
65

66
// ALL expression
NEW
67
func All[T bob.Expression, B builder[T]](exp bob.Expression) T {
×
NEW
68
        var b B
×
NEW
69
        return b.New(Join{Exprs: []bob.Expression{all, group{exp}}})
×
NEW
70
}
×
71

72
// To be embedded in query mods
73
// T is the chain type, this allows dialects to have custom chain methods
74
// F is function type, so that the dialect can change where it
75
// accepted. E.g. it can be modified to work as a mod
76
// B has a New() method that is used to create a new instance of T
77
type Builder[T bob.Expression, B builder[T]] struct{}
78

79
// prefix the expression with a NOT
80
func (e Builder[T, B]) Not(exp bob.Expression) T {
×
81
        return Not[T, B](exp)
×
82
}
×
83

84
// Or
85
func (e Builder[T, B]) Or(args ...bob.Expression) T {
×
86
        return X[T, B](Join{Exprs: args, Sep: " OR "})
×
87
}
×
88

89
// And
90
func (e Builder[T, B]) And(args ...bob.Expression) T {
×
91
        return X[T, B](Join{Exprs: args, Sep: " AND "})
×
92
}
×
93

94
// single quoted raw string
95
func (e Builder[T, B]) S(s string) T {
62✔
96
        return X[T, B](rawString(s))
62✔
97
}
62✔
98

99
// Comma separated list of arguments
100
func (e Builder[T, B]) Arg(vals ...any) T {
230✔
101
        return X[T, B](Arg(vals...))
230✔
102
}
230✔
103

104
// Comma separated list of arguments surrounded by parentheses
105
func (e Builder[T, B]) ArgGroup(vals ...any) T {
12✔
106
        return X[T, B](ArgGroup(vals...))
12✔
107
}
12✔
108

109
func (e Builder[T, B]) Placeholder(n uint) T {
×
110
        return e.Arg(make([]any, n)...)
×
111
}
×
112

113
func (e Builder[T, B]) Raw(query string, args ...any) T {
16✔
114
        return X[T, B](Clause{
16✔
115
                query: query,
16✔
116
                args:  args,
16✔
117
        })
16✔
118
}
16✔
119

120
// Add parentheses around an expressions and separate them by commas
121
func (e Builder[T, B]) Group(exps ...bob.Expression) T {
8✔
122
        return X[T, B](group(exps))
8✔
123
}
8✔
124

125
// quoted and joined... something like "users"."id"
126
func (e Builder[T, B]) Quote(aa ...string) T {
190✔
127
        return X[T, B](Quote(aa...))
190✔
128
}
190✔
129

130
// quoted and joined... something like "users"."id"
131
func (e Builder[T, B]) Cast(exp bob.Expression, typname string) T {
×
132
        return X[T, B](Cast(exp, typname))
×
133
}
×
134

135
// EXISTS expression
NEW
136
func (e Builder[T, B]) Exists(exp bob.Expression) T {
×
NEW
137
        return Exists[T, B](exp)
×
NEW
138
}
×
139

140
// prefix the expression with a - (minus)
NEW
141
func (e Builder[T, B]) Minus(exp bob.Expression) T {
×
NEW
142
        return Minus[T, B](exp)
×
NEW
143
}
×
144

145
// ANY expression
NEW
146
func (e Builder[T, B]) Any(exp bob.Expression) T {
×
NEW
147
        return Any[T, B](exp)
×
NEW
148
}
×
149

150
// ALL expression
NEW
151
func (e Builder[T, B]) All(exp bob.Expression) T {
×
NEW
152
        return All[T, B](exp)
×
NEW
153
}
×
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

© 2026 Coveralls, Inc