forked from c9s/gatsby
-
Notifications
You must be signed in to change notification settings - Fork 0
/
filler.go
161 lines (134 loc) · 3.53 KB
/
filler.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
156
157
158
159
160
161
package gatsby
import (
"database/sql"
"errors"
"fmt"
"github.com/c9s/gatsby/sqlutils"
"github.com/c9s/pq"
"reflect"
"time"
)
type RowScanner interface {
Scan(dest ...interface{}) error
}
type RecordMap map[string]interface{}
type RecordMapList []RecordMap
// Fill the struct data from a result rows
// This function iterates the struct by reflection, and creates types from sql
// package for filling result.
func FillFromRows(val PtrRecord, rows RowScanner) error {
t := reflect.ValueOf(val).Elem()
typeOfT := t.Type()
var err error
var args []interface{}
var tag reflect.StructTag
var fieldNums []int
var fieldValue reflect.Value
var rval interface{}
for i := 0; i < t.NumField(); i++ {
tag = typeOfT.Field(i).Tag
if sqlutils.GetColumnNameFromTag(&tag) == nil {
continue
}
fieldValue = t.Field(i)
rval = fieldValue.Interface()
switch rval.(type) {
case string:
args = append(args, new(sql.NullString))
case int64, int32, int16, int8, int:
args = append(args, new(sql.NullInt64))
case bool:
args = append(args, new(sql.NullBool))
case float64:
args = append(args, new(sql.NullFloat64))
case *time.Time:
args = append(args, new(pq.NullTime))
default:
// XXX: Not sure if this work
var fieldType reflect.Type = fieldValue.Type()
args = append(args, reflect.New(fieldType).Elem().Interface())
}
fieldNums = append(fieldNums, i)
}
if err = rows.Scan(args...); err != nil {
return err
}
var fieldIdx int
for i, arg := range args {
fieldIdx = fieldNums[i]
// tag = typeOfT.Field(fieldIdx).Tag
// isRequired := sqlutils.HasColumnAttributeFromTag(&tag, "required")
fieldValue = t.Field(fieldIdx)
// var rval = fieldValue.Interface()
if !fieldValue.CanSet() {
var valueType reflect.Type = fieldValue.Type()
return errors.New("Can not set value " + typeOfT.Field(fieldIdx).Name + " on " + valueType.Name())
}
switch argVal := arg.(type) {
case *sql.NullString:
if argVal.Valid {
fieldValue.SetString(argVal.String)
}
case *sql.NullInt64:
if argVal.Valid {
fieldValue.SetInt(argVal.Int64)
}
case *sql.NullBool:
if argVal.Valid {
fieldValue.SetBool(argVal.Bool)
}
case *sql.NullFloat64:
if argVal.Valid {
fieldValue.SetFloat(argVal.Float64)
}
case *pq.NullTime:
if argVal.Valid {
fieldValue.Set(reflect.ValueOf(&argVal.Time))
}
default:
return fmt.Errorf("unsupported type %T", argVal)
}
}
return err
}
func CreateMapsFromRows(rows *sql.Rows, types ...interface{}) (RecordMapList, error) {
var err error
columnNames, err := rows.Columns()
if err != nil {
return nil, err
}
// create interface
var values []interface{}
var reflectValues []reflect.Value
var results RecordMapList
values, reflectValues = sqlutils.CreateReflectValuesFromTypes(types)
for rows.Next() {
var result = RecordMap{}
if err = rows.Scan(values...); err != nil {
return nil, err
}
for i, name := range columnNames {
result[name] = reflectValues[i].Elem().Interface()
}
results = append(results, result)
}
return results, nil
}
func CreateMapFromRows(rows *sql.Rows, types ...interface{}) (RecordMap, error) {
var err error
var values []interface{}
var reflectValues []reflect.Value
var result = RecordMap{}
values, reflectValues = sqlutils.CreateReflectValuesFromTypes(types)
if err = rows.Scan(values...); err != nil {
return nil, err
}
columnNames, err := rows.Columns()
if err != nil {
return nil, err
}
for i, n := range columnNames {
result[n] = reflectValues[i].Elem().Interface()
}
return result, nil
}