migration

package module
v0.1.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 28, 2024 License: MIT Imports: 18 Imported by: 0

README

Go Migration

A simple to use database schema migration tool for go applications.

Installation

Open your favorite terminal app and cd into your go module enabled project root:

cd projectroot

[Replace "packagename" with your package's name]

To install the migration package, run:

go get -u github.com/lemmego/migration

Usage

This package resolves the DSN (Data Source Name) from the following env variables:

DB_DRIVER=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=test
DB_USERNAME=root
DB_PASSWORD=
DB_PARAMS=charset=utf8mb4&collation=utf8mb4_unicode_ci
MIGRATIONS_DIR="./cmd/migrations" # Optional

The supported DB_DRIVER values are sqlite, mysql and postgres

// projectroot/main.go
// Or,
// projectroot/cmd/myapp/main.go

package main

import (
  "github.com/joho/godotenv"
  "github.com/lemmego/migration/cmd"
  _ "projectroot/cmd/migrations"
)

func main() {
  if err := godotenv.Load(); err != nil {
    panic(err)
  }
  cmd.Execute()
}

Next, to create a sample migration, run:

go run . create create_users_table (If the main.go is located in projectroot/main.go)

Or,

go run ./cmd/myapp create create_users_table (If the main.go is located in projectroot/cmd/myapp/main.go)

Note: For all the examples (migrate up, migrate down, migrate status) below, we will assume that the main.go is located in projectroot/main.go and the go run . <subcommand> command will be used. Replace this with go run ./cmd/myapp <subcommand> if your main.go is in projectroot/cmd/myapp/main.go

If you didn't provide a MIGRATIONS_DIR env variable, A migration file will be created inside the projectroot/cmd/migrations/ directory. If the directory is not present in your project root, the migrate create ... command will create one for you. Open the migration file and populate the up() and down() method like this:

// 20220729200658_create_users_table.go

package migrations

import (
	"database/sql"
	"github.com/lemmego/migration"
)

func init() {
	migration.GetMigrator().AddMigration(&migration.Migration{
		Version: "20220729200658",
		Up:      mig_20220729200658_create_users_table_up,
		Down:    mig_20220729200658_create_users_table_down,
	})
}

func mig_20220729200658_create_users_table_up(tx *sql.Tx) error {
	_, err := tx.Exec("CREATE TABLE users ( name varchar(255) );")
	if err != nil {
		return err
	}
	return nil
}

func mig_20220729200658_create_users_table_down(tx *sql.Tx) error {
	_, err := tx.Exec("DROP TABLE users")
	if err != nil {
		return err
	}
	return nil
}

Alternatively, you could also use the db agnostic schema builder API. Which is useful for switching databases without having to rewrite the migrations.

// 20220729200658_create_users_table.go

package migrations

import (
	"database/sql"
	"github.com/lemmego/migration"
)

func init() {
	migration.GetMigrator().AddMigration(&migration.Migration{
		Version: "20220729200658",
		Up:      mig_20220729200658_create_users_table_up,
		Down:    mig_20220729200658_create_users_table_down,
	})
}

func mig_20220729200658_create_users_table_up(tx *sql.Tx) error {
  schema := migration.Create("users", func(t *migration.Table) {
    t.BigIncrements("id").Primary()
    t.ForeignID("org_id").Constrained() // "org_id" references the "id" column in the "orgs" table
    t.String("first_name", 255)
    t.String("last_name", 255)
    t.String("email", 255).Unique()
    t.String("password", 255)
    t.Text("bio").Nullable()
    t.DateTime("created_at", 0).Default("now()")
    t.DateTime("updated_at", 0).Default("now()")
  }).Build()

  if _, err := tx.Exec(schema); err != nil {
    return err
  }

  return nil
}

func mig_20220729200658_create_users_table_down(tx *sql.Tx) error {
  schema := migration.Drop("users").Build()
  if _, err := tx.Exec(schema); err != nil {
    return err
  }
  return nil
}

Once you've made sure that the expected environment variables are present in your .env file, you can run go run . migrate up

You should see something like the following:

Connecting to database...
Database connected!
Running migration 20220729200658
Finished running migration 20220729200658

Open your database client application (e.g. SequelPro, TablePlus) and open the database. You should see two new tables: schema_migrations and users.

You can revert the migration by running go run . migrate down. You should see something like this:

Connecting to database...
Database connected!
Reverting Migration 20220729200658
Finished reverting migration 20220729200658

Both the migrate up and the migrate down commands take a --step integer flag to indicate how many step should the migration run forward or backward:

E.g.:

go run . migrate down --step=1

There is also a migrate status command to see which migrations are currently pending and/or completed.

Adding "migrate" command to an existing command:

If your project already has a command, say rootCmd, you could add the MigrateCmd to that command to take full control of the package:

package mypackage

import "github.com/spf13/cobra"
import "github.com/lemmego/migration/cmd"

var rootCmd = &cobra.Command{}

func init() {
    rootCmd.AddCommand(cmd.MigrateCmd)
	rootCmd.Execute()
}
Renaming package for self-contained binary:

By default, the migration files will be created within the ./cmd/migrations directory. You can override the directory with the MIGRATIONS_DIR env variable. The package name of the migration files will follow the Go's convention of adopting the package name according to the directory the files are in, meaning if they are generated in a "migrations" directory, the package name will be "migrations". If you would like the package name to be "main" so that you can deploy it as a self-contained binary, follow these two steps:

  1. Rename the package name of each migration files to package main
  2. Add the following main.go file to the same directory where migrations are generated:
// Assuming your generated files are in the projectroot/cmd/migrations dir:
// projectroot/cmd/migrations/main.go

package main

import (
	"github.com/joho/godotenv"
	"github.com/lemmego/migration/cmd"
)

func main() {
	if err := godotenv.Load(); err != nil {
		panic(err)
	}
	cmd.Execute()
}

Now the package ./cmd/migrations is ready to be built and deployed as an independent binary.

Build:

go build ./cmd/migrations

Run:

./migrations migrate create/up/down/status

Documentation

The package documentation can be found at: https://pkg.go.dev/github.com/lemmego/migration

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

MIT

Documentation

Index

Constants

View Source
const (
	DriverSQLite   = "sqlite"
	DriverMySQL    = "mysql"
	DriverPostgres = "postgres"

	ColTypeIncrements    = "increments"
	ColTypeBigIncrements = "bigIncrements"
	ColTypeTinyInt       = "tinyInt"
	ColTypeBool          = "bool"
	ColTypeSmallInt      = "smallInt"
	ColTypeMediumInt     = "mediumInt"
	ColTypeInt           = "int"
	ColTypeBigInt        = "bigInt"
	ColTypeFloat         = "float"
	ColTypeDouble        = "double"
	ColTypeDecimal       = "decimal"
	ColTypeDate          = "date"
	ColTypeDateTime      = "dateTime"
	ColTypeDateTimeTz    = "dateTimeTz"
	ColTypeTime          = "time"
	ColTypeTimestamp     = "timestamp"
	ColTypeTimestampTz   = "timestampTz"
	ColTypeChar          = "char"
	ColTypeVarchar       = "varchar"
	ColTypeText          = "text"
	ColTypeTinyText      = "tinyText"
	ColTypeMediumText    = "mediumText"
	ColTypeLongText      = "longText"
	ColTypeBinary        = "binary"
	ColTypeVarBinary     = "varBinary"
	ColTypeBlob          = "blob"
	ColTypeTinyBlob      = "tinyBlob"
	ColTypeMediumBlob    = "mediumBlob"
	ColTypeLongBlob      = "longBlob"
	ColTypeEnum          = "enum"
	ColTypeSet           = "set"
)

Variables

View Source
var (
	ErrUnsupportedDialect = errors.New("unsupported driver")
)

Functions

func CreateMigration added in v0.1.0

func CreateMigration(name string) error

CreateMigration creates a migration file

func NewDB

func NewDB(dsn string, driverName string) *sql.DB

NewDB creates a new database connection

Types

type Column added in v0.1.0

type Column struct {
	// contains filtered or unexported fields
}

Column type is the column definition

func (*Column) Change added in v0.1.0

func (c *Column) Change()

Change changes the operation of the column to alter

func (*Column) Default added in v0.1.0

func (c *Column) Default(defaultValue any) *Column

Default adds the default value to the column

func (*Column) Done added in v0.1.0

func (c *Column) Done() *Table

Done returns the table that the column belongs to

func (*Column) NotNull added in v0.1.0

func (c *Column) NotNull() *Column

NotNull adds the not null attribute to the column

func (*Column) Nullable added in v0.1.0

func (c *Column) Nullable() *Column

Nullable adds the nullable attribute to the column

func (*Column) Primary added in v0.1.0

func (c *Column) Primary() *Column

Primary adds the primary attribute to the column

func (*Column) Type added in v0.1.0

func (c *Column) Type(dataType *DataType) *Column

Type adds a data type to the column

func (*Column) Unique added in v0.1.0

func (c *Column) Unique() *Column

Unique adds the unique attribute to the column

func (*Column) Unsigned added in v0.1.0

func (c *Column) Unsigned() *Column

Unsigned adds the unsigned attribute to the column

type DataSource added in v0.1.0

type DataSource struct {
	Driver   string
	Host     string
	Port     string
	Username string
	Password string
	Name     string
	Params   string
}

DataSource holds the necessary fields for a DSN (data source name)

func (*DataSource) String added in v0.1.0

func (ds *DataSource) String() (string, error)

String returns the string representation of the data source

type DataType added in v0.1.0

type DataType struct {
	// contains filtered or unexported fields
}

DataType represents a column type

func NewDataType added in v0.1.0

func NewDataType(columnName string, name string, dialect string) *DataType

NewDataType creates a new DataType

func (*DataType) AddSuffixes added in v0.1.0

func (dataType *DataType) AddSuffixes() *DataType

AddSuffixes adds suffixes to the column type

func (*DataType) AppendSufix added in v0.1.0

func (dataType *DataType) AppendSufix(suffix string) *DataType

AppendSufix appends a suffix to the column type

func (*DataType) SetColumnName added in v0.1.0

func (dataType *DataType) SetColumnName(columnName string)

SetColumnName sets the column name of the column

func (*DataType) SetDialect added in v0.1.3

func (dataType *DataType) SetDialect(dialect string)

SetDialect sets the driver of the column

func (*DataType) ToString added in v0.1.0

func (dataType *DataType) ToString() string

ToString returns the string representation of the column type

func (*DataType) WithEnumValues added in v0.1.0

func (dataType *DataType) WithEnumValues(enumValues []string) *DataType

WithEnumValues sets the enum values of the column

func (*DataType) WithLength added in v0.1.0

func (dataType *DataType) WithLength(length uint) *DataType

WithLength sets the length of the column

func (*DataType) WithPrecision added in v0.1.0

func (dataType *DataType) WithPrecision(precision uint) *DataType

WithPrecision sets the precision of the column

func (*DataType) WithScale added in v0.1.0

func (dataType *DataType) WithScale(scale uint) *DataType

WithScale sets the scale of the column

type Migration

type Migration struct {
	Version string
	Up      func(*sql.Tx) error
	Down    func(*sql.Tx) error
	// contains filtered or unexported fields
}

Migration represents a migration data type

type Migrator

type Migrator struct {
	Versions   []string
	Migrations map[string]*Migration
	// contains filtered or unexported fields
}

Migrator is a struct that holds the migrations

func GetMigrator

func GetMigrator() *Migrator

GetMigrator returns the migrator

func Init

func Init(db *sql.DB, dialect string) (*Migrator, error)

Init populates the fields of Migrator and returns it

func (*Migrator) AddMigration

func (m *Migrator) AddMigration(mg *Migration)

AddMigration adds a migration to the migrator

func (*Migrator) Down

func (m *Migrator) Down(step int) error

Down migration rolls back the last batch of migrations

func (*Migrator) MigrationStatus

func (m *Migrator) MigrationStatus() error

Status checks which migrations have run and which have not

func (*Migrator) Up

func (m *Migrator) Up(step int) error

Up method runs the migrations which have not yet been run

type Schema added in v0.1.0

type Schema struct {
	// contains filtered or unexported fields
}

Schema type is the schema definition

func Alter added in v0.1.0

func Alter(tableName string, tableFunc func(t *Table)) *Schema

Alter provides callback to alter an existing table, and returns a schema

func Create

func Create(tableName string, tableFunc func(t *Table)) *Schema

Create provides callback to create a new table, and returns a schema

func Drop added in v0.1.0

func Drop(tableName string) *Schema

Drop returns a schema to drop a table

func NewSchema added in v0.1.0

func NewSchema() *Schema

NewSchema creates a new schema based on the driver provided in the environment variable DB_DRIVER

func (*Schema) Build added in v0.1.0

func (s *Schema) Build() string

Build returns the SQL query for the schema

func (*Schema) HasCompositePrimaryKey added in v0.1.10

func (s *Schema) HasCompositePrimaryKey() bool

func (*Schema) HasForeignKeys added in v0.1.10

func (s *Schema) HasForeignKeys() bool

func (*Schema) HasNonPrimaryConstraints added in v0.1.10

func (s *Schema) HasNonPrimaryConstraints() bool

func (*Schema) HasPrimaryKeyOnTable added in v0.1.10

func (s *Schema) HasPrimaryKeyOnTable() bool

func (*Schema) HasUniqueConstraints added in v0.1.10

func (s *Schema) HasUniqueConstraints() bool

func (*Schema) String added in v0.1.0

func (s *Schema) String() string

String returns the SQL query for the schema

type Table added in v0.1.0

type Table struct {
	// contains filtered or unexported fields
}

Table type is the table definition

func (*Table) AddColumn added in v0.1.0

func (t *Table) AddColumn(name string, dataType *DataType) *Column

AddColumn adds a new column to the table

func (*Table) AlterColumn added in v0.1.0

func (t *Table) AlterColumn(name string, dataType string) *Column

AlterColumn alters a column in the table

func (*Table) BigIncrements added in v0.1.0

func (t *Table) BigIncrements(name string) *Column

BigIncrements adds an auto-incrementing column to the table with big integers

func (*Table) BigInt added in v0.1.2

func (t *Table) BigInt(name string) *Column

BigInt adds a big integer column to the table

func (*Table) Binary added in v0.1.0

func (t *Table) Binary(name string) *Column

Binary adds a binary column to the table

func (*Table) Boolean added in v0.1.0

func (t *Table) Boolean(name string) *Column

Boolean adds a boolean column to the table

func (*Table) Char added in v0.1.0

func (t *Table) Char(name string, length uint) *Column

Char adds a char column to the table

func (*Table) Date added in v0.1.0

func (t *Table) Date(name string) *Column

Date adds a date column to the table

func (*Table) DateTime added in v0.1.0

func (t *Table) DateTime(name string, precision uint) *Column

DateTime adds a date time column to the table

func (*Table) DateTimeTz added in v0.1.0

func (t *Table) DateTimeTz(name string, precision uint) *Column

DateTimeTz adds a date time with timezone column to the table

func (*Table) Decimal added in v0.1.0

func (t *Table) Decimal(name string, precision uint, scale uint) *Column

Decimal adds a decimal column to the table

func (*Table) Double added in v0.1.0

func (t *Table) Double(name string, precision uint, scale uint) *Column

Double adds a double column to the table

func (*Table) DropColumn added in v0.1.0

func (t *Table) DropColumn(name string) *Column

DropColumn drops a column from the table

func (*Table) DropForeignKey added in v0.1.0

func (t *Table) DropForeignKey(name string)

DropForeignKey drops a foreign key from the table

func (*Table) DropIndex added in v0.1.0

func (t *Table) DropIndex(indexName string)

DropIndex drops an index from the table

func (*Table) DropPrimaryKey added in v0.1.0

func (t *Table) DropPrimaryKey()

DropPrimaryKey drops the primary key from the table

func (*Table) DropUniqueKey added in v0.1.1

func (t *Table) DropUniqueKey(name string)

DropUniqueKey drops a unique constraint from the table

func (*Table) Enum added in v0.1.0

func (t *Table) Enum(name string, values ...string) *Column

Enum adds an enum column to the table

func (*Table) Float added in v0.1.0

func (t *Table) Float(name string, precision uint, scale uint) *Column

Float adds a float column to the table

func (*Table) Foreign added in v0.1.3

func (t *Table) Foreign(columns ...string) *foreignKey

Foreign adds a foreign key to the table

func (*Table) ForeignID added in v0.1.3

func (t *Table) ForeignID(column string) *foreignKey

ForeignID accepts an id column that references the primary column of another table

func (*Table) HasConstraints added in v0.1.0

func (t *Table) HasConstraints() bool

HasConstraints returns true if the table has constraints

func (*Table) Increments added in v0.1.0

func (t *Table) Increments(name string) *Column

Increments adds an auto-incrementing column to the table

func (*Table) Index added in v0.1.0

func (t *Table) Index(columns ...string)

Index adds an index to the table

func (*Table) Int added in v0.1.2

func (t *Table) Int(name string) *Column

Int adds an integer column to the table

func (*Table) MediumInt added in v0.1.0

func (t *Table) MediumInt(name string) *Column

MediumInt adds a medium integer column to the table

func (*Table) PrimaryKey added in v0.1.0

func (t *Table) PrimaryKey(columns ...string)

PrimaryKey adds a primary key to the table

func (*Table) RenameColumn added in v0.1.0

func (t *Table) RenameColumn(oldName string, newName string) *Column

RenameColumn renames a column in the table

func (*Table) SmallInt added in v0.1.0

func (t *Table) SmallInt(name string) *Column

SmallInt adds a small integer column to the table

func (*Table) String added in v0.1.0

func (t *Table) String(name string, length uint) *Column

String adds a varchar column to the table

func (*Table) Text added in v0.1.0

func (t *Table) Text(name string) *Column

Text adds a text column to the table

func (*Table) Time added in v0.1.0

func (t *Table) Time(name string, precision uint) *Column

Time adds a time column to the table

func (*Table) Timestamp added in v0.1.0

func (t *Table) Timestamp(name string, precision uint) *Column

Timestamp adds a timestamp column to the table

func (*Table) TimestampTz added in v0.1.0

func (t *Table) TimestampTz(name string, precision uint) *Column

TimestampTz adds a timestamp with timezone column to the table

func (*Table) TinyInt added in v0.1.0

func (t *Table) TinyInt(name string) *Column

TinyInt adds a tiny integer column to the table

func (*Table) UniqueKey added in v0.1.1

func (t *Table) UniqueKey(columns ...string)

UniqueKey adds a unique constraint to the table

func (*Table) UnsignedBigInt added in v0.1.0

func (t *Table) UnsignedBigInt(name string) *Column

UnsignedBigTInt adds an unsigned tiny integer column to the table

func (*Table) UnsignedInt added in v0.1.0

func (t *Table) UnsignedInt(name string) *Column

UnsignedInt adds an unsigned integer column to the table

func (*Table) UnsignedMediumInt added in v0.1.0

func (t *Table) UnsignedMediumInt(name string) *Column

UnsignedMediumInt adds an unsigned medium integer column to the table

func (*Table) UnsignedSmallInt added in v0.1.0

func (t *Table) UnsignedSmallInt(name string) *Column

UnsignedSmallInt adds an unsigned small integer column to the table

func (*Table) UnsignedTinyInt added in v0.1.0

func (t *Table) UnsignedTinyInt(name string) *Column

UnsignedTinyInt adds an unsigned tiny integer column to the table

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL