Automatic migration planning for Beego
TL;DR
- Beego is an open-source web framework that's widely used in the Go community.
- Atlas is an open-source tool for inspecting, planning, linting and executing schema changes to your database.
- Developers using Beego can use Atlas to automatically plan schema migrations for them, based on the desired state of their schema instead of crafting them by hand.
Automatic migration planning for Beego
Beego is a popular web framework widely used in the Go community. Among many other features, Beego provides an ORM that allows work with popular databases such as MySQL, PostgreSQL, SQLite3, and more.
Beego allows developers to manage their database schemas using its syncdb feature, which is usually sufficient during development and in many simple cases.
However, at some point, teams need more control and decide to employ the versioned migrations methodology. Once this happens, the responsibility for planning migration scripts and making sure they are in line with what Beego expects at runtime is moved to developers.
Atlas can automatically plan database schema migrations for developers using Beego. Atlas plans migrations by calculating the diff between the current state of the database, and its desired state.
In the context of versioned migrations, the current state can be thought of as the database schema that would have been created by applying all previous migration scripts.
The desired schema of your application can be provided to Atlas via an External Schema Datasource which is any program that can output a SQL schema definition to stdout.
To use Atlas with Beego, users can utilize the Beego Atlas Provider, a small Go program that can be used to load the schema of a Beego project into Atlas.
In this guide, we will show how Atlas can be used to automatically plan schema migrations for Beego users.
Prerequisites
- A local Beego project - the project have a
go.mod
file describing it.
The Beego Atlas Provider works by creating a temporary Go program, compiling and running it to extract the schema of your Beego project. Therefore, you will need to have Go installed on your machine.
Using the Beego Atlas Provider
In this guide, we will use the Beego Atlas Provider to automatically plan schema migrations for a Beego project.
Installation
Install Atlas from macOS or Linux by running:
curl -sSf https://atlasgo.sh | sh
See atlasgo.io for more installation options.
Install the provider by running:
go get -u ariga.io/atlas-provider-beego
Standalone vs Go Program mode
The Atlas Beego Provider can be used in two modes:
- Standalone - If your application contains a package that registers all of its Beego models
during initialization (using an
func init()
function), you can use the provider directly to load your Beego schema into Atlas. - Go Program - In other cases, you can use the provider as a library directly in a Go program to load your Beego schema into Atlas.
Standalone mode
In your project directory, create a new file named atlas.hcl
with the following contents:
data "external_schema" "beego" {
program = [
"go",
"run",
"-mod=mod",
"ariga.io/atlas-provider-beego",
"load",
"--path", "./path/to/models",
"--dialect", "mysql", // | postgres | sqlite
]
}
env "beego" {
src = data.external_schema.beego.url
dev = "docker://mysql/8/dev"
migration {
dir = "file://migrations"
}
format {
migrate {
diff = "{{ sql . \" \" }}"
}
}
}
Be sure to replace ./path/to/models
with the path to the package that contains the registration
of your Beego models. It should look something like this:
func init() {
orm.RegisterModel(new(User), ...)
}
Go Program mode
In other cases, you can use the provider as a library directly in a Go program to load your Beego schema into Atlas. This can happen, for example, if your models are registered in multiple packages, or if you want to use the provider as part of a larger program.
Create a new program named loader/main.go
with the following contents:
package main
import (
"io"
"os"
"ariga.io/atlas-provider-beego/beegoschema"
"github.com/<yourorg>/<yourrepo>/path/to/models"
"github.com/beego/beego/v2/client/orm"
)
func main() {
stmts, err := beegoschema.New("mysql").Load()
if err != nil {
fmt.Fprintf(os.Stderr, "failed to load beego schema: %v\n", err)
os.Exit(1)
}
io.WriteString(os.Stdout, stmts)
}
func init() {
orm.RegisterModel(new(models.HotdogType), new(models.Stand), new(models.HotdogStock))
}
Be sure to replace github.com/<yourorg>/<yourrepo>/path/to/models
with the import path to your beego models.
In addition, replace the model types (e.g models.HotdogType
) with the types of your beego models.
Next, in your project directory, create a new file named atlas.hcl
with the following contents:
data "external_schema" "beego" {
program = [
"go",
"run",
"-mod=mod",
"./loader",
]
}
env "beego" {
src = data.external_schema.beego.url
dev = "docker://mysql/8/dev"
migration {
dir = "file://migrations"
}
format {
migrate {
diff = "{{ sql . \" \" }}"
}
}
}
Usage
Atlas supports a versioned migrations
workflow, where each change to the database is versioned and recorded in a migration file. You can use the
atlas migrate diff
command to automatically generate a migration file that will migrate the database
from its latest revision to the current application schema.
Suppose we have the following Beego models in our models
package:
package models
import "github.com/beego/beego/v2/client/orm"
type HotdogType struct {
Id int `orm:"auto;pk"`
Name string `orm:"unique"`
Description string `orm:"type(text)"`
Price float64 `orm:"digits(10);decimals(2);index"`
Inventory []*HotdogStock `orm:"reverse(many)"`
}
type Stand struct {
Id int `orm:"auto;pk"`
Name string `orm:"unique;index"`
Address string `orm:"type(text)"`
Description string `orm:"type(text)"`
Inventory []*HotdogStock `orm:"reverse(many)"`
}
type HotdogStock struct {
Id int `orm:"auto;pk"`
Quantity int `orm:"default(0)"`
Hotdog *HotdogType `orm:"rel(fk);on_delete(cascade);index"`
Stand *Stand `orm:"rel(fk);on_delete(cascade);index"`
}
func init() {
orm.RegisterModel(new(HotdogType), new(Stand), new(HotdogStock))
}
Using the Standalone mode configuration file for the provider, we can generate a migration file by running this command:
atlas migrate diff --env beego
Running this command will generate files similar to this in the migrations
directory:
migrations
|-- 20230627123246.sql
`-- atlas.sum
0 directories, 2 files
Examining the contents of 20230625161420.sql
:
-- Create "hotdog_stock" table
CREATE TABLE `hotdog_stock` (
`id` int NOT NULL AUTO_INCREMENT,
`quantity` int NOT NULL DEFAULT 0,
`hotdog_id` int NOT NULL,
`stand_id` int NOT NULL,
PRIMARY KEY (`id`),
INDEX `hotdog_stock_hotdog_id` (`hotdog_id`),
INDEX `hotdog_stock_stand_id` (`stand_id`)
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- Create "hotdog_type" table
CREATE TABLE `hotdog_type` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT "",
`description` longtext NOT NULL,
`price` decimal(10,2) NOT NULL DEFAULT 0.00,
PRIMARY KEY (`id`),
INDEX `hotdog_type_price` (`price`),
UNIQUE INDEX `name` (`name`)
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- Create "stand" table
CREATE TABLE `stand` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT "",
`address` longtext NOT NULL,
`description` longtext NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `name` (`name`)
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
Amazing, Atlas automatically generated a migration file that will create the hotdog_stock
,
hotdog_type
, and stand
tables in our database!
Next, alter the models.HotdogType
struct to modify the type of the Price
field and
drop the index on it:
type HotdogType struct {
Id int `orm:"auto;pk"`
Name string `orm:"unique"`
Description string `orm:"type(text)"`
- Price float64 `orm:"digits(10);decimals(2);index"`
+ Price float64
Inventory []*HotdogStock `orm:"reverse(many)"`
}
Re-run this command:
atlas migrate diff --env beego
Observe a new migration file is generated:
-- Modify "hotdog_type" table
ALTER TABLE `hotdog_type` MODIFY COLUMN `price` double NOT NULL DEFAULT 0, DROP INDEX `hotdog_type_price`;
Conclusion
In this guide we demonstrated how projects using Beego can use Atlas to automatically
plan schema migrations based only on their data model. To learn more about executing
these migrations against your production database, read the documentation for the
migrate apply
command.
Have questions? Feedback? Find our team on our Discord server.