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

stephenafamo / scan / 10709903913

04 Sep 2024 09:36PM UTC coverage: 90.805% (-0.2%) from 91.017%
10709903913

push

github

stephenafamo
Add `Each()` to work with go1.23 range-over-func

16 of 19 new or added lines in 1 file covered. (84.21%)

553 of 609 relevant lines covered (90.8%)

43.24 hits per line

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

78.85
/exec.go
1
package scan
2

3
import (
4
        "context"
5
        "database/sql"
6
)
7

8
// One scans a single row from the query and maps it to T using a [Queryer]
9
func One[T any](ctx context.Context, exec Queryer, m Mapper[T], query string, args ...any) (T, error) {
13✔
10
        var t T
13✔
11

13✔
12
        rows, err := exec.QueryContext(ctx, query, args...)
13✔
13
        if err != nil {
13✔
14
                return t, err
×
15
        }
×
16
        defer rows.Close()
13✔
17

13✔
18
        return OneFromRows(ctx, m, rows)
13✔
19
}
20

21
// OneFromRows scans a single row from the given [Rows] result and maps it to T using a [Queryer]
22
func OneFromRows[T any](ctx context.Context, m Mapper[T], rows Rows) (T, error) {
13✔
23
        var t T
13✔
24

13✔
25
        allowUnknown, _ := ctx.Value(CtxKeyAllowUnknownColumns).(bool)
13✔
26
        v, err := wrapRows(rows, allowUnknown)
13✔
27
        if err != nil {
13✔
28
                return t, err
×
29
        }
×
30

31
        before, after := m(ctx, v.columnsCopy())
13✔
32

13✔
33
        if !rows.Next() {
13✔
34
                if err = rows.Err(); err != nil {
×
35
                        return t, err
×
36
                }
×
37
                return t, sql.ErrNoRows
×
38
        }
39

40
        t, err = scanOneRow(v, before, after)
13✔
41
        if err != nil {
16✔
42
                return t, err
3✔
43
        }
3✔
44

45
        return t, rows.Err()
10✔
46
}
47

48
// All scans all rows from the query and returns a slice []T of all rows using a [Queryer]
49
func All[T any](ctx context.Context, exec Queryer, m Mapper[T], query string, args ...any) ([]T, error) {
13✔
50
        rows, err := exec.QueryContext(ctx, query, args...)
13✔
51
        if err != nil {
13✔
52
                return nil, err
×
53
        }
×
54
        defer rows.Close()
13✔
55

13✔
56
        return AllFromRows(ctx, m, rows)
13✔
57
}
58

59
// AllFromRows scans all rows from the given [Rows] and returns a slice []T of all rows using a [Queryer]
60
func AllFromRows[T any](ctx context.Context, m Mapper[T], rows Rows) ([]T, error) {
13✔
61
        allowUnknown, _ := ctx.Value(CtxKeyAllowUnknownColumns).(bool)
13✔
62
        v, err := wrapRows(rows, allowUnknown)
13✔
63
        if err != nil {
13✔
64
                return nil, err
×
65
        }
×
66

67
        before, after := m(ctx, v.columnsCopy())
13✔
68

13✔
69
        var results []T
13✔
70
        for rows.Next() {
48✔
71
                one, err := scanOneRow(v, before, after)
35✔
72
                if err != nil {
38✔
73
                        return nil, err
3✔
74
                }
3✔
75

76
                results = append(results, one)
32✔
77
        }
78

79
        return results, rows.Err()
10✔
80
}
81

82
// Cursor runs a query and returns a cursor that works similar to *sql.Rows
83
func Cursor[T any](ctx context.Context, exec Queryer, m Mapper[T], query string, args ...any) (ICursor[T], error) {
13✔
84
        rows, err := exec.QueryContext(ctx, query, args...)
13✔
85
        if err != nil {
13✔
86
                return nil, err
×
87
        }
×
88

89
        return CursorFromRows(ctx, m, rows)
13✔
90
}
91

92
// Each returns a function that can be used to iterate over the rows of a query
93
// this function works with range-over-func so it is possible to do
94
//
95
//        for val, err := range scan.Each(ctx, exec, m, query, args...) {
96
//            if err != nil {
97
//                return err
98
//            }
99
//            // do something with val
100
//        }
101
func Each[T any](ctx context.Context, exec Queryer, m Mapper[T], query string, args ...any) func(func(T, error) bool) {
13✔
102
        rows, err := exec.QueryContext(ctx, query, args...)
13✔
103
        if err != nil {
13✔
NEW
104
                return func(yield func(T, error) bool) { yield(*new(T), err) }
×
105
        }
106

107
        allowUnknown, _ := ctx.Value(CtxKeyAllowUnknownColumns).(bool)
13✔
108
        wrapped, err := wrapRows(rows, allowUnknown)
13✔
109
        if err != nil {
13✔
NEW
110
                rows.Close()
×
NEW
111
                return func(yield func(T, error) bool) { yield(*new(T), err) }
×
112
        }
113

114
        before, after := m(ctx, wrapped.columnsCopy())
13✔
115

13✔
116
        return func(yield func(T, error) bool) {
26✔
117
                defer rows.Close()
13✔
118

13✔
119
                for rows.Next() {
48✔
120
                        val, err := scanOneRow(wrapped, before, after)
35✔
121
                        if !yield(val, err) {
38✔
122
                                return
3✔
123
                        }
3✔
124
                }
125
        }
126
}
127

128
// CursorFromRows returns a cursor from [Rows] that works similar to *sql.Rows
129
func CursorFromRows[T any](ctx context.Context, m Mapper[T], rows Rows) (ICursor[T], error) {
13✔
130
        allowUnknown, _ := ctx.Value(CtxKeyAllowUnknownColumns).(bool)
13✔
131
        v, err := wrapRows(rows, allowUnknown)
13✔
132
        if err != nil {
13✔
133
                return nil, err
×
134
        }
×
135

136
        before, after := m(ctx, v.columnsCopy())
13✔
137

13✔
138
        return &cursor[T]{
13✔
139
                v:      v,
13✔
140
                before: before,
13✔
141
                after:  after,
13✔
142
        }, nil
13✔
143
}
144

145
func scanOneRow[T any](v *Row, before func(*Row) (any, error), after func(any) (T, error)) (T, error) {
118✔
146
        val, err := before(v)
118✔
147
        if err != nil {
118✔
148
                var t T
×
149
                return t, err
×
150
        }
×
151

152
        err = v.scanCurrentRow()
118✔
153
        if err != nil {
130✔
154
                var t T
12✔
155
                return t, err
12✔
156
        }
12✔
157

158
        return after(val)
106✔
159
}
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