+60
scanner.go
+60
scanner.go
···
1
+
package norm
2
+
3
+
import (
4
+
"database/sql"
5
+
"iter"
6
+
"reflect"
7
+
)
8
+
9
+
type Scanner[T any] struct {
10
+
rows *sql.Rows
11
+
onError func(err error)
12
+
}
13
+
14
+
type ScannerOpt[T any] func(*Scanner[T])
15
+
16
+
func OnScannerError[T any](errFunc func(error)) ScannerOpt[T] {
17
+
return func(s *Scanner[T]) {
18
+
s.onError = errFunc
19
+
}
20
+
}
21
+
22
+
func NewScanner[T any](rows *sql.Rows, opts ...ScannerOpt[T]) Scanner[T] {
23
+
scanner := Scanner[T]{
24
+
rows: rows,
25
+
}
26
+
27
+
for _, o := range opts {
28
+
o(&scanner)
29
+
}
30
+
31
+
return scanner
32
+
}
33
+
34
+
func (s *Scanner[T]) Scan() iter.Seq[T] {
35
+
return func(yield func(T) bool) {
36
+
defer s.rows.Close()
37
+
38
+
for s.rows.Next() {
39
+
var data T
40
+
elem := reflect.ValueOf(&data).Elem()
41
+
numCols := elem.NumField()
42
+
columns := make([]any, numCols)
43
+
44
+
for i := range numCols {
45
+
field := elem.Field(i)
46
+
columns[i] = field.Addr().Interface()
47
+
}
48
+
49
+
if err := s.rows.Scan(columns...); err != nil {
50
+
s.onError(err)
51
+
return
52
+
}
53
+
54
+
// Yield the row - if yield returns false, stop iteration
55
+
if !yield(data) {
56
+
return
57
+
}
58
+
}
59
+
}
60
+
}