-
Notifications
You must be signed in to change notification settings - Fork 16
/
polluter.go
138 lines (113 loc) · 2.66 KB
/
polluter.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
package polluter
import (
"database/sql"
"io"
"github.com/go-redis/redis"
"github.com/pkg/errors"
"github.com/romanyx/jwalk"
)
var (
// ErrEngineNotSpecified causes if no engine option was used
// with the factory method.
ErrEngineNotSpecified = errors.New("specify database engine with the factory method option")
)
type parser interface {
parse(io.Reader) (jwalk.ObjectWalker, error)
}
type execer interface {
exec([]command) error
}
type commands []command
type command struct {
q string
args []interface{}
}
type builder interface {
build(jwalk.ObjectWalker) (commands, error)
}
type dbEngine interface {
builder
execer
}
// Polluter pollutes database with given input.
type Polluter struct {
dbEngine
parser
}
// Pollute parses input from the reader and
// tries to exec generated commands on a database.
// Use New factory function to generate.
func (p *Polluter) Pollute(r io.Reader) error {
obj, err := p.parser.parse(r)
if err != nil {
return errors.Wrap(err, "parse failed")
}
commands, err := p.dbEngine.build(obj)
if err != nil {
return errors.Wrap(err, "build commands failed")
}
if err := p.dbEngine.exec(commands); err != nil {
return errors.Wrap(err, "exec failed")
}
return nil
}
// Option defines options for Polluter.
type Option func(*Polluter)
// MySQLEngine option enables MySQL
// engine for poluter.
func MySQLEngine(db *sql.DB) Option {
return func(p *Polluter) {
p.dbEngine = mysqlEngine{db}
}
}
// PostgresEngine option enables
// Postgres engine for Polluter.
func PostgresEngine(db *sql.DB) Option {
return func(p *Polluter) {
p.dbEngine = postgresEngine{db}
}
}
// RedisEngine option enables
// Redis engine for Polluter.
func RedisEngine(cli *redis.Client) Option {
return func(p *Polluter) {
p.dbEngine = redisEngine{cli}
}
}
// JSONParser option enambles JSON
// parsing engine for seeding.
func JSONParser(p *Polluter) {
p.parser = jsonParser{}
}
// YAMLParser option enambles YAML
// parsing engine for seeding.
func YAMLParser(p *Polluter) {
p.parser = yamlParser{}
}
// New factory method returns initialized
// Polluter.
// For example to seed MySQL database with
// JSON input use:
// p := New(MySQLEngine(db))
// To seed Postgres database with YAML input
// use:
// p := New(PostgresEngine(db), YAMLParser)
func New(options ...Option) *Polluter {
p := Polluter{
parser: yamlParser{},
dbEngine: errorEngine{},
}
for i := range options {
options[i](&p)
}
return &p
}
type errorEngine struct{}
func (e errorEngine) build(_ jwalk.ObjectWalker) (commands, error) {
return commands{
command{},
}, ErrEngineNotSpecified
}
func (e errorEngine) exec(_ []command) error {
return ErrEngineNotSpecified
}