mirror of https://github.com/pressly/goose.git
refactor: move sql parser into internal package (#444)
parent
db8feddea6
commit
2636c84dc8
|
@ -1,15 +1,15 @@
|
|||
package goose
|
||||
package sqlparser
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"errors"
|
||||
)
|
||||
|
||||
type parserState int
|
||||
|
@ -55,7 +55,7 @@ var bufferPool = sync.Pool{
|
|||
// within a statement. For these cases, we provide the explicit annotations
|
||||
// 'StatementBegin' and 'StatementEnd' to allow the script to
|
||||
// tell us to ignore semicolons.
|
||||
func parseSQLMigration(r io.Reader, direction bool) (stmts []string, useTx bool, err error) {
|
||||
func ParseSQLMigration(r io.Reader, direction bool) (stmts []string, useTx bool, err error) {
|
||||
var buf bytes.Buffer
|
||||
scanBuf := bufferPool.Get().([]byte)
|
||||
defer bufferPool.Put(scanBuf)
|
||||
|
@ -229,3 +229,20 @@ func endsWithSemicolon(line string) bool {
|
|||
|
||||
return strings.HasSuffix(prev, ";")
|
||||
}
|
||||
|
||||
var verbose bool
|
||||
|
||||
func SetVersbose(b bool) {
|
||||
verbose = b
|
||||
}
|
||||
|
||||
const (
|
||||
grayColor = "\033[90m"
|
||||
resetColor = "\033[00m"
|
||||
)
|
||||
|
||||
func verboseInfo(s string, args ...interface{}) {
|
||||
if verbose {
|
||||
log.Printf(grayColor+s+resetColor, args...)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package goose
|
||||
package sqlparser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -55,7 +55,7 @@ func TestSplitStatements(t *testing.T) {
|
|||
|
||||
for i, test := range tt {
|
||||
// up
|
||||
stmts, _, err := parseSQLMigration(strings.NewReader(test.sql), true)
|
||||
stmts, _, err := ParseSQLMigration(strings.NewReader(test.sql), true)
|
||||
if err != nil {
|
||||
t.Error(fmt.Errorf("tt[%v] unexpected error: %w", i, err))
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ func TestSplitStatements(t *testing.T) {
|
|||
}
|
||||
|
||||
// down
|
||||
stmts, _, err = parseSQLMigration(strings.NewReader(test.sql), false)
|
||||
stmts, _, err = ParseSQLMigration(strings.NewReader(test.sql), false)
|
||||
if err != nil {
|
||||
t.Error(fmt.Errorf("tt[%v] unexpected error: %w", i, err))
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ func TestSplitStatements(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestKeepEmptyLines(t *testing.T) {
|
||||
stmts, _, err := parseSQLMigration(strings.NewReader(emptyLineSQL), true)
|
||||
stmts, _, err := ParseSQLMigration(strings.NewReader(emptyLineSQL), true)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to parse SQL migration. %v", err)
|
||||
}
|
||||
|
@ -102,9 +102,9 @@ func TestUseTransactions(t *testing.T) {
|
|||
}
|
||||
|
||||
tests := []testData{
|
||||
{fileName: "./examples/sql-migrations/00001_create_users_table.sql", useTransactions: true},
|
||||
{fileName: "./examples/sql-migrations/00002_rename_root.sql", useTransactions: true},
|
||||
{fileName: "./examples/sql-migrations/00003_no_transaction.sql", useTransactions: false},
|
||||
{fileName: "testdata/valid-txn/00001_create_users_table.sql", useTransactions: true},
|
||||
{fileName: "testdata/valid-txn/00002_rename_root.sql", useTransactions: true},
|
||||
{fileName: "testdata/valid-txn/00003_no_transaction.sql", useTransactions: false},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
@ -112,7 +112,7 @@ func TestUseTransactions(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, useTx, err := parseSQLMigration(f, true)
|
||||
_, useTx, err := ParseSQLMigration(f, true)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ func TestParsingErrors(t *testing.T) {
|
|||
downFirst,
|
||||
}
|
||||
for i, sql := range tt {
|
||||
_, _, err := parseSQLMigration(strings.NewReader(sql), true)
|
||||
_, _, err := ParseSQLMigration(strings.NewReader(sql), true)
|
||||
if err == nil {
|
||||
t.Errorf("expected error on tt[%v] %q", i, sql)
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
-- +goose Up
|
||||
CREATE TABLE users (
|
||||
id int NOT NULL PRIMARY KEY,
|
||||
username text,
|
||||
name text,
|
||||
surname text
|
||||
);
|
||||
|
||||
INSERT INTO users VALUES
|
||||
(0, 'root', '', ''),
|
||||
(1, 'vojtechvitek', 'Vojtech', 'Vitek');
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE users;
|
|
@ -0,0 +1,9 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
UPDATE users SET username='admin' WHERE username='root';
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
UPDATE users SET username='root' WHERE username='admin';
|
||||
-- +goose StatementEnd
|
|
@ -0,0 +1,11 @@
|
|||
-- +goose NO TRANSACTION
|
||||
-- +goose Up
|
||||
CREATE TABLE post (
|
||||
id int NOT NULL,
|
||||
title text,
|
||||
body text,
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE post;
|
|
@ -8,6 +8,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pressly/goose/v3/internal/sqlparser"
|
||||
)
|
||||
|
||||
// MigrationRecord struct.
|
||||
|
@ -58,7 +60,8 @@ func (m *Migration) run(db *sql.DB, direction bool) error {
|
|||
}
|
||||
defer f.Close()
|
||||
|
||||
statements, useTx, err := parseSQLMigration(f, direction)
|
||||
sqlparser.SetVersbose(verbose)
|
||||
statements, useTx, err := sqlparser.ParseSQLMigration(f, direction)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ERROR %v: failed to parse SQL migration file: %w", filepath.Base(m.Source), err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue