Skip to content

Commit

Permalink
Rewrite with Functional Option Pattern
Browse files Browse the repository at this point in the history
Rewrite with Functional Option Pattern to make
ReadOpts/WriteOpts optional.
  • Loading branch information
noborus committed Jun 13, 2019
1 parent c1e4878 commit fab4938
Show file tree
Hide file tree
Showing 21 changed files with 182 additions and 113 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# trdsql

[![Build Status](https://travis-ci.org/noborus/trdsql.svg?branch=master)](https://travis-ci.org/noborus/trdsql)
[![GoDoc](https://godoc.org/github.com/noborus/trdsql?status.svg)](https://https://godoc.org/github.com/noborus/trdsql)

A tool that can execute SQL queries on [CSV](https://tools.ietf.org/html/rfc4180), [LTSV](http://ltsv.org/), [JSON](https://tools.ietf.org/html/rfc7159) and [TBLN](https://tbln.dev/).

Expand Down Expand Up @@ -70,7 +71,7 @@ $ trdsql [options] SQL
* `-is` **int**
Skip header row.
* `-ir` **int**
Number of row preread for column determination. (default 1)
Number of row pre-read for column determination. (default 1)

### Output format

Expand Down Expand Up @@ -521,7 +522,7 @@ The SQL JOIN can be used.
user.csv
```CSV
1,userA
2,uesrB
2,userB
```

hist.csv
Expand All @@ -536,8 +537,8 @@ $ trdsql "SELECT u.c1,u.c2,h.c2 FROM user.csv as u LEFT JOIN hist.csv as h ON(u.
```
```
1,userA,2017-7-10
2,uesrB,2017-7-10
2,uesrB,2017-7-11
2,userB,2017-7-10
2,userB,2017-7-11
```

### PostgreSQL
Expand Down
3 changes: 1 addition & 2 deletions _example/import/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ func (f *importer) Import(db *trdsql.DB, query string) (string, error) {
func main() {
trdsql.EnableDebug()
d := importer{}
writeOpts := trdsql.NewWriteOpts()

trd := trdsql.NewTRDSQL(&d, trdsql.NewExporter(writeOpts, trdsql.NewWriter(writeOpts)))
trd := trdsql.NewTRDSQL(&d, trdsql.NewExporter(trdsql.NewWriter()))
err := trd.Exec("SELECT * FROM test")
if err != nil {
log.Fatal(err)
Expand Down
7 changes: 1 addition & 6 deletions _example/simple/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,8 @@ func (a *ArrayTable) PostWrite() error {
}

func exec(query string) [][]string {
readOpts := trdsql.NewReadOpts()
readOpts.InFormat = trdsql.CSV

writeOpts := trdsql.NewWriteOpts()
writer := &ArrayTable{}
// trd := trdsql.NewTRDSQL(trdsql.NewImporter(readOpts), trdsql.NewExporter(writeOpts, writer))
trd := trdsql.NewTRDSQL(nil, trdsql.NewExporter(writeOpts, writer))
trd := trdsql.NewTRDSQL(trdsql.NewImporter(), trdsql.NewExporter(writer))
trd.Driver = "postgres"
trd.Dsn = ""
err := trd.Exec(query)
Expand Down
44 changes: 29 additions & 15 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,17 @@ func Run(args []string) int {
cDSN string
guess bool
queryFile string
inFlag inputFlag
outFlag outputFlag
)

readOpts := trdsql.NewReadOpts()
writeOpts := trdsql.NewWriteOpts()
inFlag inputFlag
inDelimiter string
inHeader bool
inSkip int
inPreRead int

outFlag outputFlag
outDelimiter string
outHeader bool
)

flags := flag.NewFlagSet("trdsql", flag.ExitOnError)

Expand All @@ -110,18 +115,18 @@ func Run(args []string) int {
flags.BoolVar(&version, "version", false, "display version information.")
flags.BoolVar(&Debug, "debug", false, "debug print.")

flags.StringVar(&readOpts.InDelimiter, "id", ",", "Field delimiter for input.")
flags.BoolVar(&readOpts.InHeader, "ih", false, "The first line is interpreted as column names(CSV only).")
flags.IntVar(&readOpts.InSkip, "is", 0, "Skip header row.")
flags.IntVar(&readOpts.InPreRead, "ir", 1, "Number of row preread for column determination.")
flags.StringVar(&inDelimiter, "id", ",", "Field delimiter for input.")
flags.BoolVar(&inHeader, "ih", false, "The first line is interpreted as column names(CSV only).")
flags.IntVar(&inSkip, "is", 0, "Skip header row.")
flags.IntVar(&inPreRead, "ir", 1, "Number of row preread for column determination.")

flags.BoolVar(&inFlag.CSV, "icsv", false, "CSV format for input.")
flags.BoolVar(&inFlag.LTSV, "iltsv", false, "LTSV format for input.")
flags.BoolVar(&inFlag.JSON, "ijson", false, "JSON format for input.")
flags.BoolVar(&inFlag.TBLN, "itbln", false, "TBLN format for input.")

flags.StringVar(&writeOpts.OutDelimiter, "od", ",", "Field delimiter for output.")
flags.BoolVar(&writeOpts.OutHeader, "oh", false, "Output column name as header.")
flags.StringVar(&outDelimiter, "od", ",", "Field delimiter for output.")
flags.BoolVar(&outHeader, "oh", false, "Output column name as header.")

flags.BoolVar(&outFlag.CSV, "ocsv", true, "CSV format for output.")
flags.BoolVar(&outFlag.LTSV, "oltsv", false, "LTSV format for output.")
Expand Down Expand Up @@ -178,11 +183,20 @@ Options:
return 2
}

readOpts.InFormat = inputFormat(inFlag)
importer := trdsql.NewImporter(readOpts)
importer := trdsql.NewImporter(
trdsql.InFormat(inputFormat(inFlag)),
trdsql.InDelimiter(inDelimiter),
trdsql.InHeader(inHeader),
trdsql.InSkip(inSkip),
trdsql.InPreRead(inPreRead),
)

writeOpts.OutFormat = outputFormat(outFlag)
exporter := trdsql.NewExporter(writeOpts, trdsql.NewWriter(writeOpts))
w := trdsql.NewWriter(
trdsql.OutFormat(outputFormat(outFlag)),
trdsql.OutDelimiter(outDelimiter),
trdsql.OutHeader(outHeader),
)
exporter := trdsql.NewExporter(w)

trd := trdsql.NewTRDSQL(importer, exporter)

Expand Down
28 changes: 2 additions & 26 deletions exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ package trdsql
import (
"encoding/hex"
"fmt"
"io"
"log"
"os"
"strings"
"time"
"unicode/utf8"
Expand All @@ -16,38 +14,16 @@ type Exporter interface {
Export(db *DB, query string) error
}

// WriteOpts is the option to determine the writer process.
type WriteOpts struct {
OutFormat Format
OutDelimiter string
OutHeader bool
OutStream io.Writer
ErrStream io.Writer
}

// NewWriteOpts Returns WriteOpts.
func NewWriteOpts() WriteOpts {
return WriteOpts{
OutFormat: CSV,
OutDelimiter: ",",
OutHeader: false,
OutStream: os.Stdout,
ErrStream: os.Stderr,
}
}

// WriteFormat is a structure that includes Writer and WriteOpts,
// and is an implementation of the Exporter interface.
type WriteFormat struct {
WriteOpts
Writer
}

// NewExporter returns trdsql default Exporter.
func NewExporter(writeOpts WriteOpts, writer Writer) *WriteFormat {
func NewExporter(writer Writer) *WriteFormat {
return &WriteFormat{
WriteOpts: writeOpts,
Writer: writer,
Writer: writer,
}
}

Expand Down
7 changes: 2 additions & 5 deletions exporter_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package trdsql

import (
"reflect"
"testing"
)

Expand All @@ -22,9 +21,7 @@ func TestNewExporter(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
writeOpts := NewWriteOpts()
writeOpts.OutFormat = CSV
if got := NewExporter(writeOpts, NewWriter(writeOpts)); !reflect.DeepEqual(got.WriteOpts.OutFormat, tt.want) {
if got := NewExporter(NewWriter(OutFormat(tt.args.outFormat))); got == nil {
t.Errorf("NewExporter() = %v, want %v", got, tt.want)
}
})
Expand Down Expand Up @@ -58,7 +55,7 @@ func TestWriteFormat_Export(t *testing.T) {
if err != nil {
t.Fatal("Connect error")
}
e := NewExporter(NewWriteOpts(), nil)
e := NewExporter(nil)
if err := e.Export(db, tt.args.query); (err != nil) != tt.wantErr {
t.Errorf("WriteFormat.Export() error = %v, wantErr %v", err, tt.wantErr)
}
Expand Down
41 changes: 19 additions & 22 deletions importer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,15 @@ type Importer interface {
Import(db *DB, query string) (string, error)
}

// ReadOpts option to determine reader.
type ReadOpts struct {
InFormat Format
InPreRead int
InSkip int
InDelimiter string
InHeader bool
IsTemporary bool
// ReadFormat is a structure that includes ReadOpts,
// and is an implementation of the Importer interface.
type ReadFormat struct {
*ReadOpts
}

// NewReadOpts Returns ReadOpts.
func NewReadOpts() ReadOpts {
return ReadOpts{
func NewReadOpts() *ReadOpts {
return &ReadOpts{
InFormat: GUESS,
InPreRead: 1,
InSkip: 0,
Expand All @@ -38,14 +34,13 @@ func NewReadOpts() ReadOpts {
}
}

// ReadFormat is a structure that includes ReadOpts,
// and is an implementation of the Importer interface.
type ReadFormat struct {
ReadOpts
}

// NewImporter returns trdsql default Importer.
func NewImporter(readOpts ReadOpts) *ReadFormat {
func NewImporter(options ...ReadOpt) *ReadFormat {
readOpts := NewReadOpts()
for _, option := range options {
option(readOpts)
}

return &ReadFormat{
ReadOpts: readOpts,
}
Expand Down Expand Up @@ -167,7 +162,7 @@ func isSQLKeyWords(str string) bool {
// ImportFile is imports a file.
// Return the escaped table name and error.
// Do not import if file not found (no error)
func ImportFile(db *DB, fileName string, opts ReadOpts) (string, error) {
func ImportFile(db *DB, fileName string, readOpts *ReadOpts) (string, error) {
file, err := importFileOpen(fileName)
if err != nil {
debug.Printf("%s\n", err)
Expand All @@ -180,10 +175,12 @@ func ImportFile(db *DB, fileName string, opts ReadOpts) (string, error) {
}
}()

if opts.InFormat == GUESS {
opts.InFormat = guessExtension(fileName)
if readOpts.InFormat == GUESS {
readOpts.realFormat = guessExtension(fileName)
} else {
readOpts.realFormat = readOpts.InFormat
}
reader, err := NewReader(file, opts)
reader, err := NewReader(file, readOpts)
if err != nil {
return "", err
}
Expand All @@ -207,7 +204,7 @@ func ImportFile(db *DB, fileName string, opts ReadOpts) (string, error) {
debug.Printf("Column Names: [%v]", strings.Join(columnNames, ","))
debug.Printf("Column Types: [%v]", strings.Join(columnTypes, ","))

err = db.CreateTable(tableName, columnNames, columnTypes, opts.IsTemporary)
err = db.CreateTable(tableName, columnNames, columnTypes, readOpts.IsTemporary)
if err != nil {
return tableName, err
}
Expand Down
6 changes: 2 additions & 4 deletions importer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ func TestNewImporter(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
readOpts := NewReadOpts()
readOpts.InFormat = CSV
if got := NewImporter(readOpts); !reflect.DeepEqual(got.ReadOpts.InFormat, tt.want) {
if got := NewImporter(InFormat(CSV)); !reflect.DeepEqual(got.ReadOpts.InFormat, tt.want) {
t.Errorf("NewImporter() = %v, want %v", got, tt.want)
}
})
Expand Down Expand Up @@ -140,7 +138,7 @@ func TestImportFile(t *testing.T) {
type args struct {
db *DB
fileName string
opts ReadOpts
opts *ReadOpts
}
tests := []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion input_csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type CSVReader struct {
}

// NewCSVReader returns CSVReader and error.
func NewCSVReader(reader io.Reader, opts ReadOpts) (*CSVReader, error) {
func NewCSVReader(reader io.Reader, opts *ReadOpts) (*CSVReader, error) {
var err error
r := &CSVReader{}
if reader == nil {
Expand Down
2 changes: 1 addition & 1 deletion input_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type JSONReader struct {
}

// NewJSONReader returns JSONReader and error.
func NewJSONReader(reader io.Reader, opts ReadOpts) (*JSONReader, error) {
func NewJSONReader(reader io.Reader, opts *ReadOpts) (*JSONReader, error) {
if reader == nil {
return nil, errors.New("nil reader")
}
Expand Down
2 changes: 1 addition & 1 deletion input_ltsv.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type LTSVReader struct {
}

// NewLTSVReader returns LTSVReader and error.
func NewLTSVReader(reader io.Reader, opts ReadOpts) (*LTSVReader, error) {
func NewLTSVReader(reader io.Reader, opts *ReadOpts) (*LTSVReader, error) {
if reader == nil {
return nil, errors.New("nil reader")
}
Expand Down
2 changes: 1 addition & 1 deletion output_csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type CSVWriter struct {
}

// NewCSVWriter returns CSVWriter.
func NewCSVWriter(writeOpts WriteOpts) *CSVWriter {
func NewCSVWriter(writeOpts *WriteOpts) *CSVWriter {
var err error
w := &CSVWriter{}
w.writer = csv.NewWriter(writeOpts.OutStream)
Expand Down
2 changes: 1 addition & 1 deletion output_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type JSONWriter struct {
}

// NewJSONWriter returns JSONWriter.
func NewJSONWriter(writeOpts WriteOpts) *JSONWriter {
func NewJSONWriter(writeOpts *WriteOpts) *JSONWriter {
w := &JSONWriter{}
w.writer = json.NewEncoder(writeOpts.OutStream)
w.writer.SetIndent("", " ")
Expand Down
2 changes: 1 addition & 1 deletion output_ltsv.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type LTSVWriter struct {
}

// NewLTSVWriter returns LTSVWriter.
func NewLTSVWriter(writeOpts WriteOpts) *LTSVWriter {
func NewLTSVWriter(writeOpts *WriteOpts) *LTSVWriter {
w := &LTSVWriter{}
w.delimiter = "\t"
w.writer = bufio.NewWriter(writeOpts.OutStream)
Expand Down
2 changes: 1 addition & 1 deletion output_raw.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type RAWWriter struct {
}

// NewRAWWriter returns RAWWriter.
func NewRAWWriter(writeOpts WriteOpts) *RAWWriter {
func NewRAWWriter(writeOpts *WriteOpts) *RAWWriter {
var err error
w := &RAWWriter{}
w.writer = bufio.NewWriter(writeOpts.OutStream)
Expand Down
2 changes: 1 addition & 1 deletion output_tablewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type TWWriter struct {
}

// NewTWWriter returns TWWriter.
func NewTWWriter(writeOpts WriteOpts, markdown bool) *TWWriter {
func NewTWWriter(writeOpts *WriteOpts, markdown bool) *TWWriter {
w := &TWWriter{}
w.writer = tablewriter.NewWriter(writeOpts.OutStream)
w.writer.SetAutoFormatHeaders(false)
Expand Down
2 changes: 1 addition & 1 deletion output_tbln.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type TBLNWriter struct {
}

// NewTBLNWriter returns TBLNWriter.
func NewTBLNWriter(writeOpts WriteOpts) *TBLNWriter {
func NewTBLNWriter(writeOpts *WriteOpts) *TBLNWriter {
w := &TBLNWriter{}
w.writer = tbln.NewWriter(writeOpts.OutStream)
return w
Expand Down
Loading

0 comments on commit fab4938

Please sign in to comment.