forked from araddon/qlbridge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
introspect.go
121 lines (107 loc) · 2.97 KB
/
introspect.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
package datasource
import (
"database/sql/driver"
"strconv"
"time"
"github.com/araddon/dateparse"
u "github.com/araddon/gou"
"github.com/araddon/qlbridge/schema"
"github.com/araddon/qlbridge/value"
)
var (
_ = u.EMPTY
IntrospectCount = 20
)
func IntrospectSchema(s *schema.Schema, name string, iter schema.Iterator) error {
tbl, err := s.Table(name)
if err != nil {
u.Errorf("Could not find table %q", name)
return err
}
return IntrospectTable(tbl, iter)
}
func IntrospectTable(tbl *schema.Table, iter schema.Iterator) error {
nameIndex := make(map[int]string, len(tbl.Columns()))
for i, colName := range tbl.Columns() {
nameIndex[i] = colName
}
//u.Infof("s:%s INTROSPECT SCHEMA name %q", s, name)
ct := 0
for {
msg := iter.Next()
//u.Debugf("msg %#v", msg)
if msg == nil || ct > IntrospectCount {
break
}
switch mt := msg.Body().(type) {
case []driver.Value:
for i, v := range mt {
k := nameIndex[i]
_, exists := tbl.FieldMap[k]
//u.Debugf("i:%v k:%s v: %T %v", i, k, v, v)
switch val := v.(type) {
case int, int64, int16, int32, uint16, uint64, uint32:
tbl.AddFieldType(k, value.IntType)
case time.Time, *time.Time:
tbl.AddFieldType(k, value.TimeType)
case bool:
tbl.AddFieldType(k, value.BoolType)
case float32, float64:
tbl.AddFieldType(k, value.NumberType)
case string:
valType := guessValueType(val)
if !exists {
tbl.AddFieldType(k, valType)
//fld := tbl.FieldMap[k]
//u.Debugf("add field? %+v", fld)
//u.Debugf("%s = %v type: %T vt:%s new? %v", k, val, val, valType, !exists)
}
default:
u.Warnf("not implemented: %T", val)
}
}
case *SqlDriverMessageMap:
for i, v := range mt.Vals {
k := nameIndex[i]
_, exists := tbl.FieldMap[k]
//u.Debugf("i:%v k:%s v: %T %v", i, k, v, v)
switch val := v.(type) {
case int, int64, int16, int32, uint16, uint64, uint32:
tbl.AddFieldType(k, value.IntType)
case time.Time, *time.Time:
tbl.AddFieldType(k, value.TimeType)
case bool:
tbl.AddFieldType(k, value.BoolType)
case float32, float64:
tbl.AddFieldType(k, value.NumberType)
case string:
valType := guessValueType(val)
if !exists {
tbl.AddFieldType(k, valType)
//fld := tbl.FieldMap[k]
//u.Debugf("add field? %+v", fld)
//u.Debugf("%s = %v type: %T vt:%s new? %v", k, val, val, valType, !exists)
}
default:
u.Warnf("not implemented: %T", val)
}
}
default:
u.Warnf("not implemented: %T", mt)
}
ct++
}
return nil
}
func guessValueType(val string) value.ValueType {
if _, err := strconv.ParseInt(val, 10, 64); err == nil {
return value.IntType
} else if _, err := strconv.ParseBool(val); err == nil {
return value.IntType
} else if _, err := strconv.ParseFloat(val, 64); err == nil {
return value.NumberType
} else if _, err := dateparse.ParseAny(val); err == nil {
return value.TimeType
}
return value.StringType
}