-
Notifications
You must be signed in to change notification settings - Fork 0
/
loaders.go
112 lines (102 loc) · 2.47 KB
/
loaders.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package geq
import (
"context"
"fmt"
)
type MultiScanLoader[Q any] struct {
query *Query[Q]
scanners []RowsScanner
}
func (ms *MultiScanLoader[Q]) Load(ctx context.Context, db QueryRunner) (err error) {
q, err := ms.query.Build()
if err != nil {
return err
}
rows, err := db.QueryContext(ctx, q.Query, q.Args...)
if err != nil {
return err
}
for idx := 0; rows.Next(); idx++ {
allPtrs := make([]any, 0)
ptrGroups := make([][]any, len(ms.scanners))
for i, s := range ms.scanners {
ptrs, err := s.BeforeEachScan(idx, ms.query.selections)
if err != nil {
return fmt.Errorf("scan[%d] failed to prepare: %w", i, err)
}
ptrGroups[i] = ptrs
allPtrs = append(allPtrs, ptrs...)
}
err = rows.Scan(allPtrs...)
if err != nil {
return err
}
for i, s := range ms.scanners {
s.AfterEachScan(ptrGroups[i])
}
}
return nil
}
type SliceLoader[Q, R any] struct {
query *Query[Q]
mapper RowMapper[R]
}
func (l *SliceLoader[Q, R]) Load(ctx context.Context, db QueryRunner) ([]R, error) {
var dest []R
scanner := &SliceScanner[R]{mapper: l.mapper, dest: &dest}
err := loadBySingleScanner(ctx, db, scanner, l.query)
if err != nil {
return nil, err
}
return dest, nil
}
type MapLoader[Q, R any, K comparable] struct {
query *Query[Q]
mapper RowMapper[R]
key *Column[K]
}
func (l *MapLoader[Q, R, K]) Load(ctx context.Context, db QueryRunner) (map[K]R, error) {
var dest map[K]R
scanner := &MapScanner[R, K]{mapper: l.mapper, key: l.key, dest: &dest}
err := loadBySingleScanner(ctx, db, scanner, l.query)
if err != nil {
return nil, err
}
return dest, nil
}
type SliceMapLoader[Q, R any, K comparable] struct {
query *Query[Q]
mapper RowMapper[R]
key *Column[K]
}
func (l *SliceMapLoader[Q, R, K]) Load(ctx context.Context, db QueryRunner) (map[K][]R, error) {
var dest map[K][]R
scanner := &SliceMapScanner[R, K]{mapper: l.mapper, key: l.key, dest: &dest}
err := loadBySingleScanner(ctx, db, scanner, l.query)
if err != nil {
return nil, err
}
return dest, nil
}
func loadBySingleScanner[Q any](ctx context.Context, db QueryRunner, s RowsScanner, q *Query[Q]) (err error) {
bq, err := q.Build()
if err != nil {
return err
}
rows, err := db.QueryContext(ctx, bq.Query, bq.Args...)
if err != nil {
return err
}
for i := 0; rows.Next(); i++ {
ptrs, err := s.BeforeEachScan(i, q.selections)
if err != nil {
return err
}
err = rows.Scan(ptrs...)
if err != nil {
return err
}
s.AfterEachScan(ptrs)
}
return nil
}