How to bind migrations with executable

后端 未结 3 1672
伪装坚强ぢ
伪装坚强ぢ 2021-01-21 01:22

I have a Go project using goose for Mysql migrations. I would like to bind the migrations to the package executable so that the executable can be deployed and used independently

3条回答
  •  盖世英雄少女心
    2021-01-21 01:57

    How to get a single file which can migrate database and work

    1. Install

      go get -u github.com/pressly/goose/cmd/goose
      
    2. Make app. I base it on examplemain.go and add run option. Suppose your project is located at github.com/user/project:

      package main
      
      import (
          "database/sql"
          "flag"
          "log"
          "os"
      
          "github.com/pressly/goose"
      
          // Init DB drivers. -- here I recommend remove unnecessary - but it's up to you
          _ "github.com/go-sql-driver/mysql"
          _ "github.com/lib/pq"
          _ "github.com/mattn/go-sqlite3"
          _ "github.com/ziutek/mymysql/godrv"
      
          // here our migrations will live  -- use your path 
          _ "github.com/user/project/migrations"
      )
      
      var (
          flags = flag.NewFlagSet("goose", flag.ExitOnError)
          dir   = flags.String("dir", ".", "directory with migration files")
      )
      
      func main() {
          flags.Usage = usage
          flags.Parse(os.Args[1:])
      
          args := flags.Args()
      
          //////
          if len(args) > 1 && args[0] == "run" {
             log.Printf("PROGRAM RUN\n")  //
             ..... 
             os.Exit(0)
          }
      
      
          if len(args) > 1 && args[0] == "create" {
              if err := goose.Run("create", nil, *dir, args[1:]...); err != nil {
                  log.Fatalf("goose run: %v", err)
              }
              return
          }
      
          if len(args) < 3 {
              flags.Usage()
              return
          }
      
          if args[0] == "-h" || args[0] == "--help" {
              flags.Usage()
              return
          }
      
          driver, dbstring, command := args[0], args[1], args[2]
      
          switch driver {
          case "postgres", "mysql", "sqlite3", "redshift":
              if err := goose.SetDialect(driver); err != nil {
                  log.Fatal(err)
              }
          default:
              log.Fatalf("%q driver not supported\n", driver)
          }
      
          switch dbstring {
          case "":
              log.Fatalf("-dbstring=%q not supported\n", dbstring)
          default:
          }
      
          if driver == "redshift" {
              driver = "postgres"
          }
      
          db, err := sql.Open(driver, dbstring)
          if err != nil {
              log.Fatalf("-dbstring=%q: %v\n", dbstring, err)
          }
      
          arguments := []string{}
          if len(args) > 3 {
              arguments = append(arguments, args[3:]...)
          }
      
          if err := goose.Run(command, db, *dir, arguments...); err != nil {
              log.Fatalf("goose run: %v", err)
          }
      }
      
      func usage() {
          log.Print(usagePrefix)
          flags.PrintDefaults()
          log.Print(usageCommands)
      }
      
      var (
          usagePrefix = `Usage: goose [OPTIONS] DRIVER DBSTRING COMMAND
      Drivers:
          postgres
          mysql
          sqlite3
          redshift
      Examples:
          goose sqlite3 ./foo.db status
          goose sqlite3 ./foo.db create init sql
          goose sqlite3 ./foo.db create add_some_column sql
          goose sqlite3 ./foo.db create fetch_user_data go
          goose sqlite3 ./foo.db up
          goose postgres "user=postgres dbname=postgres sslmode=disable" status
          goose mysql "user:password@/dbname?parseTime=true" status
          goose redshift "postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db"
      status
      Options:
      `
      
          usageCommands = `
      Commands:
          up                   Migrate the DB to the most recent version available
          up-to VERSION        Migrate the DB to a specific VERSION
          down                 Roll back the version by 1
          down-to VERSION      Roll back to a specific VERSION
          redo                 Re-run the latest migration
          status               Dump the migration status for the current DB
          version              Print the current version of the database
          create NAME [sql|go] Creates new migration file with next version
      `
      )
      
    3. Create folder for migrations:

      mkdir migrations && cd migrations
      
    4. Create first migrations. We will use go-style migrations:

      goose mysql "user:password@/dbname?parseTime=true" create init go
      

      You'll get a file 00001_init.go with Go code. Migrations are baked in it as SQL-commands. Just edit them as you need.

    5. Then go to the main folder and build the application:

      cd ..
      go build -v -o myapp *.go
      
    6. You'll get a file myapp with all the migrations baked in it. To check move it to some other place, for example to /tmp folder, and run from there:

      ./myapp mysql "user:password@/dbname?parseTime=true" status
      
    7. Run your app:

      ./myapp run
      

    Result

    You have single file which can be used as a migration tool so as a working application itself. All the migration are buil-it. In source code they are stored in a subpackage migrations - so it's easy to edit.

提交回复
热议问题