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

stephenafamo / bob / 25928259135

15 May 2026 04:11PM UTC coverage: 44.979% (+0.03%) from 44.954%
25928259135

push

github

web-flow
Merge pull request #686 from atzedus/feat/columns-expr-expressions

feat(expr): Add ColumnsExpr accessors and improve column rendering defaults

9 of 21 new or added lines in 1 file covered. (42.86%)

1 existing line in 1 file now uncovered.

10946 of 24336 relevant lines covered (44.98%)

656.87 hits per line

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

47.5
/expr/columns.go
1
package expr
2

3
import (
4
        "context"
5
        "io"
6
        "reflect"
7
        "slices"
8

9
        "github.com/stephenafamo/bob"
10
        "github.com/stephenafamo/bob/internal"
11
        "github.com/stephenafamo/bob/internal/mappings"
12
)
13

14
// NewColumnsExpr returns a [ColumnsExpr] object with the given column names
15
func NewColumnsExpr(names ...string) ColumnsExpr {
22✔
16
        return ColumnsExpr{names: internal.FilterNonZero(names)}
22✔
17
}
22✔
18

19
// ColumnsExpr is a set of columns that can be used in a query
20
// It is used to properly quote and format the columns in the query
21
// such as "users"."id" AS "id", "users"."name" AS "name"
22
type ColumnsExpr struct {
23
        parent        []string
24
        names         []string
25
        aggFunc       [2]string
26
        aliasPrefix   string
27
        aliasDisabled bool
28
}
29

30
// Parent returns the parent columns
NEW
31
func (c ColumnsExpr) Parent() []string {
×
NEW
32
        return slices.Clone(c.parent)
×
NEW
33
}
×
34

35
// Names returns the names of the columns
36
func (c ColumnsExpr) Names() []string {
×
37
        return slices.Clone(c.names)
×
38
}
×
39

40
// AggFunc returns the aggregation function of the columns
NEW
41
func (c ColumnsExpr) AggFunc() [2]string {
×
NEW
42
        return c.aggFunc
×
NEW
43
}
×
44

45
// AliasPrefix returns the alias prefix of the columns
NEW
46
func (c ColumnsExpr) AliasPrefix() string {
×
NEW
47
        return c.aliasPrefix
×
NEW
48
}
×
49

50
// AliasDisabled returns whether aliasing is disabled for the columns
NEW
51
func (c ColumnsExpr) AliasDisabled() bool {
×
NEW
52
        return c.aliasDisabled
×
NEW
53
}
×
54

55
func (c ColumnsExpr) WithAggFunc(a, b string) ColumnsExpr {
×
56
        c.aggFunc = [2]string{a, b}
×
57
        return c
×
58
}
×
59

60
// WithParent sets the parent of the columns.
61
func (c ColumnsExpr) WithParent(p ...string) ColumnsExpr {
22✔
62
        c.parent = internal.FilterNonZero(p)
22✔
63
        return c
22✔
64
}
22✔
65

66
// WithPrefix sets the prefix of the aliases of the column set.
67
func (c ColumnsExpr) WithPrefix(prefix string) ColumnsExpr {
×
68
        c.aliasPrefix = prefix
×
69
        return c
×
70
}
×
71

72
// EnableAlias enables adding 'AS "prefix_column_name"' when writing SQL.
73
func (c ColumnsExpr) EnableAlias() ColumnsExpr {
×
74
        c.aliasDisabled = false
×
75
        return c
×
76
}
×
77

78
// DisableAlias disables adding 'AS "prefix_column_name"' when writing SQL.
79
func (c ColumnsExpr) DisableAlias() ColumnsExpr {
×
80
        c.aliasDisabled = true
×
81
        return c
×
82
}
×
83

84
// Only drops other column names from the column set
85
func (c ColumnsExpr) Only(cols ...string) ColumnsExpr {
×
86
        c.names = internal.Only(c.names, cols...)
×
87
        return c
×
88
}
×
89

90
// Except drops the given column names from the column set
91
func (c ColumnsExpr) Except(cols ...string) ColumnsExpr {
×
92
        c.names = internal.Except(c.names, cols...)
×
93
        return c
×
94
}
×
95

96
func (c ColumnsExpr) WriteSQL(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) {
10✔
97
        if len(c.names) == 0 {
10✔
98
                return nil, nil
×
99
        }
×
100

101
        hasParent := false
10✔
102
        for _, part := range c.parent {
18✔
103
                if part != "" {
16✔
104
                        hasParent = true
8✔
105
                        break
8✔
106
                }
107
        }
108

109
        shouldAlias := !c.aliasDisabled && (hasParent || c.aliasPrefix != "" || c.aggFunc != [2]string{})
10✔
110

10✔
111
        // wrap in parenthesis and join with comma
10✔
112
        for k, col := range c.names {
40✔
113
                if k != 0 {
50✔
114
                        w.WriteString(", ")
20✔
115
                }
20✔
116

117
                w.WriteString(c.aggFunc[0])
30✔
118
                for _, part := range c.parent {
54✔
119
                        if part == "" {
24✔
UNCOV
120
                                continue
×
121
                        }
122
                        d.WriteQuoted(w, part)
24✔
123
                        w.WriteString(".")
24✔
124
                }
125

126
                d.WriteQuoted(w, col)
30✔
127
                w.WriteString(c.aggFunc[1])
30✔
128

30✔
129
                if shouldAlias {
54✔
130
                        w.WriteString(" AS ")
24✔
131
                        d.WriteQuoted(w, c.aliasPrefix+col)
24✔
132
                }
24✔
133
        }
134

135
        return nil, nil
10✔
136
}
137

138
func ColsForStruct[T any](name string) ColumnsExpr {
8✔
139
        var model T
8✔
140
        return NewColumnsExpr(mappings.GetMappings(reflect.TypeOf(model)).All...).WithParent(name)
8✔
141
}
8✔
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