Skip to content

Commit

Permalink
Introduce table option and formatters
Browse files Browse the repository at this point in the history
  • Loading branch information
lucapette committed Apr 25, 2017
1 parent b14dc34 commit c227125
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 55 deletions.
20 changes: 19 additions & 1 deletion cmd/fakedata.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var usage = `
--limit n limits rows up to n [default: 10]
--help shows help information
--format f generates rows in f format [options: csv|tab|sql, default: " "]
--table t uses t for the table name of the sql statement [default: TABLE]
--version shows version information
`

Expand All @@ -28,6 +29,21 @@ var limitFlag = flag.Int("limit", 10, "limits rows up to n")
var helpFlag = flag.Bool("help", false, "shows help information")
var formatFlag = flag.String("format", "", "generators rows in f format")
var versionFlag = flag.Bool("version", false, "shows version information")
var tableFlag = flag.String("table", "TABLE", "uses t for the table name of the sql statement [default: TABLE]")

func getFormatter(format string) (f fakedata.Formatter) {
switch format {
case "csv":
f = fakedata.NewSeparatorFormatter(",")
case "tab":
f = fakedata.NewSeparatorFormatter("\t")
case "sql":
f = fakedata.NewSQLFormatter(*tableFlag)
default:
f = fakedata.NewSeparatorFormatter(" ")
}
return f
}

