forked from leobcn/dyndao
/
setter.go
143 lines (131 loc) · 3.96 KB
/
setter.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
package oracle
import (
"database/sql"
"fmt"
"io/ioutil"
"reflect"
"strconv"
"time"
"github.com/pkg/errors"
"github.com/rbastic/dyndao/object"
"github.com/rbastic/dyndao/schema"
sg "github.com/rbastic/dyndao/sqlgen"
"gopkg.in/goracle.v2"
)
// LobDST helps us to implement custom support for goracle.Lob
type LobDST string
// Scan is necessary here to deal with oracle BLOB/CLOB data type.
func (l *LobDST) Scan(src interface{}) error {
// Scan ignores NULLs, and our DynamicObjectSetter handles them.
if src == nil {
return nil
}
lob, ok := src.(*goracle.Lob)
if !ok {
return fmt.Errorf("LobDST can only be used with goracle.Lib, type was %v", reflect.TypeOf(src))
}
res, err := ioutil.ReadAll(lob)
if err != nil {
return errors.Wrap(err, "failed to read son")
}
*l = LobDST(res)
return nil
}
// DynamicObjectSetter is used to dynamically set the values of an object by
// checking the necessary types (via sql.ColumnType, and what the driver tells
// us we have for column types)
func DynamicObjectSetter(s *sg.SQLGenerator, schTable *schema.Table, columnNames []string, columnPointers []interface{}, columnTypes []*sql.ColumnType, obj *object.Object) error {
// NOTE: Read this post for more info on why the code below is written this way:
// https://stackoverflow.com/questions/23507531/is-golangs-sql-package-incapable-of-ad-hoc-exploratory-queries/23507765#23507765
for i, v := range columnPointers {
ct := columnTypes[i]
typeName := ct.DatabaseTypeName()
shouldMapToString := false
colDef := schTable.GetColumn(columnNames[i])
if colDef == nil {
return fmt.Errorf("DynamicObjectSetter: undefined column definition for column named '%s' - if you are JOINing against columns which do not exist in the schemaTable, please create special definitions for them", columnNames[i])
}
shouldMapToString = colDef.MapToString
if s.IsTimestampType(typeName) {
val := v.(*time.Time)
obj.Set(columnNames[i], *val)
} else if s.IsStringType(typeName) {
val := v.(*string)
obj.Set(columnNames[i], *val)
} else if s.IsNumberType(typeName) {
nullable, _ := ct.Nullable()
if shouldMapToString {
if nullable {
val := v.(*sql.NullInt64)
if val.Valid {
obj.Set(columnNames[i], strconv.FormatInt(val.Int64, 10))
}
} else {
val := v.(*int64)
obj.Set(columnNames[i], strconv.FormatInt(*val, 10))
}
} else {
if nullable {
val := v.(*sql.NullInt64)
if val.Valid {
obj.Set(columnNames[i], val.Int64)
}
} else {
val := v.(*int64)
obj.Set(columnNames[i], *val)
}
}
} else if s.IsFloatingType(typeName) {
nullable, _ := ct.Nullable()
if nullable {
val := v.(*sql.NullFloat64)
if val.Valid {
obj.Set(columnNames[i], val.Float64)
}
} else {
val := v.(*float64)
obj.Set(columnNames[i], *val)
}
} else if s.IsLOBType(typeName) {
if v == nil {
obj.Set(columnNames[i], object.NewNULLValue())
} else {
val := v.(*LobDST)
obj.Set(columnNames[i], string(*val))
}
} else {
return errors.New("dynamicObjectSetter: Unrecognized type: " + typeName)
}
}
return nil
}
func MakeColumnPointers(s *sg.SQLGenerator, schTable *schema.Table, columnNames []string, columnTypes []*sql.ColumnType) ([]interface{}, error) {
sliceLen := len(columnNames)
columnPointers := make([]interface{}, sliceLen)
for i := 0; i < sliceLen; i++ {
ct := columnTypes[i]
typeName := ct.DatabaseTypeName()
if s.IsStringType(typeName) {
var s string
columnPointers[i] = &s
} else if s.IsNumberType(typeName) {
nullable, _ := ct.Nullable()
if nullable {
var j sql.NullInt64
columnPointers[i] = &j
} else {
var j int64
columnPointers[i] = &j
}
} else if s.IsTimestampType(typeName) {
var j time.Time
columnPointers[i] = &j
} else if s.IsLOBType(typeName) {
s := new(LobDST)
columnPointers[i] = s
} else {
return nil, errors.New("makeColumnPointers: Unrecognized type: " + typeName)
}
}
return columnPointers, nil
}