Skip to content

Commit

Permalink
Merge pull request #1 from mashiike/feature/new-with-sql-db
Browse files Browse the repository at this point in the history
Feature/new with sql db
  • Loading branch information
mashiike authored Nov 10, 2021
2 parents 187d8e8 + c4518aa commit 66a9d99
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 45 deletions.
33 changes: 14 additions & 19 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,25 @@ on:
branches:
- "!**/*"
tags:
- "v*"
- "v*.*.*"

jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.16
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.17

- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Check out code into the Go module directory
uses: actions/checkout@v2

- name: setup tools
run: |
mkdir ~/bin
curl -sL https://github.com/Songmu/goxz/releases/download/v0.4.1/goxz_v0.4.1_linux_amd64.tar.gz | tar zxvf - && install goxz_v0.4.1_linux_amd64/goxz ~/bin/
curl -sL https://github.com/tcnksm/ghr/releases/download/v0.13.0/ghr_v0.13.0_linux_amd64.tar.gz | tar zxvf - && install ghr_v0.13.0_linux_amd64/ghr ~/bin/
- name: dist
run: PATH=~/bin:$PATH make dist

- name: release
run: PATH=~/bin:$PATH make release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v1
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ jobs:
strategy:
matrix:
go:
- 1.16
- 1.17
name: Build
runs-on: ubuntu-latest
steps:
Expand Down
34 changes: 34 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
before:
hooks:
- go mod download
builds:
- env:
- CGO_ENABLED=0
main: ./cmd/mysqlbatch
binary: mysqlbatch
ldflags:
- -s -w
- -X main.Version=v{{.Version}}
- -X main.BuildDate=v{{.Date}}
goos:
- darwin
- linux
- windows
goarch:
- amd64
- arm64
release:
prerelease: true
archives:
checksum:
name_template: "checksums.txt"
snapshot:
name_template: "{{ .Env.NIGHTLY_VERSION }}"
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
17 changes: 2 additions & 15 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
GIT_VER := $(shell git describe --tags)
DATE := $(shell date +%Y-%m-%dT%H:%M:%S%z)
GO_VER := $(shell go version)

export GO111MODULE := on

