Contemplate or dwell on one's own success or another's misfortune with smugness or malignant pleasure.
Gloat is a modular SQL migration library for the Go programming language. Being a library, gloat can be easily integrated into your application or ORM.
If you are using gloat as a library, the main components you'll be dealing with
are migration, source, store and SQL executor. You'll be using those through the
methods on the Gloat struct.
db, err := sql.Open("postgres", "connection string")
if err != nil {
// Handle the *sql.DB creation error.
}
gl := gloat.Gloat{
Store: gloat.NewPostgreSQLStore(db),
Source: gloat.NewFileSystemSource("migrations"),
Executor: gloat.NewSQLExecutor(db),
}Migration holds all the relevant information for a migration. The content of the forward (up) side of a migration, the backward (down) side, a path and version. The version is used to determine the order of which the migrations would be executed. The path is the name in a store.
type Migration struct {
UpSQL []byte
DownSQL []byte
Path string
Version int64
}The Source interface represents a source of migration. The most common source
is the file system.
type Source interface {
Collect() (Migrations, error)
}gloat.NewFileSystemSource is a constructor function that creates a source
that collects migrations from a folder with the following structure:
migrations/
└── 20170329154959_introduce_domain_model
├── down.sql
└── up.sql
In the example above migrations is a folder that stores all of the
migrations. A migrations itself is a folder with a name in the form of
:timestamp_:name containing up.sql and down.sql files.
The up.sql file contains the SQL that's executed when a migration is applied:
CREATE TABLE users (
id bigserial PRIMARY KEY NOT NULL,
name character varying NOT NULL,
email character varying NOT NULL,
created_at timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL
);While down.sql is executed when a migration is reverted:
DROP TABLE users;If the down.sql file is not present, we say that a migration is irreversible.
The Store is an interface representing a place where the applied migrations are
recorded. The common thing is to store the migrations in a database table. The
gloat.DatabaseStore does just that. The gloat.NewPostgreSQLStore constructor
function creates such store that records the migration in a table called
schema_migrations. The table is automatically created if it does not exist.
type Store interface {
Source
Insert(*Migration, StoreExecer) error
Remove(*Migration, StoreExecer) error
}The Store.Insert records the migration version in to the schema_migrations
table, while Store.Remove deletes the column with the version from
the table. There are the following builtin store constructors:
// NewPostgreSQLStore creates a Store for PostgreSQL.
func NewPostgreSQLStore(db *sql.DB) Store {}
// NewMySQLStore creates a Store for MySQL.
func NewMySQLStore(db *sql.DB) Store {}
// NewSQLite3Store creates a Store for SQLite3.
func NewSQLite3Store(db *sql.DB) Store {}The Executor interface, well, it executes the migrations. For SQL migrations,
there is the gloat.SQLExecutor implementation. It's an interface,
nevertheless, so you can fake it out during testing.
type Executor interface {
Up(*Migration, Store) error
Down(*Migration, Store) error
}The executor executes the migration UpSQL or DownSQL sections.
A Gloat binds a migration Source, Store and Executor into one thing, so
it's easier to Apply, and Revert migrations.
gl := gloat.Gloat{
Store: gloat.NewPostgreSQLStore(db),
Source: gloat.NewFileSystemSource("migrations"),
Executor: gloat.NewSQLExecutor(db),
}
// Applies all of the unapplied migrations.
if migrations, err := gl.Unapplied(); err == nil {
for _, migration := range migrations {
gl.Apply(migration)
}
}
// Revert the last applied migration.
if migration, err := gl.Current(); err == nil {
gl.Revert(migration)
}Here is a description for the main Gloat methods.
// Unapplied returns the unapplied migrations in the current gloat.
func (c *Gloat) Unapplied() (Migrations, error) {}
// Current returns the latest applied migration. Even if no error is returned,
// the current migration can be nil.
//
// This is the case when the last applied migration is no longer available from
// the source or there are no migrations to begin with.
func (c *Gloat) Current() (*Migration, error) {}
// Apply applies a migration.
func (c *Gloat) Apply(migration *Migration) error {}
// Revert rollbacks a migration.
func (c *Gloat) Revert(migration *Migration) error {}