forked from jmoiron/sqlx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrow.go
More file actions
165 lines (144 loc) · 4.49 KB
/
row.go
File metadata and controls
165 lines (144 loc) · 4.49 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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package sqlx
import (
"database/sql"
"errors"
"github.com/tietang/sqlx/reflectx"
"reflect"
)
// Row is a reimplementation of sql.Row in order to gain access to the underlying
// sql.Rows.Columns() data, necessary for StructScan.
type Row struct {
err error
unsafe bool
rows *sql.Rows
Mapper *reflectx.Mapper
}
// Scan is a fixed implementation of sql.Row.Scan, which does not discard the
// underlying error from the internal rows object if it exists.
func (r *Row) Scan(dest ...interface{}) error {
if r.err != nil {
return r.err
}
// TODO(bradfitz): for now we need to defensively clone all
// []byte that the driver returned (not permitting
// *RawBytes in Rows.Scan), since we're about to close
// the Rows in our defer, when we return from this function.
// the contract with the driver.Next(...) interface is that it
// can return slices into read-only temporary memory that's
// only valid until the next Scan/Close. But the TODO is that
// for a lot of drivers, this copy will be unnecessary. We
// should provide an optional interface for drivers to
// implement to say, "don't worry, the []bytes that I return
// from Next will not be modified again." (for instance, if
// they were obtained from the network anyway) But for now we
// don't care.
defer r.rows.Close()
for _, dp := range dest {
if _, ok := dp.(*sql.RawBytes); ok {
return errors.New("sql: RawBytes isn't allowed on Row.Scan")
}
}
if !r.rows.Next() {
if err := r.rows.Err(); err != nil {
return err
}
return sql.ErrNoRows
}
err := r.rows.Scan(dest...)
if err != nil {
return err
}
// Make sure the query can be processed to completion with no errors.
if err := r.rows.Close(); err != nil {
return err
}
return nil
}
// Columns returns the underlying sql.Rows.Columns(), or the deferred error usually
// returned by Row.Scan()
func (r *Row) Columns() ([]string, error) {
if r.err != nil {
return []string{}, r.err
}
return r.rows.Columns()
}
// ColumnTypes returns the underlying sql.Rows.ColumnTypes(), or the deferred error
func (r *Row) ColumnTypes() ([]*sql.ColumnType, error) {
if r.err != nil {
return []*sql.ColumnType{}, r.err
}
return r.rows.ColumnTypes()
}
// Err returns the error encountered while scanning.
func (r *Row) Err() error {
return r.err
}
// StructScan a single Row into dest.
func (r *Row) StructScan(dest interface{}) error {
return r.scanAny(dest, true)
}
// SliceScan using this Rows.
func (r *Row) SliceScan() ([]interface{}, error) {
return SliceScan(r)
}
// MapScan using this Rows.
func (r *Row) MapScan(dest map[string]interface{}) error {
return MapScan(r, dest)
}
func (r *Row) scanAny(dest interface{}, structOnly bool) error {
if r.err != nil {
return r.err
}
if r.rows == nil {
r.err = sql.ErrNoRows
return r.err
}
defer r.rows.Close()
v := reflect.ValueOf(dest)
if v.Kind() != reflect.Ptr {
return errors.New("must pass a pointer, not a value, to StructScan destination")
}
if v.IsNil() {
return errors.New("nil pointer passed to StructScan destination")
}
if v.Elem().Kind() == reflect.Slice || v.Elem().Kind() == reflect.Map {
return fetchRows(r.rows, dest)
}
return fetchRow(r.rows, dest)
//
//base := reflectx.Deref(v.Type())
//scannable := isScannable(base)
//
//if structOnly && scannable {
// return structOnlyError(base)
//}
//
//columns, err := r.Columns()
//if err != nil {
// return err
//}
//
//if scannable && len(columns) > 1 {
// return fmt.Errorf("scannable dest type %s with >1 columns (%d) in result", base.Kind(), len(columns))
//}
//
//if scannable {
// return r.Scan(dest)
//}
//
//m := r.Mapper
//
//fields := m.TraversalsByName(v.Type(), columns)
//// if we are not unsafe and are missing fields, return an error
//if f, err := missingFields(fields); err != nil && !r.unsafe {
// return fmt.Errorf("missing destination name %s in %T", columns[f], dest)
//}
//values := make([]interface{}, len(columns))
//
//err = fieldsByTraversal(v, fields, values, true)
//if err != nil {
// return err
//}
//// scan into the struct field pointers and append to our results
//return r.Scan(values...)
}