.PHONY: test binary install clean dist
.PHONY: test clean
cmd/mysqlbatch/mysqlbatch: *.go cmd/mysqlbatch/*.go
cd cmd/mysqlbatch && go build -ldflags "-s -w -X 'main.Version=${GIT_VER}' -X 'main.BuildDate=${DATE}' -X 'main.GoVersion=${GO_VER}'" -gcflags="-trimpath=${PWD}"
cd cmd/mysqlbatch && go build .

test:
go test -race .
Expand All @@ -15,12 +11,3 @@ test:
clean:
rm -f cmd/mysqlbatch/mysqlbatch
rm -fr dist/

dist:
CGO_ENABLED=0 \
goxz -pv=$(GIT_VER) \
-build-ldflags="-s -w -X 'main.Version=${GIT_VER}' -X 'main.BuildDate=${DATE}' -X 'main.GoVersion=${GO_VER}'" \
-os=darwin,linux -arch=amd64 -d=dist ./cmd/mysqlbatch

release:
ghr -u mashiike -r mysqlbatch -n "$(GIT_VER)" $(GIT_VER) dist/
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,23 @@ $ mysqlbatch -u root -p ${password} -h localhost < batch.sql
```


## Usage as a library


```go
executer, err := mysqlbatch.Open("root:password@tcp(localhost:3306)/testdb?parseTime=true")
if err != nil {
//...
}
defer executer.Close()
if err := executer.Execute(strings.NewReader("UPDATE users SET name = 'hoge';")); err != nil {
//...
}
```

more infomation see [go doc](https://godoc.org/github.com/mashiike/mysqlbatch).

## License

see [LICENSE](https://github.com/mashiike/mysqlbatch/blob/master/LICENSE) file.

4 changes: 2 additions & 2 deletions cmd/mysqlbatch/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"log"
"os"
"os/signal"
"runtime"
"syscall"

"github.com/mashiike/mysqlbatch"
Expand All @@ -15,7 +16,6 @@ import (
var (
Version = "current"
BuildDate = "(no data)"
GoVersion = "(no data)"
)

func main() {
Expand All @@ -34,7 +34,7 @@ func main() {

if *versionFlag {
fmt.Printf("version : %s\n", Version)
fmt.Printf("go version: %s\n", GoVersion)
fmt.Printf("go version: %s\n", runtime.Version())
fmt.Printf("build date: %s\n", BuildDate)
return
}
Expand Down
54 changes: 48 additions & 6 deletions executer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/pkg/errors"
)

// Config is a connection setting to MySQL.
// Exists to generate a Golang connection DSN to MySQL
type Config struct {
DSN string
User string
Expand All @@ -24,6 +26,7 @@ type Config struct {
Database string
}

// NewDefaultConfig returns the config for connecting to the local MySQL server
func NewDefaultConfig() *Config {
return &Config{
User: "root",
Expand All @@ -32,6 +35,7 @@ func NewDefaultConfig() *Config {
}
}

//GetDSN returns a DSN dedicated to connecting to MySQL.
func (c *Config) GetDSN() string {
if c.DSN == "" {
return fmt.Sprintf(
Expand All @@ -46,32 +50,43 @@ func (c *Config) GetDSN() string {
return strings.TrimPrefix(c.DSN, "mysql://")
}

//Executer queries the DB. There is no parallelism
type Executer struct {
mu sync.Mutex
dsn string
db *sql.DB
lastExecuteTime time.Time
selectHook func(query string, columns []string, rows [][]string)
executeHook func(query string, rowsAffected int64, lastInsertId int64)
isSelectFunc func(query string) bool
timeCheckQuery string
}

//New return Executer with config
func New(config *Config) (*Executer, error) {
return Open(config.GetDSN())
}

//Open with dsn
func Open(dsn string) (*Executer, error) {
db, err := sql.Open("mysql", dsn)
if err != nil {
return nil, errors.Wrap(err, "mysql connect failed")
}
return NewWithDB(db), nil
}

// NewWithDB returns Executer with *sql.DB
// Note: Since it is made assuming MySQL, it may be inconvenient for other DBs.
func NewWithDB(db *sql.DB) *Executer {
db.SetMaxIdleConns(1)
db.SetMaxOpenConns(1)
return &Executer{
dsn: dsn,
db: db,
}, nil
db: db,
timeCheckQuery: "SELECT NOW()",
}
}

// Close DB
func (e *Executer) Close() error {
e.mu.Lock()
defer e.mu.Unlock()
Expand All @@ -81,10 +96,12 @@ func (e *Executer) Close() error {
return e.db.Close()
}

//Execute SQL
func (e *Executer) Execute(queryReader io.Reader) error {
return e.ExecuteContext(context.Background(), queryReader)
}

//ExecuteContext SQL execute with context.Context
func (e *Executer) ExecuteContext(ctx context.Context, queryReader io.Reader) error {
e.mu.Lock()
defer e.mu.Unlock()
Expand All @@ -95,7 +112,7 @@ func (e *Executer) ExecuteContext(ctx context.Context, queryReader io.Reader) er
}

func (e *Executer) updateLastExecuteTime(ctx context.Context) error {
row := e.db.QueryRowContext(ctx, "SELECT NOW()")
row := e.db.QueryRowContext(ctx, e.timeCheckQuery)
if err := row.Err(); err != nil {
return errors.Wrap(err, "get db time")
}
Expand All @@ -116,7 +133,15 @@ func (e *Executer) executeContext(ctx context.Context, queryReader io.Reader) er
}
if e.selectHook != nil {
upperedQuery := strings.ToUpper(query)
if strings.HasPrefix(upperedQuery, "SELECT") || strings.HasPrefix(upperedQuery, "SHOW") {
var isSelect bool
if e.isSelectFunc == nil {
if strings.HasPrefix(upperedQuery, "SELECT") || strings.HasPrefix(upperedQuery, "SHOW") || strings.HasPrefix(upperedQuery, `\`) {
isSelect = true
}
} else {
isSelect = e.isSelectFunc(upperedQuery)
}
if isSelect {
if err := e.queryContext(ctx, query); err != nil {
return errors.Wrap(err, "query rows failed")
}
Expand Down Expand Up @@ -175,18 +200,32 @@ func (e *Executer) queryContext(ctx context.Context, query string) error {
return nil
}

//LastExecuteTime returns last execute time on DB
func (e *Executer) LastExecuteTime() time.Time {
return e.lastExecuteTime
}

//SetExecuteHook set non select query hook
func (e *Executer) SetExecuteHook(hook func(query string, rowsAffected, lastInsertId int64)) {
e.executeHook = hook
}

//SetSelectHook set select query hook
func (e *Executer) SetSelectHook(hook func(query string, columns []string, rows [][]string)) {
e.selectHook = hook
}

//SetIsSelectFunc :Set the function to decide whether to execute in QueryContext
func (e *Executer) SetIsSelectFunc(f func(query string) bool) {
e.isSelectFunc = f
}

//SetTimeCheckQuery set time check query for non mysql db
func (e *Executer) SetTimeCheckQuery(query string) {
e.timeCheckQuery = query
}

//SetTimeCheckQuery set select query hook, but result is table string
func (e *Executer) SetTableSelectHook(hook func(query, table string)) {
e.selectHook = func(query string, columns []string, rows [][]string) {
var buf strings.Builder
Expand All @@ -198,10 +237,12 @@ func (e *Executer) SetTableSelectHook(hook func(query, table string)) {
}
}

// QueryScanner separate string by ; and delete newline
type QueryScanner struct {
*bufio.Scanner
}

//NewQueryScanner returns QueryScanner
func NewQueryScanner(queryReader io.Reader) *QueryScanner {
scanner := bufio.NewScanner(queryReader)
onSplit := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
Expand All @@ -224,6 +265,7 @@ func NewQueryScanner(queryReader io.Reader) *QueryScanner {
}
}

//Query return
func (s *QueryScanner) Query() string {
return strings.Trim(strings.NewReplacer(
"\r\n", " ",
Expand Down
8 changes: 6 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
module github.com/mashiike/mysqlbatch

go 1.16
go 1.17

require (
github.com/go-sql-driver/mysql v1.6.0
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/olekukonko/tablewriter v0.0.5
github.com/pkg/errors v0.9.1
github.com/sergi/go-diff v1.1.0
)

require (
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
)

0 comments on commit 66a9d99

Please sign in to comment.