github.com/akkaraju-satvik/dbmap@v0.0.3-0.20240414054547-f818701a74f0/cmd/init.go (about)

     1  package cmd
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  	"os"
     7  	"regexp"
     8  	"strings"
     9  
    10  	"github.com/akkaraju-satvik/dbmap/config"
    11  	"github.com/akkaraju-satvik/dbmap/queries"
    12  	"github.com/fatih/color"
    13  	"github.com/spf13/cobra"
    14  
    15  	_ "github.com/lib/pq"
    16  )
    17  
    18  var initErrorStrings = map[string]string{
    19  	"migrations": "Error creating migrations directory\n %s",
    20  	"config":     "Error creating config file",
    21  	"table":      "Error creating migrations table\n %s",
    22  	"db":         "Could not find a database with the provided connection string\n %s",
    23  	"postgres":   "Please provide a valid postgres connection string\n Example: postgres://user:password@localhost:5432/dbname\n",
    24  }
    25  
    26  var initCmd = &cobra.Command{
    27  	Use:   "init",
    28  	Short: "Initialize dbmap in a project directory",
    29  	Long: `Initializes dbmap in a project directory by creating a migrations directory and a config file.
    30  
    31  The config file will contain the database connection string and the migrations directory path.`,
    32  	Run: func(cmd *cobra.Command, args []string) {
    33  		migrationsDir, err := cmd.Flags().GetString("migrations-dir")
    34  		if err != nil {
    35  			fmt.Println(err.Error())
    36  			os.Exit(1)
    37  		}
    38  		connection, err := cmd.Flags().GetString("db-connection")
    39  		if err != nil {
    40  			color.Red(err.Error())
    41  			os.Exit(1)
    42  		}
    43  		if connection == "" {
    44  			fmt.Printf("Enter the database connection string: ")
    45  			fmt.Scanln(&connection)
    46  			if connection == "" {
    47  				color.Red("Please provide a valid postgres connection string\n Example: postgres://user:password@localhost:5432/dbname\n")
    48  				os.Exit(1)
    49  			}
    50  		}
    51  		ssl, _ := cmd.Flags().GetBool("ssl")
    52  		if !strings.Contains(connection, "sslmode=require") && !ssl {
    53  			connection = connection + "?sslmode=disable"
    54  		}
    55  		err = initializeProject(migrationsDir, connection)
    56  		if err != nil {
    57  			color.Red(err.Error())
    58  			os.Exit(1)
    59  		}
    60  	},
    61  }
    62  
    63  func initializeProject(migrationsDir, connection string) error {
    64  	postgresConnStringRegex := regexp.MustCompile(`^postgres:\/\/.*\:.*@.*\/.*$`)
    65  	if !postgresConnStringRegex.MatchString(connection) {
    66  		return fmt.Errorf(initErrorStrings["postgres"])
    67  	}
    68  	if migrationsDir == "" {
    69  		migrationsDir = "migrations"
    70  	}
    71  	err := os.MkdirAll(migrationsDir, 0755)
    72  	if err != nil {
    73  		removeSetup()
    74  		return fmt.Errorf(initErrorStrings["migrations"], err.Error())
    75  	}
    76  	configFile, err := os.Create("dbmap.config.yaml")
    77  	if err != nil {
    78  		removeSetup()
    79  		return fmt.Errorf(initErrorStrings["config"])
    80  	}
    81  	defer configFile.Close()
    82  	configFileContent := strings.Replace(config.ConfigFile, "$MIGRATIONS_DIR", migrationsDir, 1)
    83  	configFileContent = strings.Replace(configFileContent, "$DB_URL", connection, 1)
    84  	_, err = configFile.WriteString(configFileContent)
    85  	if err != nil {
    86  		removeSetup()
    87  		return fmt.Errorf(initErrorStrings["config"])
    88  	}
    89  	db, err := sql.Open("postgres", connection)
    90  	if err != nil {
    91  		removeSetup()
    92  		return fmt.Errorf(initErrorStrings["db"], err.Error())
    93  	}
    94  	defer db.Close()
    95  	_, err = db.Exec(queries.InitQuery)
    96  	if err != nil {
    97  		removeSetup()
    98  		return fmt.Errorf(initErrorStrings["table"], err.Error())
    99  	}
   100  	color.Green("Setup complete")
   101  	return nil
   102  }
   103  
   104  func init() {
   105  	initCmd.Flags().StringP("migrations-dir", "d", "migrations", "Directory to store migration files")
   106  	initCmd.Flags().StringP("db-connection", "c", "", "Database connection string")
   107  	initCmd.Flags().BoolP("ssl", "s", false, "Use SSL for database connection")
   108  	rootCmd.AddCommand(initCmd)
   109  }
   110  
   111  func removeSetup() {
   112  	os.Remove("dbmap.config.yaml")
   113  	os.Remove("migrations")
   114  }