Skip to content

Commit

Permalink
create down migrations for actions from console (close hasura#164) (h…
Browse files Browse the repository at this point in the history
  • Loading branch information
arvi3411301 authored and shahidhk committed Jul 20, 2018
1 parent 07ac9fe commit 75dbe35
Show file tree
Hide file tree
Showing 16 changed files with 360 additions and 301 deletions.
4 changes: 3 additions & 1 deletion cli/commands/migrate_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ type migrateCreateOptions struct {

func (o *migrateCreateOptions) run() error {
timestamp := getTime()
err := mig.CreateCmd(o.EC.MigrationDir, timestamp, o.name)
createOptions := mig.New(timestamp, o.name, o.EC.MigrationDir)
createOptions.IsCMD = true
err := createOptions.Create()
if err != nil {
return errors.Wrap(err, "error creating migration files")
}
Expand Down
19 changes: 16 additions & 3 deletions cli/migrate/api/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Response struct {
type Request struct {
Name string `json:"name"`
Up []interface{} `json:"up"`
Down []interface{} `json:"down"`
}

func MigrateAPI(c *gin.Context) {
Expand Down Expand Up @@ -79,7 +80,19 @@ func MigrateAPI(c *gin.Context) {
// Convert to Millisecond
timestamp := startTime.UnixNano() / int64(time.Millisecond)

err = cmd.CreateCmd(sourceURL.Path, timestamp, request.Name, request.Up)
createOptions := cmd.New(timestamp, request.Name, sourceURL.Path)
err = createOptions.SetMetaUp(request.Up)
if err != nil {
c.JSON(http.StatusInternalServerError, &Response{Code: "create_file_error", Message: err.Error()})
return
}
err = createOptions.SetMetaDown(request.Down)
if err != nil {
c.JSON(http.StatusInternalServerError, &Response{Code: "create_file_error", Message: err.Error()})
return
}

err = createOptions.Create()
if err != nil {
c.JSON(http.StatusInternalServerError, &Response{Code: "create_file_error", Message: err.Error()})
return
Expand All @@ -88,7 +101,7 @@ func MigrateAPI(c *gin.Context) {
// Rescan file system
err = t.ReScan()
if err != nil {
deleteErr := cmd.DeleteCmd(sourceURL.Path, timestamp)
deleteErr := createOptions.Delete()
if deleteErr != nil {
c.JSON(http.StatusInternalServerError, &Response{Code: "delete_file_error", Message: deleteErr.Error()})
return
Expand All @@ -98,7 +111,7 @@ func MigrateAPI(c *gin.Context) {
}

if err = t.Migrate(uint64(timestamp), "up"); err != nil {
deleteErr := cmd.DeleteCmd(sourceURL.Path, timestamp)
deleteErr := createOptions.Delete()
if deleteErr != nil {
c.JSON(http.StatusInternalServerError, &Response{Code: "delete_file_error", Message: deleteErr.Error()})
return
Expand Down
152 changes: 86 additions & 66 deletions cli/migrate/cmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,103 +21,123 @@ const (

var ext = []string{sqlFile, yamlFile}

func DeleteCmd(dir string, timestamp int64) error {
count := 0
type CreateOptions struct {
Version int64
Directory string
Name string
IsCMD bool
MetaUp []byte
MetaDown []byte
SQLUp []byte
SQLDown []byte
}

func New(version int64, name, directory string) *CreateOptions {
if runtime.GOOS == "windows" {
dir = strings.TrimPrefix(dir, "/")
directory = strings.TrimPrefix(directory, "/")
}
fileName := fmt.Sprintf("%v_", timestamp)
// scan directory
files, err := ioutil.ReadDir(dir)
return &CreateOptions{
Version: version,
Directory: directory,
Name: name,
MetaUp: []byte(`[]`),
MetaDown: []byte(`[]`),
SQLUp: []byte{},
SQLDown: []byte{},
}
}

func (c *CreateOptions) SetMetaUp(data interface{}) error {
t, err := json.Marshal(data)
if err != nil {
return err
}
yamlData, err := yaml.JSONToYAML(t)
if err != nil {
return err
}
c.MetaUp = yamlData
return nil
}

for _, fi := range files {
if !fi.IsDir() {
if strings.HasPrefix(fi.Name(), fileName) {
base := filepath.Join(dir, fi.Name())
err = deleteFile(base)
if err != nil {
return err
}
count = count + 1
}
}
func (c *CreateOptions) SetMetaDown(data interface{}) error {
t, err := json.Marshal(data)
if err != nil {
return err
}
if count == 0 {
return errors.New("Cannot find any migration file")
yamlData, err := yaml.JSONToYAML(t)
if err != nil {
return err
}
c.MetaDown = yamlData
return nil
}

func CreateCmd(dir string, timestamp int64, name string, options ...interface{}) error {
if runtime.GOOS == "windows" {
dir = strings.TrimPrefix(dir, "/")
func (c *CreateOptions) SetSQLUp(data string) error {
c.SQLUp = []byte(data)
return nil
}

func (c *CreateOptions) SetSQLDown(data string) error {
c.SQLDown = []byte(data)
return nil
}

func (c *CreateOptions) Create() error {
fileName := fmt.Sprintf("%v_%v.", c.Version, c.Name)
base := filepath.Join(c.Directory, fileName)
err := os.MkdirAll(c.Directory, os.ModePerm)
if err != nil {
return err
}
fileName := fmt.Sprintf("%v_%v.", timestamp, name)
base := filepath.Join(dir, fileName)
err := os.MkdirAll(dir, os.ModePerm)
// Create MetaUp
err = createFile(base+"up.yaml", c.MetaUp)
if err != nil {
return err
}

// If len(options) == 0, cmd else, api
if len(options) == 0 {
return createForCMD(base)
// Create MetaDown
err = createFile(base+"down.yaml", c.MetaDown)
if err != nil {
return err
}
return createForAPI(base, options[0])
}

func createForCMD(base string) error {
var data []byte
var err error
for _, v := range ext {
switch v {
case sqlFile:
data = []byte{}
case yamlFile:
bytes := []byte(`[]`)
data, err = yaml.JSONToYAML(bytes)
if err != nil {
return err
}
}
err = createFile(base+"up"+v, data)
if c.IsCMD {
err = createFile(base+"up.sql", c.SQLUp)
if err != nil {
return err
}
err = createFile(base+"down"+v, data)
err = createFile(base+"down.sql", c.SQLDown)
if err != nil {
return err
}
}
return nil
}

func createForAPI(base string, options interface{}) error {
var data []byte
for _, v := range ext {
switch v {
// Only yaml file for api-console
case yamlFile:
// Up file
t, err := json.Marshal(options)
if err != nil {
return err
}

data, err = yaml.JSONToYAML(t)
if err != nil {
return err
}
func (c *CreateOptions) Delete() error {
count := 0
fileName := fmt.Sprintf("%v_", c.Version)
// scan directory
files, err := ioutil.ReadDir(c.Directory)
if err != nil {
return err
}

err = createFile(base+"up"+v, data)
if err != nil {
return err
for _, fi := range files {
if !fi.IsDir() {
if strings.HasPrefix(fi.Name(), fileName) {
base := filepath.Join(c.Directory, fi.Name())
err = deleteFile(base)
if err != nil {
return err
}
count = count + 1
}
}
}
if count == 0 {
return errors.New("Cannot find any migration file")
}
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion cli/migrate/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ func (m *Migrate) versionUpExists(version uint64) error {
return os.ErrNotExist
}

// versionUpExists checks the source if either the up or down migration for
// versionDownExists checks the source if either the up or down migration for
// the specified migration version exists.
func (m *Migrate) versionDownExists(version uint64) error {
// try up migration first
Expand Down
2 changes: 1 addition & 1 deletion cli/migrate/source/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (f *File) Open(url string, logger *log.Logger) (source.Driver, error) {

for _, fi := range files {
if !fi.IsDir() {
m, err := source.DefaultParse(fi.Name())
m, err := source.DefaultParse(fi.Name(), p)
if err != nil {
continue // ignore files that we can't parse
}
Expand Down
26 changes: 19 additions & 7 deletions cli/migrate/source/file/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,28 @@ func Test(t *testing.T) {
// write files that meet driver test requirements
mustWriteFile(t, tmpDir, "1_foobar.up.sql", "1 up")
mustWriteFile(t, tmpDir, "1_foobar.down.sql", "1 down")
mustWriteFile(t, tmpDir, "1_foobar.up.yaml", "1 metaup")
mustWriteFile(t, tmpDir, "1_foobar.down.yaml", "1 metadown")
mustWriteFile(t, tmpDir, "1_foobar.up.yaml", `- args:
name: test
type: add_existing_table_or_view
`)
mustWriteFile(t, tmpDir, "1_foobar.down.yaml", `- args:
name: test
type: add_existing_table_or_view
`)

mustWriteFile(t, tmpDir, "3_foobar.up.sql", "3 up")

mustWriteFile(t, tmpDir, "4_foobar.up.yaml", "4 metaup")
mustWriteFile(t, tmpDir, "4_foobar.up.yaml", `- args:
name: test
type: add_existing_table_or_view
`)

mustWriteFile(t, tmpDir, "5_foobar.down.sql", "5 down")

mustWriteFile(t, tmpDir, "6_foobar.down.yaml", "6 metadown")
mustWriteFile(t, tmpDir, "6_foobar.down.yaml", `- args:
name: test
type: add_existing_table_or_view
`)

mustWriteFile(t, tmpDir, "8_foobar.up.sql", "7 up")
mustWriteFile(t, tmpDir, "8_foobar.down.sql", "7 down")
Expand Down Expand Up @@ -89,7 +101,7 @@ func TestOpenWithRelativePath(t *testing.T) {
t.Fatal(err)
}

mustWriteFile(t, filepath.Join(tmpDir, "foo"), "1_foobar.up.sql", "")
mustWriteFile(t, filepath.Join(tmpDir, "foo"), "1_foobar.up.sql", "test")

logger, _ := test.NewNullLogger()
f := &File{}
Expand Down Expand Up @@ -140,8 +152,8 @@ func TestOpenWithDuplicateVersion(t *testing.T) {
}
defer os.RemoveAll(tmpDir)

mustWriteFile(t, tmpDir, "1_foo.up.sql", "") // 1 up
mustWriteFile(t, tmpDir, "1_bar.up.sql", "") // 1 up
mustWriteFile(t, tmpDir, "1_foo.up.sql", "test") // 1 up
mustWriteFile(t, tmpDir, "1_bar.up.sql", "test") // 1 up

logger, _ := test.NewNullLogger()
f := &File{}
Expand Down
25 changes: 24 additions & 1 deletion cli/migrate/source/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package source
import (
"errors"
"fmt"
"io/ioutil"
"path/filepath"
"regexp"
"strconv"

yaml "github.com/ghodss/yaml"
)

var (
Expand All @@ -22,7 +26,7 @@ var (
var Regex = regexp.MustCompile(`^([0-9]+)_(.*)\.(` + string(Down) + `|` + string(Up) + `)\.(.*)$`)

// Parse returns Migration for matching Regex pattern.
func Parse(raw string) (*Migration, error) {
func Parse(raw string, directory string) (*Migration, error) {
var direction Direction
m := Regex.FindStringSubmatch(raw)
if len(m) == 5 {
Expand All @@ -40,6 +44,18 @@ func Parse(raw string) (*Migration, error) {
} else {
return nil, errors.New("Invalid Direction type")
}
data, err := ioutil.ReadFile(filepath.Join(directory, raw))
if err != nil {
return nil, err
}
var t []interface{}
err = yaml.Unmarshal(data, &t)
if err != nil {
return nil, err
}
if len(t) == 0 {
return nil, errors.New("Empty metadata file")
}
} else if m[4] == "sql" {
if m[3] == "up" {
direction = Up
Expand All @@ -48,6 +64,13 @@ func Parse(raw string) (*Migration, error) {
} else {
return nil, errors.New("Invalid Direction type")
}
data, err := ioutil.ReadFile(filepath.Join(directory, raw))
if err != nil {
return nil, err
}
if string(data[:]) == "" {
return nil, errors.New("Empty SQL file")
}
}

return &Migration{
Expand Down
Loading

0 comments on commit 75dbe35

Please sign in to comment.