-
Notifications
You must be signed in to change notification settings - Fork 0
/
preprocessor.go
122 lines (107 loc) · 2.61 KB
/
preprocessor.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
package preprocessor
import (
"encoding/csv"
"fmt"
"os"
"github.com/jacobsimpson/mtsql/ast"
"github.com/jacobsimpson/mtsql/logical"
md "github.com/jacobsimpson/mtsql/metadata"
)
func Convert(q ast.Query, tables map[string]*md.Relation) (logical.Operation, error) {
var sfw *ast.SFW
if p, ok := q.(*ast.Profile); ok {
sfw = p.SFW
} else if s, ok := q.(*ast.SFW); ok {
sfw = s
} else {
return nil, fmt.Errorf("expected a select query, but got something else")
}
result, err := convertFrom(sfw.From, tables)
if err != nil {
return nil, err
}
if sfw.Where != nil {
result = &logical.Selection{
Child: result,
}
}
if sfw.SelList != nil {
mapper := newMapper(result.Provides())
columns := []*md.Column{}
for _, a := range sfw.SelList.Attributes {
matches, err := mapper.findMatches(a)
if err != nil {
return nil, err
}
columns = append(columns, matches...)
}
result = logical.NewProjection(
result,
columns)
}
return result, nil
}
func convertFrom(from ast.From, tables map[string]*md.Relation) (logical.Operation, error) {
if rel, ok := from.(*ast.Relation); ok {
return convertRelation(rel, tables)
}
if ij, ok := from.(*ast.InnerJoin); ok {
left, err := convertRelation(ij.Left, tables)
if err != nil {
return nil, err
}
right, err := convertRelation(ij.Right, tables)
if err != nil {
return nil, err
}
selection := &logical.Selection{
Child: &logical.Product{
LHS: left,
RHS: right,
},
//requires: []*md.Column{
// &md.Column{},
//},
}
return selection, nil
}
return nil, fmt.Errorf("unable to convert from relationship")
}
func convertRelation(relation *ast.Relation, tables map[string]*md.Relation) (*logical.Source, error) {
t := tables[relation.Name]
if t == nil {
t = &md.Relation{
Name: relation.Name,
Type: md.CsvType,
Source: relation.Name + ".csv",
}
columns, err := loadColumns(t.Name, t.Source)
if err != nil {
return nil, err
}
t.Columns = columns
tables[t.Name] = t
}
return &logical.Source{t.Name, t}, nil
}
func loadColumns(tableName, file string) ([]*md.Column, error) {
f, err := os.Open(file)
if err != nil {
return nil, fmt.Errorf("table %q could not be located at %q", tableName, file)
}
defer f.Close()
reader := csv.NewReader(f)
columnNames, err := reader.Read()
if err != nil {
return nil, fmt.Errorf("unable to read columns for table %q at %q", tableName, file)
}
var columns []*md.Column
for _, cn := range columnNames {
columns = append(columns, &md.Column{
Qualifier: tableName,
Name: cn,
Type: md.StringType,
})
}
return columns, nil
}