graphql-engine/cli/commands/migrate.go

132 lines
3.1 KiB
Go
Raw Normal View History

2018-06-24 16:40:48 +03:00
package commands
import (
"fmt"
"net/url"
"runtime"
"strings"
2018-06-24 16:40:48 +03:00
"github.com/hasura/graphql-engine/cli"
"github.com/hasura/graphql-engine/cli/migrate"
mig "github.com/hasura/graphql-engine/cli/migrate/cmd"
"github.com/hasura/graphql-engine/cli/version"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
2018-06-24 16:40:48 +03:00
"github.com/spf13/cobra"
// Initialize migration drivers
_ "github.com/hasura/graphql-engine/cli/migrate/database/hasuradb"
_ "github.com/hasura/graphql-engine/cli/migrate/source/file"
2018-06-24 16:40:48 +03:00
)
// NewMigrateCmd returns the migrate command
2018-06-24 16:40:48 +03:00
func NewMigrateCmd(ec *cli.ExecutionContext) *cobra.Command {
migrateCmd := &cobra.Command{
Use: "migrate",
Short: "Manage migrations on the database",
SilenceUsage: true,
}
migrateCmd.AddCommand(
newMigrateApplyCmd(ec),
newMigrateStatusCmd(ec),
newMigrateCreateCmd(ec),
2018-06-24 16:40:48 +03:00
)
return migrateCmd
}
func newMigrate(dir string, db *url.URL, adminSecretValue string, logger *logrus.Logger, v *version.Version) (*migrate.Migrate, error) {
dbURL := getDataPath(db, getAdminSecretHeaderName(v), adminSecretValue)
fileURL := getFilePath(dir)
t, err := migrate.New(fileURL.String(), dbURL.String(), true, logger)
if err != nil {
return nil, errors.Wrap(err, "cannot create migrate instance")
}
return t, nil
}
// ExecuteMigration runs the actual migration
func ExecuteMigration(cmd string, t *migrate.Migrate, stepOrVersion int64) error {
var err error
switch cmd {
case "up":
err = mig.UpCmd(t, stepOrVersion)
case "down":
err = mig.DownCmd(t, stepOrVersion)
case "version":
var direction string
if stepOrVersion >= 0 {
direction = "up"
} else {
direction = "down"
stepOrVersion = -(stepOrVersion)
}
err = mig.GotoCmd(t, uint64(stepOrVersion), direction)
default:
err = fmt.Errorf("Invalid command")
}
return err
}
func executeStatus(t *migrate.Migrate) (*migrate.Status, error) {
status, err := t.GetStatus()
if err != nil {
return nil, err
}
return status, nil
}
func getDataPath(nurl *url.URL, adminSecretHeader, adminSecretValue string) *url.URL {
host := &url.URL{
Scheme: "hasuradb",
Host: nurl.Host,
Path: nurl.Path,
}
q := nurl.Query()
// Set sslmode in query
switch scheme := nurl.Scheme; scheme {
case "https":
q.Set("sslmode", "enable")
default:
q.Set("sslmode", "disable")
}
if adminSecretValue != "" {
q.Add("headers", fmt.Sprintf("%s:%s", adminSecretHeader, adminSecretValue))
}
host.RawQuery = q.Encode()
return host
}
func getFilePath(dir string) *url.URL {
host := &url.URL{
Scheme: "file",
Path: dir,
}
// Add Prefix / to path if runtime.GOOS equals to windows
if runtime.GOOS == "windows" && !strings.HasPrefix(host.Path, "/") {
host.Path = "/" + host.Path
}
return host
}
const (
XHasuraAdminSecret = "X-Hasura-Admin-Secret"
XHasuraAccessKey = "X-Hasura-Access-Key"
)
func getAdminSecretHeaderName(v *version.Version) string {
if v.ServerSemver == nil {
return XHasuraAdminSecret
}
flags, err := v.GetServerFeatureFlags()
if err != nil {
return XHasuraAdminSecret
}
if flags.HasAccessKey {
return XHasuraAccessKey
}
return XHasuraAdminSecret
}