18
Migrations
With database created, we also need to create tables in which our data will be store. And best way to do that is using migrations. We will be using go-pg/migrations module. On GitHub page you can find basic installation and usage guide, and we will use that. Let's start by creating new directory migrations/
inside of project root and file file migrations/main.go
:
package main
import (
"flag"
"fmt"
"os"
"rgb/internal/database"
"rgb/internal/store"
"github.com/go-pg/migrations/v8"
)
const usageText = `This program runs command on the db. Supported commands are:
- init - creates version info table in the database
- up - runs all available migrations.
- up [target] - runs available migrations up to the target one.
- down - reverts last migration.
- reset - reverts all migrations.
- version - prints current db version.
- set_version [version] - sets db version without running migrations.
Usage:
go run *.go <command> [args]
`
func main() {
flag.Usage = usage
flag.Parse()
store.SetDBConnection(database.NewDBOptions())
db := store.GetDBConnection()
oldVersion, newVersion, err := migrations.Run(db, flag.Args()...)
if err != nil {
exitf(err.Error())
}
if newVersion != oldVersion {
fmt.Printf("migrated from version %d to %d\n", oldVersion, newVersion)
} else {
fmt.Printf("version is %d\n", oldVersion)
}
}
func usage() {
fmt.Print(usageText)
flag.PrintDefaults()
os.Exit(2)
}
func errorf(s string, args ...interface{}) {
fmt.Fprintf(os.Stderr, s+"\n", args...)
}
func exitf(s string, args ...interface{}) {
errorf(s, args...)
os.Exit(1)
}
As you can see this is similar to official example with some small changes. We are using SetDBConnection()
and GetDBConnection()
functions that we defined before in out store package. This is main entry point for running migrations, and next to this file, we need to add our actual migration files. Let’s create first migration file 1_addUsersTable.go
:
package main
import (
"fmt"
"github.com/go-pg/migrations/v8"
)
func init() {
migrations.MustRegisterTx(func(db migrations.DB) error {
fmt.Println("creating table users...")
_, err := db.Exec(`CREATE TABLE users(
id SERIAL PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
modified_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)`)
return err
}, func(db migrations.DB) error {
fmt.Println("dropping table users...")
_, err := db.Exec(`DROP TABLE users`)
return err
})
}
Run migrations using commands:
cd migrations/
go run *.go init
go run *.go up
This will create users table. As you can see, we added created_at
and modified_at
columns to our database table, so we also need to add them in our User struct definition in internal/store/users.go
:
type User struct {
ID int
Username string `binding:"required,min=5,max=30"`
Password string `binding:"required,min=7,max=32"`
CreatedAt time.Time
ModifiedAt time.Time
}
Try to create new account again to see that it's working now.
And we can see that user entry is created in database.
It's also possible to create migrations executable file:
cd migrations/
go build -o migrations *.go
And run it using:
./migrations init
./migrations up
18