forked from araddon/qlbridge
/
mockcsv.go
134 lines (115 loc) · 3.52 KB
/
mockcsv.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
package mockcsv
import (
"fmt"
"strings"
u "github.com/araddon/gou"
"github.com/araddon/qlbridge/datasource"
"github.com/araddon/qlbridge/datasource/membtree"
"github.com/araddon/qlbridge/schema"
)
var (
// Enforce Features of this MockCsv Data Source
// - the rest are implemented in the static in-memory btree
_ schema.Source = (*MockCsvSource)(nil)
_ schema.Conn = (*MockCsvTable)(nil)
_ schema.ConnUpsert = (*MockCsvTable)(nil)
_ schema.ConnDeletion = (*MockCsvTable)(nil)
MockCsvGlobal = NewMockSource()
)
func init() {
//u.SetupLogging("debug")
//u.SetColorOutput()
datasource.Register("mockcsv", MockCsvGlobal)
}
// MockCsv is used for mocking so has a global data source we can load data into
func LoadTable(name, csvRaw string) {
MockCsvGlobal.CreateTable(name, csvRaw)
}
// Mock Data source for testing
// - creates an in memory b-tree per "table"
// - not thread safe
type MockCsvSource struct {
tablenamelist []string
tables map[string]*membtree.StaticDataSource
raw map[string]string
}
// A table
type MockCsvTable struct {
*membtree.StaticDataSource
//insert *rel.SqlInsert
}
func NewMockSource() *MockCsvSource {
return &MockCsvSource{
tablenamelist: make([]string, 0),
raw: make(map[string]string),
tables: make(map[string]*membtree.StaticDataSource),
}
}
func (m *MockCsvSource) Open(tableName string) (schema.Conn, error) {
tableName = strings.ToLower(tableName)
if ds, ok := m.tables[tableName]; ok {
return &MockCsvTable{StaticDataSource: ds}, nil
}
err := m.loadTable(tableName)
if err != nil {
u.Errorf("could not load table %q err=%v", tableName, err)
return nil, err
}
ds := m.tables[tableName]
return &MockCsvTable{StaticDataSource: ds}, nil
}
func (m *MockCsvSource) Table(tableName string) (*schema.Table, error) {
tableName = strings.ToLower(tableName)
if ds, ok := m.tables[tableName]; ok {
return ds.Table(tableName)
}
err := m.loadTable(tableName)
if err != nil {
u.Errorf("could not load table %q err=%v", tableName, err)
return nil, err
}
ds, ok := m.tables[tableName]
if !ok {
return nil, schema.ErrNotFound
}
return ds.Table(tableName)
}
func (m *MockCsvSource) loadTable(tableName string) error {
csvRaw, ok := m.raw[tableName]
if !ok {
return schema.ErrNotFound
}
sr := strings.NewReader(csvRaw)
u.Debugf("mockcsv:%p load mockcsv: %q data:%v", m, tableName, csvRaw)
csvSource, _ := datasource.NewCsvSource(tableName, 0, sr, make(<-chan bool, 1))
tbl := membtree.NewStaticData(tableName)
u.Infof("loaded columns %v", csvSource.Columns())
tbl.SetColumns(csvSource.Columns())
//u.Infof("set index col for %v: %v -- %v", tableName, 0, csvSource.Columns()[0])
m.tables[tableName] = tbl
// Now we are going to page through the Csv rows and Put into
// Static Data Source, ie copy into memory btree structure
for {
msg := csvSource.Next()
if msg == nil {
//u.Infof("table:%v len=%v", tableName, tbl.Length())
return nil
}
dm, ok := msg.Body().(*datasource.SqlDriverMessageMap)
if !ok {
return fmt.Errorf("Expected *datasource.SqlDriverMessageMap but got %T", msg.Body())
}
// We don't know the Key
tbl.Put(nil, nil, dm.Values())
}
return nil
}
func (m *MockCsvSource) Close() error { return nil }
func (m *MockCsvSource) Tables() []string { return m.tablenamelist }
func (m *MockCsvSource) CreateTable(tableName, csvRaw string) {
if _, exists := m.raw[tableName]; !exists {
m.tablenamelist = append(m.tablenamelist, tableName)
}
m.raw[tableName] = csvRaw
m.loadTable(tableName)
}