Add database setup commands

This commit is contained in:
Vikram Rangnekar
2019-09-28 11:34:03 -04:00
parent 527ea5044d
commit 7e4d14fbca
12 changed files with 220 additions and 90 deletions

View File

@ -35,102 +35,98 @@ var (
qcompile *qcode.Compiler
pcompile *psql.Compiler
authFailBlock int
rootCmd *cobra.Command
servCmd *cobra.Command
seedCmd *cobra.Command
migrateCmd *cobra.Command
statusCmd *cobra.Command
newMigrationCmd *cobra.Command
initCmd *cobra.Command
)
func Init() {
rootCmd = &cobra.Command{
logger = initLog()
rootCmd := &cobra.Command{
Use: "super-graph",
Short: "An instant high-performance GraphQL API. No code needed. https://supergraph.dev",
//Run: cmdServ,
}
seedCmd = &cobra.Command{
Use: "seed",
Short: "Run the seed script to seed the database",
Run: cmdSeed,
}
servCmd = &cobra.Command{
rootCmd.AddCommand(&cobra.Command{
Use: "serv",
Short: "Run the super-graph service",
Run: cmdServ,
}
})
migrateCmd = &cobra.Command{
Use: "migrate",
rootCmd.AddCommand(&cobra.Command{
Use: "db:create",
Short: "Create database",
Run: cmdDBCreate,
})
rootCmd.AddCommand(&cobra.Command{
Use: "db:drop",
Short: "Drop database",
Run: cmdDBDrop,
})
rootCmd.AddCommand(&cobra.Command{
Use: "db:seed",
Short: "Run the seed script to seed the database",
Run: cmdDBSeed,
})
rootCmd.AddCommand(&cobra.Command{
Use: "db:migrate",
Short: "Migrate the database",
Long: `Migrate the database to destination migration version.
Destination migration version can be one of the following value types:
An integer:
Migrate to the most recent migration.
e.g. migrate up
Rollback the most recent migration.
e.g. migrate down
Migrate to a specific migration.
e.g. tern migrate -d 42
e.g. migrate 42
"+" and an integer:
Migrate forward N steps.
e.g. tern migrate -d +3
e.g. migrate +3
"-" and an integer:
Migrate backward N steps.
e.g. tern migrate -d -2
e.g. migrate -2
"-+" and an integer:
Redo previous N steps (migrate backward N steps then forward N steps).
e.g. tern migrate -d -+1
The word "last":
Migrate to the most recent migration. This is the default value, so it is
never needed to specify directly.
e.g. tern migrate
e.g. tern migrate -d last
e.g. migrate -+1
`,
Run: cmdMigrate,
}
Run: cmdDBMigrate,
})
statusCmd = &cobra.Command{
Use: "status",
rootCmd.AddCommand(&cobra.Command{
Use: "db:status",
Short: "Print current migration status",
Run: cmdStatus,
}
Run: cmdDBStatus,
})
newMigrationCmd = &cobra.Command{
Use: "new NAME",
rootCmd.AddCommand(&cobra.Command{
Use: "db:new NAME",
Short: "Generate a new migration",
Long: "Generate a new migration with the next sequence number and provided name",
Run: cmdNewMigration,
}
Run: cmdDBNew,
})
initCmd = &cobra.Command{
Use: "init APP-NAME",
Short: "Initialize a new application",
rootCmd.AddCommand(&cobra.Command{
Use: "db:setup",
Short: "Setup database",
Long: "This command will create, migrate and seed the database",
Run: cmdDBSetup,
})
rootCmd.AddCommand(&cobra.Command{
Use: "new APP-NAME",
Short: "Create a new application",
Long: "Generate all the required files to start on a new Super Graph app",
Run: cmdInit,
}
logger = initLog()
Run: cmdNew,
})
rootCmd.Flags().StringVar(&confPath,
"path", "./config", "path to config files")
//cmdMigrate.Flags().StringVarP(&cliOptions.destinationVersion,
// "destination", "d", "last", "destination migration version")
rootCmd.AddCommand(initCmd)
rootCmd.AddCommand(servCmd)
rootCmd.AddCommand(seedCmd)
rootCmd.AddCommand(migrateCmd)
rootCmd.AddCommand(statusCmd)
rootCmd.AddCommand(newMigrationCmd)
if err := rootCmd.Execute(); err != nil {
logger.Fatal().Err(err).Send()
}
@ -209,11 +205,10 @@ func initConf() (*config, error) {
return c, nil
}
func initDB(c *config) (*pgx.Conn, error) {
func initDB(c *config, useDB bool) (*pgx.Conn, error) {
config, _ := pgx.ParseConfig("")
config.Host = c.DB.Host
config.Port = c.DB.Port
config.Database = c.DB.DBName
config.User = c.DB.User
config.Password = c.DB.Password
config.RuntimeParams = map[string]string{
@ -221,6 +216,10 @@ func initDB(c *config) (*pgx.Conn, error) {
"search_path": c.DB.Schema,
}
if useDB {
config.Database = c.DB.DBName
}
switch c.LogLevel {
case "debug":
config.LogLevel = pgx.LogLevelDebug

View File

@ -2,17 +2,19 @@ package serv
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"strings"
"text/template"
rice "github.com/GeertJohan/go.rice"
"github.com/spf13/cobra"
"github.com/valyala/fasttemplate"
)
func cmdInit(cmd *cobra.Command, args []string) {
func cmdNew(cmd *cobra.Command, args []string) {
if len(args) != 1 {
cmd.Help()
os.Exit(1)
@ -32,8 +34,8 @@ func cmdInit(cmd *cobra.Command, args []string) {
return os.Mkdir(p, os.ModePerm)
})
ifNotExists(path.Join(appPath, "seed.js"), func(p string) error {
if v, err := tmpl.get("docker-compose.yml"); err == nil {
ifNotExists(path.Join(appPath, "Dockerfile"), func(p string) error {
if v, err := tmpl.get("Dockerfile"); err == nil {
return ioutil.WriteFile(p, v, 0644)
} else {
return err
@ -72,6 +74,14 @@ func cmdInit(cmd *cobra.Command, args []string) {
}
})
ifNotExists(path.Join(appConfigPath, "seed.js"), func(p string) error {
if v, err := tmpl.get("docker-compose.yml"); err == nil {
return ioutil.WriteFile(p, v, 0644)
} else {
return err
}
})
// Create app migrations folder and add relevant files
appMigrationsPath := path.Join(appConfigPath, "migrations")
@ -103,11 +113,14 @@ func newTempl(data map[string]string) *Templ {
func (t *Templ) get(name string) ([]byte, error) {
v := t.MustString(name)
b := bytes.Buffer{}
tm := template.Must(template.New(name).Parse(v))
tmpl := fasttemplate.New(v, "{%", "%}")
if err := tm.Execute(&b, t.data); err != nil {
return nil, err
}
tmpl.ExecuteFunc(&b, func(w io.Writer, tag string) (int, error) {
if val, ok := t.data[strings.TrimSpace(tag)]; ok {
return w.Write([]byte(val))
}
return 0, fmt.Errorf("unknown template variable '%s'", tag)
})
return b.Bytes(), nil
}

View File

@ -34,7 +34,63 @@ var newMigrationText = `-- Write your migrate up statements here
-- Then delete the separator line above.
`
func cmdNewMigration(cmd *cobra.Command, args []string) {
func cmdDBSetup(cmd *cobra.Command, args []string) {
cmdDBCreate(cmd, []string{})
cmdDBMigrate(cmd, []string{"up"})
cmdDBSeed(cmd, []string{})
}
func cmdDBCreate(cmd *cobra.Command, args []string) {
var err error
if conf, err = initConf(); err != nil {
logger.Fatal().Err(err).Msg("failed to read config")
}
ctx := context.Background()
conn, err := initDB(conf, false)
if err != nil {
logger.Fatal().Err(err).Msg("failed to connect to database")
}
defer conn.Close(ctx)
sql := fmt.Sprintf("create database %s", conf.DB.DBName)
_, err = conn.Exec(ctx, sql)
if err != nil {
logger.Fatal().Err(err).Msg("failed to create database")
}
logger.Info().Msgf("created database '%s'", conf.DB.DBName)
}
func cmdDBDrop(cmd *cobra.Command, args []string) {
var err error
if conf, err = initConf(); err != nil {
logger.Fatal().Err(err).Msg("failed to read config")
}
ctx := context.Background()
conn, err := initDB(conf, false)
if err != nil {
logger.Fatal().Err(err).Msg("failed to connect to database")
}
defer conn.Close(ctx)
sql := fmt.Sprintf("drop database if exists %s", conf.DB.DBName)
_, err = conn.Exec(ctx, sql)
if err != nil {
logger.Fatal().Err(err).Msg("failed to create database")
}
logger.Info().Msgf("dropped database '%s'", conf.DB.DBName)
}
func cmdDBNew(cmd *cobra.Command, args []string) {
if len(args) != 1 {
cmd.Help()
os.Exit(1)
@ -73,14 +129,21 @@ func cmdNewMigration(cmd *cobra.Command, args []string) {
logger.Info().Msgf("created migration '%s'", mpath)
}
func cmdMigrate(cmd *cobra.Command, args []string) {
func cmdDBMigrate(cmd *cobra.Command, args []string) {
var err error
if len(args) == 0 {
cmd.Help()
os.Exit(1)
}
dest := args[0]
if conf, err = initConf(); err != nil {
logger.Fatal().Err(err).Msg("failed to read config")
}
conn, err := initDB(conf)
conn, err := initDB(conf, true)
if err != nil {
logger.Fatal().Err(err).Msg("failed to connect to database")
}
@ -90,7 +153,8 @@ func cmdMigrate(cmd *cobra.Command, args []string) {
if err != nil {
logger.Fatal().Err(err).Msg("failed to initializing migrator")
}
//m.Data = config.Data
m.Data = getMigrationVars()
err = m.LoadMigrations(conf.MigrationsPath)
if err != nil {
@ -113,7 +177,6 @@ func cmdMigrate(cmd *cobra.Command, args []string) {
os.Exit(1)
}
dest := args[0]
mustParseDestination := func(d string) int32 {
var n int64
n, err = strconv.ParseInt(d, 10, 32)
@ -123,9 +186,12 @@ func cmdMigrate(cmd *cobra.Command, args []string) {
return int32(n)
}
if dest == "last" {
if dest == "up" {
err = m.Migrate()
} else if dest == "down" {
err = m.MigrateTo(currentVersion - 1)
} else if len(dest) >= 3 && dest[0:2] == "-+" {
err = m.MigrateTo(currentVersion - mustParseDestination(dest[2:]))
if err == nil {
@ -139,7 +205,8 @@ func cmdMigrate(cmd *cobra.Command, args []string) {
err = m.MigrateTo(currentVersion + mustParseDestination(dest[1:]))
} else {
//err = make(type, 0).MigrateTo(mustParseDestination(dest))
cmd.Help()
os.Exit(1)
}
if err != nil {
@ -168,14 +235,14 @@ func cmdMigrate(cmd *cobra.Command, args []string) {
}
func cmdStatus(cmd *cobra.Command, args []string) {
func cmdDBStatus(cmd *cobra.Command, args []string) {
var err error
if conf, err = initConf(); err != nil {
logger.Fatal().Err(err).Msg("failed to read config")
}
conn, err := initDB(conf)
conn, err := initDB(conf, true)
if err != nil {
logger.Fatal().Err(err).Msg("failed to connect to database")
}
@ -185,7 +252,8 @@ func cmdStatus(cmd *cobra.Command, args []string) {
if err != nil {
logger.Fatal().Err(err).Msg("failed to initialize migrator")
}
//m.Data = config.Data
m.Data = getMigrationVars()
err = m.LoadMigrations(conf.MigrationsPath)
if err != nil {
@ -247,3 +315,11 @@ func ExtractErrorLine(source string, position int) (ErrorLineExtract, error) {
return ele, nil
}
func getMigrationVars() map[string]interface{} {
return map[string]interface{}{
"app_name": strings.Title(conf.AppName),
"app_name_slug": strings.ToLower(strings.Replace(conf.AppName, " ", "_", -1)),
"env": strings.ToLower(os.Getenv("GO_ENV")),
}
}

View File

@ -14,7 +14,7 @@ import (
"github.com/spf13/cobra"
)
func cmdSeed(cmd *cobra.Command, args []string) {
func cmdDBSeed(cmd *cobra.Command, args []string) {
var err error
if conf, err = initConf(); err != nil {

View File

@ -133,9 +133,12 @@ func getConfigName() string {
case strings.HasPrefix(ge, "tes"):
return "test"
case strings.HasPrefix(ge, "dev"):
return "dev"
}
return "dev"
return ge
}
func getAuthFailBlock(c *config) int {