-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexecutor_test.go
More file actions
132 lines (114 loc) · 3.26 KB
/
Copy pathexecutor_test.go
File metadata and controls
132 lines (114 loc) · 3.26 KB
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package pgcrud_test
import (
"context"
"database/sql"
"fmt"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
// cols builds field descriptions for the given column names.
func cols(names ...string) []pgconn.FieldDescription {
fds := make([]pgconn.FieldDescription, len(names))
for i, n := range names {
fds[i] = pgconn.FieldDescription{Name: n}
}
return fds
}
// fakeRows is an in-memory pgx.Rows. Scan hands each value to the
// destination the way pgx does for sql.Scanner targets.
type fakeRows struct {
fds []pgconn.FieldDescription
data [][]any
idx int
closed bool
err error
}
func newFakeRows(fds []pgconn.FieldDescription, data ...[]any) *fakeRows {
return &fakeRows{fds: fds, data: data}
}
func (r *fakeRows) Close() { r.closed = true }
func (r *fakeRows) Err() error { return r.err }
func (r *fakeRows) FieldDescriptions() []pgconn.FieldDescription { return r.fds }
func (r *fakeRows) RawValues() [][]byte { return nil }
func (r *fakeRows) Conn() *pgx.Conn { return nil }
func (r *fakeRows) CommandTag() pgconn.CommandTag {
return pgconn.NewCommandTag(fmt.Sprintf("SELECT %d", len(r.data)))
}
func (r *fakeRows) Next() bool {
if r.idx >= len(r.data) {
return false
}
r.idx++
return true
}
func (r *fakeRows) Values() ([]any, error) {
return r.data[r.idx-1], nil
}
func (r *fakeRows) Scan(dest ...any) error {
return scanRow(r.data[r.idx-1], dest)
}
func scanRow(row []any, dest []any) error {
if len(dest) != len(row) {
return fmt.Errorf("fakeRows: %d dest for %d values", len(dest), len(row))
}
for i, d := range dest {
switch d := d.(type) {
case sql.Scanner:
if err := d.Scan(row[i]); err != nil {
return err
}
case *int64:
*d = row[i].(int64)
case *bool:
*d = row[i].(bool)
case *string:
*d = row[i].(string)
default:
return fmt.Errorf("fakeRows: unsupported dest %T", d)
}
}
return nil
}
type fakeRow struct{ rows *fakeRows }
func (r fakeRow) Scan(dest ...any) error {
if !r.rows.Next() {
return pgx.ErrNoRows
}
// A QueryRow caller such as Count scans a single scalar; like the two-query
// ScanAndCount test, it reads column 0 of whatever canned row is served.
row := r.rows.data[r.rows.idx-1]
if len(dest) < len(row) {
row = row[:len(dest)]
}
return scanRow(row, dest)
}
type call struct {
method string
sql string
args []any
}
// fakeExecutor records calls and replays canned results.
type fakeExecutor struct {
calls []call
rows *fakeRows
tag pgconn.CommandTag
err error
}
func (e *fakeExecutor) Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error) {
e.calls = append(e.calls, call{"Exec", sql, args})
return e.tag, e.err
}
func (e *fakeExecutor) Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error) {
e.calls = append(e.calls, call{"Query", sql, args})
if e.err != nil {
return nil, e.err
}
return e.rows, nil
}
func (e *fakeExecutor) QueryRow(ctx context.Context, sql string, args ...any) pgx.Row {
e.calls = append(e.calls, call{"QueryRow", sql, args})
if e.rows != nil {
e.rows.idx = 0 // a fresh row set for each QueryRow, so one fake can serve fetch and count
}
return fakeRow{rows: e.rows}
}