问题
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 from any system, similar to JAR files in JAVA projects.
Is there an equivalent in Go to accomplish that?
回答1:
How to get a single file which can migrate database and work
Install
go get -u github.com/pressly/goose/cmd/goose
Make app. I base it on example
main.go
and addrun
option. Suppose your project is located atgithub.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 ` )
Create folder for migrations:
mkdir migrations && cd migrations
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.Then go to the main folder and build the application:
cd .. go build -v -o myapp *.go
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
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.
回答2:
If you use Docker you may put folder to the image.
If not projects like https://github.com/rakyll/statik or https://github.com/jteeuwen/go-bindata can help.
回答3:
If you're already using Goose, one option would be to write the migrations in Go instead of SQL. Based on the Go migrations example in the Goose repo, when you build the goose
binary here, it will bundle all the *.go
ones into the binary.
This was the output after I built the example and removed all files except the binary itself. The Go-based migration was embedded:
2017/10/31 11:22:31 Applied At Migration
2017/10/31 11:22:31 =======================================
2017/10/31 11:22:31 Mon Jun 19 21:56:00 2017 -- 00002_rename_root.go
If you're looking to use SQL-based migrations but don't want to take on additional dependencies, you could embed your SQL-based migrations into *.go
files as string constants, then, starting from the go-migrations
example, add an init phase to main.go
that writes them out to the current directory before proceeding.
来源:https://stackoverflow.com/questions/47030199/how-to-bind-migrations-with-executable