func main() {
if *versionFlag {
Expand Down Expand Up @@ -55,8 +71,10 @@ func main() {
rand.Seed(time.Now().UnixNano())

columns := fakedata.NewColumns(flag.Args())
formatter := getFormatter(*formatFlag)

for i := 0; i < *limitFlag; i++ {
fmt.Print(fakedata.GenerateRow(columns, *formatFlag))
fmt.Print(fakedata.GenerateRow(columns, formatter))
}
}

Expand Down
46 changes: 2 additions & 44 deletions pkg/fakedata/fakedata.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,9 @@ package fakedata

import (
"bytes"
"fmt"
"sort"
"strings"
)

func joinFunc(sep string) func(Columns, []string) string {
return func(columns Columns, values []string) string {
return strings.Join(values, sep)
}
}

func sqlFunc() func(Columns, []string) string {
return func(columns Columns, values []string) string {
sql := bytes.NewBufferString("INSERT INTO TABLE (")

sql.WriteString(strings.Join(columns.names(), ","))
sql.WriteString(") values (")

formattedValues := make([]string, len(columns))
for i, value := range values {
formattedValues[i] = fmt.Sprintf("'%s'", value)
}
sql.WriteString(strings.Join(formattedValues, ","))

sql.WriteString(");")
return sql.String()
}
}

func formatter(format string) (f func(Columns, []string) string) {
switch format {
case "tab":
f = joinFunc("\t")
case "csv":
f = joinFunc(",")
case "sql":
f = sqlFunc()
default:
f = joinFunc(" ")
}
return f
}

func generate(key string) string {
if f, ok := generators[key]; ok {
return f()
Expand All @@ -55,17 +15,15 @@ func generate(key string) string {

// GenerateRow generates a row of fake data using Columns
// in the specified format
func GenerateRow(columns Columns, format string) string {
func GenerateRow(columns Columns, formatter Formatter) string {
var output bytes.Buffer

f := formatter(format)

genValues := make([]string, len(columns))
for i, field := range columns {
genValues[i] = generate(field.Key)
}

output.WriteString(f(columns, genValues))
output.WriteString(formatter.Format(columns, genValues))

output.WriteString("\n")

Expand Down
24 changes: 14 additions & 10 deletions pkg/fakedata/fakedata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,31 @@ import (
)

func TestGenerateRow(t *testing.T) {
csv := fakedata.NewSeparatorFormatter(",")
def := fakedata.NewSeparatorFormatter(" ")
tab := fakedata.NewSeparatorFormatter("\t")

type args struct {
columns fakedata.Columns
format string
columns fakedata.Columns
formatter fakedata.Formatter
}
tests := []struct {
name string
args args
want string
}{
{"email", args{columns: fakedata.Columns{{Key: "email"}}, format: ""}, `.+?@.+?\..+`},
{"domain", args{columns: fakedata.Columns{{Key: "domain"}}, format: ""}, `.+?\..+?`},
{"username", args{columns: fakedata.Columns{{Key: "username"}}, format: ""}, `[a-zA-Z0-9]{2,}`},
{"duoble", args{columns: fakedata.Columns{{Key: "double"}}, format: ""}, `-?[0-9]+?(\.[0-9]+?)?`},
{"username domain", args{columns: fakedata.Columns{{Key: "username"}, {Key: "domain"}}, format: " "}, `[a-zA-Z0-9]{2,} .+?\..+?`},
{"username domain", args{columns: fakedata.Columns{{Key: "username"}, {Key: "domain"}}, format: "csv"}, `[a-zA-Z0-9]{2,},.+?\..+?`},
{"username domain", args{columns: fakedata.Columns{{Key: "username"}, {Key: "domain"}}, format: "tab"}, `[a-zA-Z0-9]{2,}\t.+?\..+?`},
{"email", args{columns: fakedata.Columns{{Key: "email"}}, formatter: def}, `.+?@.+?\..+`},
{"domain", args{columns: fakedata.Columns{{Key: "domain"}}, formatter: def}, `.+?\..+?`},
{"username", args{columns: fakedata.Columns{{Key: "username"}}, formatter: def}, `[a-zA-Z0-9]{2,}`},
{"duoble", args{columns: fakedata.Columns{{Key: "double"}}, formatter: def}, `-?[0-9]+?(\.[0-9]+?)?`},
{"username domain", args{columns: fakedata.Columns{{Key: "username"}, {Key: "domain"}}, formatter: def}, `[a-zA-Z0-9]{2,} .+?\..+?`},
{"username domain csv", args{columns: fakedata.Columns{{Key: "username"}, {Key: "domain"}}, formatter: csv}, `[a-zA-Z0-9]{2,},.+?\..+?`},
{"username domain tab", args{columns: fakedata.Columns{{Key: "username"}, {Key: "domain"}}, formatter: tab}, `[a-zA-Z0-9]{2,}\t.+?\..+?`},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := fakedata.GenerateRow(tt.args.columns, tt.args.format)
got := fakedata.GenerateRow(tt.args.columns, tt.args.formatter)

matched, err := regexp.MatchString(tt.want, got)
if err != nil {
Expand Down
55 changes: 55 additions & 0 deletions pkg/fakedata/formatter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package fakedata

import (
"bytes"
"fmt"
"strings"
)

// Formatter is that wraps the Format method we use to format each row
type Formatter interface {
Format(Columns, []string) string
}

// SeparatorFormatter is a Formatter for characther separated formats
type SeparatorFormatter struct {
Separator string
}

// Format as characther separated strings
func (f *SeparatorFormatter) Format(columns Columns, values []string) string {
return strings.Join(values, f.Separator)
}

// SQLFormatter is a Formatter for the SQL insert statement
type SQLFormatter struct {
Table string
}

// Format as SQL statements
func (f *SQLFormatter) Format(columns Columns, values []string) string {
sql := bytes.NewBufferString(fmt.Sprintf("INSERT INTO %s (", f.Table))

sql.WriteString(strings.Join(columns.names(), ","))
sql.WriteString(") values (")

formattedValues := make([]string, len(columns))
for i, value := range values {
formattedValues[i] = fmt.Sprintf("'%s'", value)
}
sql.WriteString(strings.Join(formattedValues, ","))

sql.WriteString(");")
return sql.String()
}

// NewSeparatorFormatter returns a SeparatorFormatter using the sep string as a separator
func NewSeparatorFormatter(sep string) (f *SeparatorFormatter) {
return &SeparatorFormatter{Separator: sep}

}

// NewSQLFormatter returns a SQLFormatter using the table string for table name generation
func NewSQLFormatter(table string) (f *SQLFormatter) {
return &SQLFormatter{Table: table}
}

0 comments on commit c227125

Please sign in to comment.