-
Notifications
You must be signed in to change notification settings - Fork 0
/
reader_query.go
155 lines (131 loc) · 3.83 KB
/
reader_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
155
package spnr
import (
"reflect"
"cloud.google.com/go/spanner"
"github.com/pkg/errors"
"google.golang.org/api/iterator"
)
/*
QueryOne fetches a record by calling specified query, and map the record into the passed pointer of struct.
Errors:
If no records are found, this method will return ErrNotFound.
If multiple records are found, this method will return ErrMoreThanOneRecordFound.
If you don't need to fetch all columns but only needs one column, use QueryValue instead.
If you don't need to fetch all columns but only needs some columns, please make a temporal struct to map the columns.
*/
func (r *Reader) QueryOne(sql string, params map[string]any, target any) error {
if err := validateStructType(target); err != nil {
return err
}
r.logf(readLogTemplate, "sql:"+sql, params)
iter := r.tx.Query(r.ctx, spanner.Statement{SQL: sql, Params: params})
defer iter.Stop()
row, err := iter.Next()
if errors.Is(err, iterator.Done) {
return ErrNotFound
}
if err != nil {
return errors.WithStack(err)
}
err = row.ToStruct(target)
if err != nil {
return errors.WithStack(err)
}
_, err = iter.Next()
if errors.Is(err, iterator.Done) {
return nil
} else {
return ErrMoreThanOneRecordFound
}
}
// Query fetches records by calling specified query, and map the records into the passed pointer of a slice of struct.
func (r *Reader) Query(sql string, params map[string]any, target any) error {
if err := validateStructSliceType(target); err != nil {
return err
}
r.logf(readLogTemplate, "sql:"+sql, params)
slice := reflect.ValueOf(target).Elem()
innerType := slice.Type().Elem()
iter := r.tx.Query(r.ctx, spanner.Statement{SQL: sql, Params: params})
defer iter.Stop()
for {
row, err := iter.Next()
if errors.Is(err, iterator.Done) {
break
}
if err != nil {
return errors.WithStack(err)
}
e := reflect.New(innerType).Elem()
if err := row.ToStruct(e.Addr().Interface()); err != nil {
return errors.WithStack(err)
}
slice.Set(reflect.Append(slice, e))
}
return nil
}
/*
QueryValue fetches one value by calling specified query, and map the value into the passed pointer of value.
Errors:
If no records are found, this method will return ErrNotFound.
If multiple records are found, this method will return ErrMoreThanOneRecordFound.
Example:
var cnt int64
QueryValue("select count(*) as cnt from Singers", nil, &cnt)
*/
func (r *Reader) QueryValue(sql string, params map[string]any, target any) error {
r.logf(readLogTemplate, "sql:"+sql, params)
iter := r.tx.Query(r.ctx, spanner.Statement{SQL: sql, Params: params})
defer iter.Stop()
row, err := iter.Next()
if err != nil {
if errors.Is(err, iterator.Done) {
return ErrNotFound
}
return errors.WithStack(err)
}
if row == nil {
return ErrNotFound
}
err = row.Columns(target)
if err != nil {
return errors.WithStack(err)
}
_, err = iter.Next()
if errors.Is(err, iterator.Done) {
return nil
} else {
return ErrMoreThanOneRecordFound
}
}
/*
QueryValues fetches each value of multiple records by calling specified query, and map the values into the passed pointer of a slice of struct.
Example:
var names []string
QueryValue("select Name from Singers", nil, &names)
*/
func (r *Reader) QueryValues(sql string, params map[string]any, target any) error {
if err := validateSliceType(target); err != nil {
return err
}
r.logf(readLogTemplate, "sql:"+sql, params)
slice := reflect.ValueOf(target).Elem()
innerType := slice.Type().Elem()
iter := r.tx.Query(r.ctx, spanner.Statement{SQL: sql, Params: params})
defer iter.Stop()
for {
row, err := iter.Next()
if errors.Is(err, iterator.Done) {
break
}
if err != nil {
return errors.WithStack(err)
}
e := reflect.New(innerType).Elem()
if err := row.Columns(e.Addr().Interface()); err != nil {
return errors.WithStack(err)
}
slice.Set(reflect.Append(slice, e))
}
return nil
}