Skip to content

Commit d60dbd1

Browse files
authored
Idiomatic error handling (#43)
1 parent 4d0c41a commit d60dbd1

File tree

2 files changed

+55
-38
lines changed

2 files changed

+55
-38
lines changed

builq.go

+11-12
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,10 @@ func (c Columns) Prefixed(p string) string {
2525
type Builder struct {
2626
parts []string
2727
args [][]any
28-
err error // the first error occurred while building the query.
29-
counter int // a counter for numbered placeholders ($1, $2, ...).
30-
placeholder byte // a placeholder used to build the query.
31-
sep byte // a separator between Addf calls.
32-
debug bool // is it DebugBuild call to fill with args.
28+
counter int // a counter for numbered placeholders ($1, $2, ...).
29+
placeholder byte // a placeholder used to build the query.
30+
sep byte // a separator between Addf calls.
31+
debug bool // is it DebugBuild call to fill with args.
3332
}
3433

3534
// OnelineBuilder behaves like Builder but result is 1 line.
@@ -87,14 +86,13 @@ func (b *Builder) Addf(format constString, args ...any) *Builder {
8786

8887
// Build the query and arguments.
8988
func (b *Builder) Build() (query string, args []any, err error) {
90-
query, args = b.build()
91-
return query, args, b.err
89+
return b.build()
9290
}
9391

9492
// DebugBuild the query, good for debugging but not for REAL usage.
9593
func (b *Builder) DebugBuild() (query string) {
9694
b.debug = true
97-
query, _ = b.build()
95+
query, _, _ = b.build()
9896
b.debug = false
9997
return query
10098
}
@@ -110,7 +108,7 @@ func (b *Builder) addf(format constString, args ...any) *Builder {
110108
return b
111109
}
112110

113-
func (b *Builder) build() (_ string, _ []any) {
111+
func (b *Builder) build() (string, []any, error) {
114112
var query strings.Builder
115113
// TODO: better default (sum of parts + est len of indexes)
116114
query.Grow(100)
@@ -121,13 +119,14 @@ func (b *Builder) build() (_ string, _ []any) {
121119
format := b.parts[i]
122120
args := b.args[i]
123121

124-
err := b.write(&query, &resArgs, format, args...)
125-
b.setErr(err)
122+
if err := b.write(&query, &resArgs, format, args...); err != nil {
123+
return "", nil, err
124+
}
126125
}
127126

128127
// drop last separators for clarity.
129128
q := strings.TrimRight(query.String(), string(b.sep))
130-
return q, resArgs
129+
return q, resArgs, nil
131130
}
132131

133132
var (

write.go

+44-26
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ func (b *Builder) write(sb *strings.Builder, resArgs *[]any, s string, args ...a
3737

3838
arg := args[argID]
3939
s = s[1:]
40-
b.writeArg(sb, resArgs, verb, arg)
40+
if err := b.writeArg(sb, resArgs, verb, arg); err != nil {
41+
return err
42+
}
4143

4244
case '+', '#':
4345
isBatch := verb == '#'
@@ -56,9 +58,13 @@ func (b *Builder) write(sb *strings.Builder, resArgs *[]any, s string, args ...a
5658
s = s[1:]
5759

5860
if isBatch {
59-
b.writeBatch(sb, resArgs, verb, arg)
61+
if err := b.writeBatch(sb, resArgs, verb, arg); err != nil {
62+
return err
63+
}
6064
} else {
61-
b.writeSlice(sb, resArgs, verb, arg)
65+
if err := b.writeSlice(sb, resArgs, verb, arg); err != nil {
66+
return err
67+
}
6268
}
6369

6470
default:
@@ -79,30 +85,44 @@ func (b *Builder) write(sb *strings.Builder, resArgs *[]any, s string, args ...a
7985
}
8086
}
8187

82-
func (b *Builder) writeBatch(sb *strings.Builder, resArgs *[]any, verb byte, arg any) {
83-
for i, arg := range b.asSlice(arg) {
88+
func (b *Builder) writeBatch(sb *strings.Builder, resArgs *[]any, verb byte, arg any) error {
89+
args, err := b.asSlice(arg)
90+
if err != nil {
91+
return err
92+
}
93+
for i, arg := range args {
8494
if i > 0 {
8595
sb.WriteString(", ")
8696
}
8797
sb.WriteByte('(')
88-
b.writeSlice(sb, resArgs, verb, arg)
98+
if err := b.writeSlice(sb, resArgs, verb, arg); err != nil {
99+
return err
100+
}
89101
sb.WriteByte(')')
90102
}
103+
return nil
91104
}
92105

93-
func (b *Builder) writeSlice(sb *strings.Builder, resArgs *[]any, verb byte, arg any) {
94-
for i, arg := range b.asSlice(arg) {
106+
func (b *Builder) writeSlice(sb *strings.Builder, resArgs *[]any, verb byte, arg any) error {
107+
args, err := b.asSlice(arg)
108+
if err != nil {
109+
return err
110+
}
111+
for i, arg := range args {
95112
if i > 0 {
96113
sb.WriteString(", ")
97114
}
98-
b.writeArg(sb, resArgs, verb, arg)
115+
if err := b.writeArg(sb, resArgs, verb, arg); err != nil {
116+
return err
117+
}
99118
}
119+
return nil
100120
}
101121

102-
func (b *Builder) writeArg(sb *strings.Builder, resArgs *[]any, verb byte, arg any) {
122+
func (b *Builder) writeArg(sb *strings.Builder, resArgs *[]any, verb byte, arg any) error {
103123
if b.debug {
104124
b.writeDebug(sb, arg)
105-
return
125+
return nil
106126
}
107127

108128
var isSimple bool
@@ -128,21 +148,25 @@ func (b *Builder) writeArg(sb *strings.Builder, resArgs *[]any, verb byte, arg a
128148
}
129149
case 'd':
130150
isSimple = true
131-
b.assertNumber(arg)
151+
if err := b.assertNumber(arg); err != nil {
152+
return err
153+
}
132154
fmt.Fprint(sb, arg)
133155
}
134156

135157
// ok to have many simple placeholders
136158
if isSimple {
137-
return
159+
return nil
138160
}
139161

140162
switch {
141163
case b.placeholder == 0:
142164
b.placeholder = verb
143165
case b.placeholder != verb:
144-
b.setErr(errMixedPlaceholders)
166+
return errMixedPlaceholders
145167
}
168+
169+
return nil
146170
}
147171

148172
func (b *Builder) writeDebug(sb *strings.Builder, arg any) {
@@ -172,33 +196,27 @@ func (b *Builder) writeDebug(sb *strings.Builder, arg any) {
172196
}
173197
}
174198

175-
func (b *Builder) asSlice(v any) []any {
199+
func (b *Builder) asSlice(v any) ([]any, error) {
176200
value := reflect.ValueOf(v)
177201

178202
if value.Kind() != reflect.Slice {
179-
b.setErr(errNonSliceArgument)
180-
return nil
203+
return nil, errNonSliceArgument
181204
}
182205

183206
res := make([]any, value.Len())
184207
for i := 0; i < value.Len(); i++ {
185208
res[i] = value.Index(i).Interface()
186209
}
187-
return res
210+
return res, nil
188211
}
189212

190-
func (b *Builder) assertNumber(v any) {
213+
func (b *Builder) assertNumber(v any) error {
191214
switch v.(type) {
192215
case int, int8, int16, int32, int64,
193216
uint, uint8, uint16, uint32, uint64,
194217
float32, float64:
218+
return nil
195219
default:
196-
b.setErr(errNonNumericArg)
197-
}
198-
}
199-
200-
func (b *Builder) setErr(err error) {
201-
if b.err == nil {
202-
b.err = err
220+
return errNonNumericArg
203221
}
204222
}

0 commit comments

Comments
 (0)