-
Notifications
You must be signed in to change notification settings - Fork 0
/
builder.go
173 lines (146 loc) · 4.88 KB
/
builder.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
162
163
164
165
166
167
168
169
170
171
172
173
package tdat
import (
"time"
)
// Builder can be used to build models. It is easier to use Builder than to
// build tables 'by hand'.
type Builder struct {
tableBuilders []*TableBuilder
}
// NewBuilder creates a new Builder.
// Initially, the Builder is empty (contains no tables).
func NewBuilder() *Builder {
return &Builder{}
}
// AddTable adds a new table to the builder. It returns a new TableBuilder
// that can be used to add columns and rows to the table.
func (b *Builder) AddTable(name string) *TableBuilder {
tb := newTableBuilder(name)
b.tableBuilders = append(b.tableBuilders, tb)
return tb
}
// Build builds and validates the model. If validation fails,
// a non-nil error is returned.
func (b *Builder) Build() (*Model, error) {
tables := []*Table{}
for _, tb := range b.tableBuilders {
tables = append(tables, tb.build())
}
model := &Model{tables}
err := ValidateModel(model)
if err != nil {
return nil, err
}
return model, nil
}
// MustBuild is like Build, except it panics if
// validation fails.
func (b *Builder) MustBuild() *Model {
model, err := b.Build()
if err != nil {
panic(err)
}
return model
}
// ----------------------------------------------------
// TableBuilder is used to build Tables.
type TableBuilder struct {
name string
columns []*Column
rowBuilders []*RowBuilder
}
func newTableBuilder(name string) *TableBuilder {
return &TableBuilder{name: name}
}
// AddColumn adds a new column to the table.
func (b *TableBuilder) AddColumn(name string, columnType ValueType) {
b.columns = append(b.columns, &Column{name, columnType})
}
// AddIntColumn adds a new IntValue column to the table.
func (b *TableBuilder) AddIntColumn(name string) { b.AddColumn(name, IntValue) }
// AddFloatColumn adds a new FloatValue column to the table.
func (b *TableBuilder) AddFloatColumn(name string) { b.AddColumn(name, FloatValue) }
// AddBoolColumn adds a new BoolValue column to the table.
func (b *TableBuilder) AddBoolColumn(name string) { b.AddColumn(name, BoolValue) }
// AddStringColumn adds a new StringValue column to the table.
func (b *TableBuilder) AddStringColumn(name string) { b.AddColumn(name, StringValue) }
// AddTimeColumn adds a new TimeValue column to the table.
func (b *TableBuilder) AddTimeColumn(name string) { b.AddColumn(name, TimeValue) }
// AddRow adds a new row to the table. It returns a RowBuilder that can be used
// to add values to the new Row.
func (b *TableBuilder) AddRow() *RowBuilder {
rb := newRowBuilder()
b.rowBuilders = append(b.rowBuilders, rb)
return rb
}
func (b *TableBuilder) build() *Table {
rows := []*Row{}
for _, rb := range b.rowBuilders {
rows = append(rows, rb.build())
}
return &Table{b.name, b.columns, rows}
}
// ----------------------------------------------------
// RowBuilder can be used to build Rows.
type RowBuilder struct {
values []*Value
}
func newRowBuilder() *RowBuilder {
return &RowBuilder{}
}
// AddValue adds a value of a specific valueType to the Row.
// If val is nil, a null Value is added to the row.
// Otherwise, the val argument must fit the valueType:
//
// for IntValue:
// val must be of type int64
// for FloatValue:
// val must be of type float64
// for BoolValue:
// val must be of type bool
// for StringValue:
// val must be of type string
// for TimeValue:
// val must be of type time.Time
//
// If the type of val does not fit the valueType properly, AddValue will panic.
func (b *RowBuilder) AddValue(valueType ValueType, val interface{}) {
value := &Value{Type: valueType}
if val == nil {
value.Null = true
} else {
switch valueType {
case IntValue:
value.AsInt = val.(int64)
case FloatValue:
value.AsFloat = val.(float64)
case BoolValue:
value.AsBool = val.(bool)
case StringValue:
value.AsString = val.(string)
case TimeValue:
value.AsTime = val.(time.Time)
default:
panic("unknown valueType")
}
}
b.values = append(b.values, value)
}
// AddIntValue adds a Value of type IntValue.
// The val parameter must be nil or of type int64.
func (b *RowBuilder) AddIntValue(val interface{}) { b.AddValue(IntValue, val) }
// AddFloatValue adds a Value of type FloatValue.
// The val parameter must be nil or of type float64.
func (b *RowBuilder) AddFloatValue(val interface{}) { b.AddValue(FloatValue, val) }
// AddBoolValue adds a Value of type BoolValue.
// The val parameter must be nil or of type bool.
func (b *RowBuilder) AddBoolValue(val interface{}) { b.AddValue(BoolValue, val) }
// AddStringValue adds a Value of type StringValue.
// The val parameter must be nil or of type string.
func (b *RowBuilder) AddStringValue(val interface{}) { b.AddValue(StringValue, val) }
// AddTimeValue adds a Value of type TimeValue.
// The val parameter must be nil or of type time.Time.
func (b *RowBuilder) AddTimeValue(val interface{}) { b.AddValue(TimeValue, val) }
func (b *RowBuilder) build() *Row {
return &Row{b.values}
}