/
driver.go
195 lines (158 loc) · 5.06 KB
/
driver.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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package build
import (
"database/sql"
"djinn-ci.com/database"
"djinn-ci.com/driver"
"djinn-ci.com/errors"
"djinn-ci.com/manifest"
"github.com/andrewpillar/query"
"github.com/jmoiron/sqlx"
)
// Driver is the type that represents the driver being used by a build.
type Driver struct {
ID int64 `db:"id"`
BuildID int64 `db:"build_id"`
Type driver.Type `db:"type"`
Config manifest.Driver `db:"config"`
Build *Build `db:"-"`
}
// DriverStore is the type for creating Driver models in the database.
type DriverStore struct {
database.Store
// Build is the bound Build model. If not nil this will bind the Build
// model to any Driver models that are created. If not nil this will append
// a WHERE clause on the build_id column for all SELECT queries performed.
Build *Build
}
var (
_ database.Model = (*Driver)(nil)
_ database.Binder = (*DriverStore)(nil)
_ database.Loader = (*DriverStore)(nil)
driverTable = "build_drivers"
)
// NewDriverStore returns a new DriverStore for querying the build_drivers
// table. Each database passed to this function will be bound to the returned
// DriverStore.
func NewDriverStore(db *sqlx.DB, mm ...database.Model) *DriverStore {
s := &DriverStore{
Store: database.Store{DB: db},
}
s.Bind(mm...)
return s
}
// DriverModel is called along with database.ModelSlice to convert the given slice of
// Driver models to a slice of database.Model interfaces.
func DriverModel(dd []*Driver) func(int) database.Model {
return func(i int) database.Model {
return dd[i]
}
}
// Bind implements the database.Binder interface. This will only bind the model
// if they are pointers to Build.
func (d *Driver) Bind(mm ...database.Model) {
for _, m := range mm {
switch v := m.(type) {
case *Build:
d.Build = v
}
}
}
// SetPrimary implements the database.Model interface.
func (d *Driver) SetPrimary(id int64) { d.ID = id }
// Primary implements the database.Model interface.
func (d *Driver) Primary() (string, int64) { return "id", d.ID }
// IsZero implements the database.Model interface.
func (d *Driver) IsZero() bool {
return d == nil || d.ID == 0 && d.BuildID == 0 && d.Type == driver.Type(0) && len(d.Config) == 0
}
// JSON implements the database.Model interface. This returns an empty map.
func (*Driver) JSON(_ string) map[string]interface{} { return map[string]interface{}{} }
// Endpoint implements the database.Model interface. This returns an empty string.
func (*Driver) Endpoint(_ ...string) string { return "" }
// Values implements the database.Model interface. This will return a map with
// the following values, build_id, type, and config.
func (d *Driver) Values() map[string]interface{} {
return map[string]interface{}{
"build_id": d.BuildID,
"type": d.Type,
"config": d.Config,
}
}
// Bind implements the database.Binder interface. This will only bind the model
// if they are pointers to Build.
func (s *DriverStore) Bind(mm ...database.Model) {
for _, m := range mm {
switch v := m.(type) {
case *Build:
s.Build = v
}
}
}
// New returns a new Driver binding any non-nil models to it from the current
// DriverStore.
func (s *DriverStore) New() *Driver {
d := &Driver{
Build: s.Build,
}
if s.Build != nil {
d.BuildID = s.Build.ID
}
return d
}
// Create creates a new driver using the given configuration.
func (s *DriverStore) Create(cfg map[string]string) (*Driver, error) {
d := s.New()
d.Config = cfg
if err := d.Type.UnmarshalText([]byte(cfg["type"])); err != nil {
return d, errors.Err(err)
}
err := s.Store.Create(driverTable, d)
return d, errors.Err(err)
}
// Get returns a single Driver database, applying each query.Option that is
// given. The database.Where option is applied to the *Build bound database.
func (s *DriverStore) Get(opts ...query.Option) (*Driver, error) {
d := &Driver{
Build: s.Build,
}
opts = append([]query.Option{
database.Where(s.Build, "build_id"),
}, opts...)
err := s.Store.Get(d, driverTable, opts...)
if err == sql.ErrNoRows {
err = nil
}
return d, errors.Err(err)
}
// All returns a slice of Driver models, applying each query.Option that is
// given. The database.Where option is applied to the *Build bound database.
func (s *DriverStore) All(opts ...query.Option) ([]*Driver, error) {
dd := make([]*Driver, 0)
opts = append([]query.Option{
database.Where(s.Build, "build_id"),
}, opts...)
err := s.Store.All(&dd, driverTable, opts...)
if err == sql.ErrNoRows {
err = nil
}
for _, d := range dd {
d.Build = s.Build
}
return dd, errors.Err(err)
}
// Load loads in a slice of Driver models where the given key is in the list
// of given vals. Each database is loaded individually via a call to the given
// load callback. This method calls DriverStore.All under the hood, so any
// bound models will impact the models being loaded.
func (s *DriverStore) Load(key string, vals []interface{}, load database.LoaderFunc) error {
dd, err := s.All(query.Where(key, "IN", database.List(vals...)))
if err != nil {
return errors.Err(err)
}
for i := range vals {
for _, d := range dd {
load(i, d)
}
}
return nil
}