-
Notifications
You must be signed in to change notification settings - Fork 0
/
query.go
154 lines (134 loc) · 3.23 KB
/
query.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package psql
import (
"context"
"database/sql"
"errors"
"io/fs"
)
type SQLQuery struct {
Query string
Args []any
}
type SQLQueryT[T any] struct {
Query string
Args []any
}
// Q is a short hand to create a Query object
func Q(q string, args ...any) *SQLQuery {
return &SQLQuery{q, args}
}
// QT is a short hand to create a Query object against a specific table
func QT[T any](q string, args ...any) *SQLQueryT[T] {
return &SQLQueryT[T]{q, args}
}
// Exec simply runs a query against the DefaultBackend
//
// Deprecated: use .Exec() instead
func Exec(q *SQLQuery) error {
_, err := GetBackend(nil).DB().Exec(q.Query, q.Args...)
return err
}
// Query performs a query and use a callback to advance results, meaning there is no need to
// call sql.Rows.Close()
//
// err = psql.Query(psql.Q("SELECT ..."), func(row *sql.Rows) error { ... })
//
// Deprecated: use .Each() instead
func Query(q *SQLQuery, cb func(*sql.Rows) error) error {
return QueryContext(context.Background(), q, cb)
}
// QueryContext performs a query and use a callback to advance results, meaning there is no need to
// call sql.Rows.Close()
//
// Deprecated: use .Each() instead
func QueryContext(ctx context.Context, q *SQLQuery, cb func(*sql.Rows) error) error {
r, err := doQueryContext(ctx, q.Query, q.Args...)
if err != nil {
return err
}
defer r.Close()
for r.Next() {
err = cb(r)
if err != nil {
if errors.Is(err, ErrBreakLoop) {
return nil
}
return err
}
}
return nil
}
// Each will execute the query and call cb for each row, so you do not need to call
// .Next() or .Close() on the object.
//
// Example use: err := psql.Q("SELECT ...").Each(ctx, func(row *sql.Rows) error { ... })
func (q *SQLQuery) Each(ctx context.Context, cb func(*sql.Rows) error) error {
r, err := doQueryContext(ctx, q.Query, q.Args...)
if err != nil {
return err
}
defer r.Close()
for r.Next() {
err := cb(r)
if err != nil {
if errors.Is(err, ErrBreakLoop) {
return nil
}
return err
}
}
return nil
}
// Exec simply executes the query and returns any error that could have happened
func (q *SQLQuery) Exec(ctx context.Context) error {
_, err := GetBackend(ctx).DB().Exec(q.Query, q.Args...)
return err
}
// Each will execute the query and call cb for each row
func (q *SQLQueryT[T]) Each(ctx context.Context, cb func(*T) error) error {
t := Table[T]()
t.check(ctx)
r, err := doQueryContext(ctx, q.Query, q.Args...)
if err != nil {
return err
}
defer r.Close()
for r.Next() {
obj, err := t.spawn(r)
if err != nil {
return err
}
err = cb(obj)
if err != nil {
if errors.Is(err, ErrBreakLoop) {
return nil
}
return err
}
}
return nil
}
// Single will execute the query and fetch a single result
func (q *SQLQueryT[T]) Single(ctx context.Context) (*T, error) {
t := Table[T]()
t.check(ctx)
r, err := doQueryContext(ctx, q.Query, q.Args...)
if err != nil {
return nil, err
}
defer r.Close()
if !r.Next() {
return nil, fs.ErrNotExist
}
return t.spawn(r)
}
// All will execute the query and return all the results
func (q *SQLQueryT[T]) All(ctx context.Context) ([]*T, error) {
t := Table[T]()
t.check(ctx)
r, err := doQueryContext(ctx, q.Query, q.Args...)
if err != nil {
return nil, err
}
return t.spawnAll(r)
}