DEV Community

Kengo Wada
Kengo Wada

Posted on

GORM and Goose Migrations

Let's get started with handling migrations in Go with GORM and Goose.

Prerequisites

  • Go installed
  • GORM Supported SQL Database(I'll be using Postgresql)

Note:
You may refer to this repo for the file structure.

Install Goose Locally

Follow the steps here to install Goose for your operating system.

I tried using the installation script with Ubuntu 20.04 but I run into errors and found a solution here

wget http://github.com/golang-migrate/migrate/releases/latest/download/migrate.linux-amd64.deb
sudo dpkg -i migrate.linux-amd64.deb

goose --help // To test if install went well.
Enter fullscreen mode Exit fullscreen mode

Start Dummy Project

  • Create a directory
mkdir app
cd app
Enter fullscreen mode Exit fullscreen mode
  • Initialize it as a Go project
go mod init app
Enter fullscreen mode Exit fullscreen mode
  • Create main.go in the root of your project
package main

func main() {

}
Enter fullscreen mode Exit fullscreen mode

Getting Started With GORM

  • Create database directory
mkdir database
cd database
touch postgres.go
Enter fullscreen mode Exit fullscreen mode
  • Add the following to database/postgres.go
package database

import (
    "database/sql"
    "os"

    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

var dbURL := os.Getenv("GOOSE_DBSTRING")

var GORM_DB *gorm.DB
var SQL_DB *sql.DB
var DB_MIGRATOR gorm.Migrator

func ConnectToDatabase() (error) {
    db, err := gorm.Open(postgres.Open(dbURL), &gorm.Config{})
    if err == nil {
        GORM_DB = db
        SQL_DB, _ = db.DB()
        DB_MIGRATOR = db.Migrator()
    }
    return err
}
Enter fullscreen mode Exit fullscreen mode
  • At this point you'll have failed import errors, so let's fix that
go mod tidy
Enter fullscreen mode Exit fullscreen mode
  • Now create env in your projects root directory
mkdir env
touch env/goose.env
Enter fullscreen mode Exit fullscreen mode
  • Add the following to env/goose.env
export GOOSE_DRIVER='postgres'
export GOOSE_DBSTRING='postgres://user:password@localhost:5432/db_name?sslmode=disable'
export GOOSE_MIGRATION_DIR='./migrations'
Enter fullscreen mode Exit fullscreen mode
  • Now source the environment variables
source env/goose.env
Enter fullscreen mode Exit fullscreen mode

Creating Models and Migrations

  • Create a models directory in your projects root directory
mkdir models
touch models/user.go
Enter fullscreen mode Exit fullscreen mode
  • Add the following to models/user.go
package models

import (
    "gorm.io/gorm"
)

type User struct {
    *gorm.Model
    Name     string
    Email    string
    Password string
}
Enter fullscreen mode Exit fullscreen mode
  • Now run goose command to create migration file
mkdir migrations
goose -s create create_user
Enter fullscreen mode Exit fullscreen mode
  • After this, you'll have import errors. Let's fix this
go mod tidy
Enter fullscreen mode Exit fullscreen mode
  • Update the 00001_create_user.go file to have the following
package migrations

import (
    "app/database"
    "app/models"
    "context"
    "database/sql"

    "github.com/pressly/goose/v3"
)

func init() {
    goose.AddMigrationContext(upCreateUser, downCreateUser)
}

func upCreateUser(ctx context.Context, tx *sql.Tx) error {
    return database.DB_MIGRATOR.CreateTable(&models.User{})
}

func downCreateUser(ctx context.Context, tx *sql.Tx) error {
    return database.DB_MIGRATOR.DropTable(&models.User{})
}
Enter fullscreen mode Exit fullscreen mode

Bringing It All Together

  • Update the main.go file to have the following
package main

import (
    "app/database"
    _ "app/migrations" // This loads the migrations init functions

    "github.com/pressly/goose/v3"
)

func main() {
    err := database.ConnectToDatabase()
    if err != nil {
        panic(err)
    }

    if err := goose.SetDialect("postgres"); err != nil {
        panic(err)
    }
    if err := goose.Up(database.SQL_DB, "migrations"); err != nil {
        panic(err)
    }
    // Start server...
}
Enter fullscreen mode Exit fullscreen mode
  • Now you can run migrations before starting the server
go run .
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
__59cdb67 profile image
Руслан Искандаров • Edited

I got this error when running my main.go
failed to run Go migration: Go functions must be registered and built into a custom binary