A few months ago I started working on one of my pet projects powered by Go using MySQL as persistent data storage. After some research to find the best solution to migrate my database schema, the most popular decisions suggested for me were auto-migrator by GORM and golang-migrate utility. Unfortunately, they did not meet my expectations.
Let me explain why...
First of all, I did not want to stick to the one specific ORM and moreover, I didn't want to use ORM in my project at all. I do not want to debate whether GORM is good or not, it was just that in my case it was much more convenient and easier to use the standard library database/sql.
I also wanted to have a long-term solution that would allow me to programmatically write code to the database without delving into sql queries. Therefore, the solution using pure sql did not suit me either.
Progress
Since none of the solutions I found worked for me, I decided to write a code that would fully meet my requirements and expectations.
At first, the solution I wrote was integrated into my migration files, but I immediately noticed that the code that is used to make changes to the database can be split into a separate package. This package was still an integral part of my project, but nevertheless began to grow into something more.
After a few weeks of using my package, I decided that it proved to be quite stable and can be published in the public domain for general use. So it became part of the open-source community and my first public Go project on GitHub 💪
MySQL database migrator designed to run migrations to your features and manage database schema update with intuitive go code. It is compatible with the latest MySQL v8.
Installation
To install migrator package, you need to install Go and set your Go workspace first.
The first need Go installed (version 1.13+ is required), then you can use the below Go command to install migrator.
How to write good documentation for your package? The package manager independently reads the comments in front of functions and variables, and then generates documentation for your package. So be careful what and how you write in the comment before the function. Try to describe in as much detail as possible what exactly is happening and for what exactly and how this or that part of your package is used. Unfortunately, there are currently no mechanisms for editing public documentation, so you cannot change the display order or formatting to your liking. Documentation is a visual display of your comments in front of exported functions and variables. 🤷♂️
go.mod file really matters. While the unexported package can be called whatever you like (fe. module migrator), published module should be named the same as the place where it is actually located (fe. module github.com/larapulse/migrator)
Features
Migrate, Rollback and Revert your migration:
m:=migrator.Migrator{Pool:migrations}migrated,err=m.Migrate(db)iferr!=nil{log.Errorf("Could not migrate: %v",err)os.Exit(1)}iflen(migrated)==0{log.Print("Nothing were migrated.")}for_,m:=rangemigrated{log.Printf("Migration: %s was migrated ✅",m)}log.Print("Migration did run successfully")
While Migrate runs all unexecuted migrations from the pool, you can also Rollback last executed migration batch, or Rollback whole migration list.
It creates migrations table and tracks there all executed migrations. You can set any name you like if you want.
Using transactional migrations. In case you have multiple commands within one migration and you want to be sure it is migrated properly, you might enable transactional execution per migration:
You may add any column definition to the database on your own, just be sure you implement migrator.columnType interface:
typecustomTypestringfunc(ctcustomType)buildRow()string{returnstring(ct)}posts:=migrator.Table{Name:"posts"}posts.UniqueID("id")posts.Column("data",customType("json not null"))posts.Timestamps()
The same logic is for adding custom commands to the schema to be migrated or reverted, just be sure you implement command interface:
At the time of this writing, the latest stable version is v1.2.0. As the next steps, it is planned to add more commands for interacting with the schema.
If necessary, in the next major versions drivers can be added for Postgres, SQLite, Microsoft SQL Server etc.
Result
At the moment, this package is a part of the go open source community and is versatile enough to be used in various projects. I really hope that it will also be useful to you when working with the database schema.
It is not popular yet, but I am really proud of it and believe it may grow fast with your support and contributions!