golembic

package module
v0.0.0-...-8743f21 Latest Latest
Warning

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

Go to latest
Published: Aug 17, 2021 License: MIT Imports: 13 Imported by: 0

README

golembic-blend

SQL Schema Management in Go, inspired by sqlalchemy/alembic

GoDoc

The goal of this repository is to reframe github.com/dhermes/golembic in terms of the primitives in github.com/blend/go-sdk/db.

Examples

Typical Usage

If the database is empty, all migrations will be run:

$ make restart-postgres
...
$ go run ./examples/cmd/
2021-08-13T17:40:01.857253Z    [db.migration] -- applied -- Check table does not exist: golembic_migrations
2021-08-13T17:40:01.860942Z    [db.migration] -- plan -- Determine migrations that need to be applied
2021-08-13T17:40:01.86595Z     [db.migration] -- applied -- Finished planning migrations sequence
2021-08-13T17:40:01.875813Z    [db.migration] -- applied -- 3f34bd961f15: Create users table
2021-08-13T17:40:01.884822Z    [db.migration] -- applied -- 464bc456c630: Seed data in users table
2021-08-13T17:40:01.892263Z    [db.migration] -- applied -- 959456a8af88: Add city column to users table
2021-08-13T17:40:01.900737Z    [db.migration] -- applied -- 57393d6ddb95: Rename the root user [MILESTONE]
2021-08-13T17:40:01.924805Z    [db.migration] -- applied -- 4d07dd6af28d: Add index on user emails (concurrently)
2021-08-13T17:40:01.937113Z    [db.migration] -- applied -- 2a35ccd628bc: Create books table
2021-08-13T17:40:01.944698Z    [db.migration] -- applied -- 3196713ca7e6: Create movies table
2021-08-13T17:40:01.946226Z    [db.migration.stats] 9 applied 0 skipped 0 failed 9 total

After creation, the next run does nothing

$ go run ./examples/cmd/
2021-08-13T17:40:21.716154Z    [db.migration] -- skipped -- Check table does not exist: golembic_migrations
2021-08-13T17:40:21.720037Z    [db.migration] -- plan -- Determine migrations that need to be applied
2021-08-13T17:40:21.726482Z    [db.migration] -- plan -- No migrations to run; latest revision: 3196713ca7e6
2021-08-13T17:40:21.726511Z    [db.migration] -- applied -- Finished planning migrations sequence
2021-08-13T17:40:21.728566Z    [db.migration.stats] 1 applied 1 skipped 0 failed 2 total

If we manually delete one, the last migration will get run

$ make psql
...
golembic=> DELETE FROM golembic_migrations WHERE revision = '3196713ca7e6';
DELETE 1
golembic=> DROP TABLE movies;
DROP TABLE
golembic=> \q
$
$
$ go run ./examples/cmd/
2021-08-13T17:40:43.830474Z    [db.migration] -- skipped -- Check table does not exist: golembic_migrations
2021-08-13T17:40:43.833663Z    [db.migration] -- plan -- Determine migrations that need to be applied
2021-08-13T17:40:43.839139Z    [db.migration] -- applied -- Finished planning migrations sequence
2021-08-13T17:40:43.849448Z    [db.migration] -- applied -- 3196713ca7e6: Create movies table
2021-08-13T17:40:43.850975Z    [db.migration.stats] 2 applied 1 skipped 0 failed 3 total
Error Mode: Stale Checkout

During development or in sandbox environments, sometimes a team member will try to run migrations with an out-of-date branch. Conversely, a team member could run a migration that has not been checked into the mainline branch. In either of these cases, the migrations table will contain an unknown migration.

We can artificially introduce a "new" migration to see what such a failure would look like:

$ make psql-reset
...
$ go run ./examples/cmd/
...
2021-08-13T17:41:27.957464Z    [db.migration] -- applied -- 3196713ca7e6: Create movies table
2021-08-13T17:41:27.959059Z    [db.migration.stats] 9 applied 0 skipped 0 failed 9 total
$
$ make psql
...
golembic=> INSERT INTO golembic_migrations (serial_id, revision, previous) VALUES (7, 'not-in-sequence', '3196713ca7e6');
INSERT 0 1
golembic=> \q
$
$ go run ./examples/cmd/
2021-08-13T17:41:54.157961Z    [db.migration] -- skipped -- Check table does not exist: golembic_migrations
2021-08-13T17:41:54.161573Z    [db.migration] -- plan -- Determine migrations that need to be applied
2021-08-13T17:41:54.167462Z    [db.migration] -- failed Finished planning migrations sequence -- No migration registered for revision; Revision: "not-in-sequence"
2021-08-13T17:41:54.169252Z    [db.migration.stats] 0 applied 1 skipped 1 failed 2 total
No migration registered for revision; Revision: "not-in-sequence"
exit status 1

If the "verify history" option is used (off by default) we get slightly more information at the cost of some more SQL queries used for verification:

$ go run ./examples/cmd/ --verify-history
2021-08-13T17:42:51.532835Z    [db.migration] -- skipped -- Check table does not exist: golembic_migrations
2021-08-13T17:42:51.535955Z    [db.migration] -- plan -- Determine migrations that need to be applied
2021-08-13T17:42:51.542234Z    [db.migration] -- failed -- Sequence has 7 migrations but 8 are stored in the table
2021-08-13T17:42:51.542296Z    [db.migration] -- failed Finished planning migrations sequence -- Migration stored in SQL doesn't match sequence
2021-08-13T17:42:51.543918Z    [db.migration.stats] 0 applied 1 skipped 1 failed 2 total
Migration stored in SQL doesn't match sequence
exit status 1

Similarly, if we can modify an existing entry in the sequence so it becomes unknown (vs. appending to the sequence):

$ make psql
...
golembic=> DELETE FROM golembic_migrations WHERE revision IN ('not-in-sequence', '3196713ca7e6');
DELETE 2
golembic=> INSERT INTO golembic_migrations (serial_id, revision, previous) VALUES (6, 'not-in-sequence', '2a35ccd628bc');
INSERT 0 1
golembic=> \q
$
$ go run ./examples/cmd/
2021-08-13T17:43:26.942161Z    [db.migration] -- skipped -- Check table does not exist: golembic_migrations
2021-08-13T17:43:26.946179Z    [db.migration] -- plan -- Determine migrations that need to be applied
2021-08-13T17:43:26.95287Z     [db.migration] -- failed Finished planning migrations sequence -- No migration registered for revision; Revision: "not-in-sequence"
2021-08-13T17:43:26.955163Z    [db.migration.stats] 0 applied 1 skipped 1 failed 2 total
No migration registered for revision; Revision: "not-in-sequence"
exit status 1
$
$
$ go run ./examples/cmd/ --verify-history
2021-08-13T17:43:36.111506Z    [db.migration] -- skipped -- Check table does not exist: golembic_migrations
2021-08-13T17:43:36.114598Z    [db.migration] -- plan -- Determine migrations that need to be applied
2021-08-13T17:43:36.119419Z    [db.migration] -- failed -- Stored migration 6: "not-in-sequence:2a35ccd628bc" does not match migration "3196713ca7e6:2a35ccd628bc" in sequence
2021-08-13T17:43:36.119526Z    [db.migration] -- failed Finished planning migrations sequence -- Migration stored in SQL doesn't match sequence
2021-08-13T17:43:36.121124Z    [db.migration.stats] 0 applied 1 skipped 1 failed 2 total
Migration stored in SQL doesn't match sequence
exit status 1
Error Mode: Milestone

During typical development, new migrations will be added over time. Sometimes a "milestone" migration must be applied before the application can move forward with rolling updates.

Let's simulate the time period at which the first 3 example migrations were checked in:

$ make psql-reset
...
$
$ go run ./examples/cmd/ --length 3
2021-08-13T17:43:55.509783Z    [db.migration] -- applied -- Check table does not exist: golembic_migrations
2021-08-13T17:43:55.512859Z    [db.migration] -- plan -- Determine migrations that need to be applied
2021-08-13T17:43:55.517287Z    [db.migration] -- applied -- Finished planning migrations sequence
2021-08-13T17:43:55.52841Z     [db.migration] -- applied -- 3f34bd961f15: Create users table
2021-08-13T17:43:55.536941Z    [db.migration] -- applied -- 464bc456c630: Seed data in users table
2021-08-13T17:43:55.543169Z    [db.migration] -- applied -- 959456a8af88: Add city column to users table
2021-08-13T17:43:55.544858Z    [db.migration.stats] 5 applied 0 skipped 0 failed 5 total

Then 2 more example migrations (57393d6ddb95 and 4d07dd6af28d) were merged in, the first of which was a milestone:

$ go run ./examples/cmd/ --length 5
2021-08-13T17:44:08.249128Z    [db.migration] -- skipped -- Check table does not exist: golembic_migrations
2021-08-13T17:44:08.253153Z    [db.migration] -- plan -- Determine migrations that need to be applied
2021-08-13T17:44:08.261251Z    [db.migration] -- failed -- Revision 57393d6ddb95 (1 / 2 migrations)
2021-08-13T17:44:08.261325Z    [db.migration] -- failed Finished planning migrations sequence -- If a migration sequence contains a milestone, it must be the last migration
2021-08-13T17:44:08.263539Z    [db.migration.stats] 0 applied 1 skipped 1 failed 2 total
If a migration sequence contains a milestone, it must be the last migration
exit status 1

This will fail because revision 57393d6ddb95 is a milestone and so can't be applied with any revisions after it. (The application needs to deploy and stabilize with a milestone migration before the next rolling update deploy can happen.) So the application must be deployed at a point where only 1 new migration is present:

$ go run ./examples/cmd/ --length 4
2021-08-13T17:44:21.688567Z    [db.migration] -- skipped -- Check table does not exist: golembic_migrations
2021-08-13T17:44:21.693548Z    [db.migration] -- plan -- Determine migrations that need to be applied
2021-08-13T17:44:21.701493Z    [db.migration] -- applied -- Finished planning migrations sequence
2021-08-13T17:44:21.715395Z    [db.migration] -- applied -- 57393d6ddb95: Rename the root user [MILESTONE]
2021-08-13T17:44:21.717678Z    [db.migration.stats] 2 applied 1 skipped 0 failed 3 total

and then deploy the latest changes after the previous deploy stabilizes:

$ go run ./examples/cmd/ --length 5
2021-08-13T17:44:25.22514Z     [db.migration] -- skipped -- Check table does not exist: golembic_migrations
2021-08-13T17:44:25.229023Z    [db.migration] -- plan -- Determine migrations that need to be applied
2021-08-13T17:44:25.234496Z    [db.migration] -- applied -- Finished planning migrations sequence
2021-08-13T17:44:25.260623Z    [db.migration] -- applied -- 4d07dd6af28d: Add index on user emails (concurrently)
2021-08-13T17:44:25.26268Z     [db.migration.stats] 2 applied 1 skipped 0 failed 3 total

Documentation

Overview

Package golembic is intended to provide tooling for managing SQL migrations in Go.

The underlying principles of golembic are as follows:

- Migrations should follow a straight line (from some root); this line should be verified to avoid merge conflicts causing "branching"

- The "current" state of the world will be tracked in a `migrations` table containing all migrations that have been applied.

- A series of migrations should be easy to use both in a script or as part of a larger piece of Go code

- Down migrations are not supported. The idea being that the risk of data loss from a down migration is not worth it and that writing down migrations can be more challenging than writing up migrations.

The design allows for running "arbitrary" code inside migrations so that even non-SQL tasks can be tracked as a "run-once" migration.

The name is a portmanteau of Go (the programming language) and `alembic`, the Python migrations package. The name `alembic` itself is motivated by the foundational ORM SQLAlchemy (an alembic is a distilling apparatus used by alchemists).

Index

Constants

View Source
const (
	// DefaultMetadataTable is the default name for the table used to store
	// metadata about migrations.
	DefaultMetadataTable = "golembic_migrations"
)

Variables

View Source
var (
	// ErrNotRoot is the error returned when attempting to start a sequence of
	// migrations with a non-root migration.
	ErrNotRoot = ex.Class("Root migration cannot have a previous migration set")
	// ErrMissingRevision is the error returned when attempting to register a migration
	// with no revision.
	ErrMissingRevision = ex.Class("A migration must have a revision")
	// ErrNoPrevious is the error returned when attempting to register a migration
	// with no previous.
	ErrNoPrevious = ex.Class("Cannot register a migration with no previous migration")
	// ErrPreviousNotRegistered is the error returned when attempting to register
	// a migration with a previous that is not yet registered.
	ErrPreviousNotRegistered = ex.Class("Cannot register a migration until previous migration is registered")
	// ErrAlreadyRegistered is the error returned when a migration has already been
	// registered.
	ErrAlreadyRegistered = ex.Class("Migration has already been registered")
	// ErrNilInterface is the error returned when a value satisfying an interface
	// is nil in a context where it is not allowed.
	ErrNilInterface = ex.Class("Value satisfying interface was nil")
	// ErrMigrationNotRegistered is the error returned when no migration has been
	// registered for a given revision.
	ErrMigrationNotRegistered = ex.Class("No migration registered for revision")
	// ErrMigrationMismatch is the error returned when the migration stored in
	// SQL does not match the registered migration.
	ErrMigrationMismatch = ex.Class("Migration stored in SQL doesn't match sequence")
	// ErrCannotInvokeUp is the error returned when a migration cannot invoke the
	// up function (e.g. if it is `nil`).
	ErrCannotInvokeUp = ex.Class("Cannot invoke up function for a migration")
	// ErrCannotPassMilestone is the error returned when a migration sequence
	// contains a milestone migration that is **NOT** the last step.
	ErrCannotPassMilestone = ex.Class("If a migration sequence contains a milestone, it must be the last migration")
)

Functions

func ApplyDynamic

func ApplyDynamic(ctx context.Context, s *migration.Suite, c *db.Connection) (err error)

ApplyDynamic applies a migrations suite. Rather than using a `range` over `s.Groups`, it uses a length check, which allows `s.Groups` to change dynamically during the iteration.

func GenerateSuite

func GenerateSuite(m *Manager) (*migration.Suite, error)

GenerateSuite generates a suite of migrations from a sequence of golembic migrations.

func PlanEventWrite

func PlanEventWrite(ctx context.Context, log logger.Log, revision, body string, status PlanStatus)

func QuoteIdentifier

func QuoteIdentifier(name string) string

QuoteIdentifier quotes an identifier, such as a table name, for usage in a query.

This implementation is vendored in here to avoid the side effects of importing `github.com/lib/pq`.

See: - https://github.com/lib/pq/blob/v1.8.0/conn.go#L1564-L1581 - https://www.sqlite.org/lang_keywords.html - https://github.com/ronsavage/SQL/blob/a67e7eaefae89ed761fa4dcbc5431ec9a235a6c8/sql-99.bnf#L412

Types

type ApplyConfig

type ApplyConfig struct {
	VerifyHistory bool
}

ApplyConfig provides configurable fields for "up" commands that will apply migrations.

func NewApplyConfig

func NewApplyConfig(opts ...ApplyOption) (*ApplyConfig, error)

NewApplyConfig creates a new `ApplyConfig` and applies options.

type ApplyOption

type ApplyOption = func(*ApplyConfig) error

ApplyOption describes options used to create an apply configuration.

func OptApplyVerifyHistory

func OptApplyVerifyHistory(verify bool) ApplyOption

OptApplyVerifyHistory sets `VerifyHistory` on an `ApplyConfig`.

type CreateTableParameters

type CreateTableParameters struct {
	SerialID  string
	Revision  string
	Previous  string
	CreatedAt string
}

CreateTableParameters specifies a set of parameters that are intended to be used in a `CREATE TABLE` statement.

type Manager

type Manager struct {
	// MetadataTable is the name of the table that stores migration metadata.
	// The expected default value (`DefaultMetadataTable`) is
	// "golembic_migrations".
	MetadataTable string
	// Sequence is the collection of registered migrations to be applied,
	// verified, described, etc. by this manager.
	Sequence *Migrations
	// VerifyHistory indicates that the rows **stored** in the migration metadata
	// table should be verified during planning.
	VerifyHistory bool
	// DevelopmentMode is a flag indicating that this manager is currently
	// being run in development mode, so things like extra validation should
	// intentionally be disabled. This is intended for use in testing and
	// development, where an entire database is spun up locally (e.g. in Docker)
	// and migrations will be applied from scratch (including milestones that
	// may not come at the end).
	DevelopmentMode bool
	// Log is used for printing output
	Log logger.Log
}

Manager orchestrates database operations done via `Up` / `UpConn` as well as supporting operations such as writing rows into a migration metadata table during a migration.

func NewManager

func NewManager(opts ...ManagerOption) (*Manager, error)

NewManager creates a new manager for orchestrating migrations.

func (*Manager) ApplyMigration

func (m *Manager) ApplyMigration(ctx context.Context, pool *db.Connection, tx *sql.Tx, migration Migration) (err error)

ApplyMigration creates a transaction that runs the "Up" migration.

func (*Manager) InsertMigration

func (m *Manager) InsertMigration(ctx context.Context, pool *db.Connection, tx *sql.Tx, migration Migration) error

InsertMigration inserts a migration into the migrations metadata table.

func (*Manager) Latest

func (m *Manager) Latest(ctx context.Context, pool *db.Connection, tx *sql.Tx) (revision string, createdAt time.Time, err error)

Latest determines the revision and timestamp of the most recently applied migration.

NOTE: This assumes, but does not check, that the migrations metadata table exists.

func (*Manager) Plan

func (m *Manager) Plan(ctx context.Context, pool *db.Connection, tx *sql.Tx, opts ...ApplyOption) ([]Migration, error)

Plan gathers (and verifies) all migrations that have not yet been applied.

type ManagerOption

type ManagerOption = func(*Manager) error

ManagerOption describes options used to create a new manager.

func OptDevelopmentMode

func OptDevelopmentMode(mode bool) ManagerOption

OptDevelopmentMode sets the development mode flag on a manager.

func OptManagerLog

func OptManagerLog(log logger.Log) ManagerOption

OptManagerLog sets the logger interface on a manager. If `log` is `nil`code man the option will return an error.

func OptManagerMetadataTable

func OptManagerMetadataTable(table string) ManagerOption

OptManagerMetadataTable sets the metadata table name on a manager.

func OptManagerSequence

func OptManagerSequence(migrations *Migrations) ManagerOption

OptManagerSequence sets the migrations sequence on a manager.

func OptManagerVerifyHistory

func OptManagerVerifyHistory(verify bool) ManagerOption

OptManagerVerifyHistory sets `VerifyHistory` on a manager.

type Migration

type Migration struct {
	// Previous is the revision identifier for the migration immediately
	// preceding this one. If absent, this indicates that this migration is
	// the "base" or "root" migration.
	Previous string
	// Revision is an opaque name that uniquely identifies a migration. It
	// is required for a migration to be valid.
	Revision string
	// Description is a long form description of why the migration is being
	// performed. It is intended to be used in "describe" scenarios where
	// a long form "history" of changes is presented.
	Description string
	// Milestone is a flag indicating if the current migration is a milestone.
	// A milestone is a special migration that **must** be the last migration
	// in a sequence whenever applied. This is intended to be used in situations
	// where a change must be "staged" in two (or more parts) and one part
	// must run and "stabilize" before the next migration runs. For example, in
	// a rolling update deploy strategy some changes may not be compatible with
	// "old" and "new" versions of the code that may run simultaneously, so a
	// milestone marks the last point where old / new versions of application
	// code should be expected to be able to interact with the current schema.
	Milestone bool
	// Up is the function to be executed when a migration is being applied. Either
	// this field or `UpConn` are required (not both) and this field should be
	// the default choice in most cases. This function will be run in a transaction
	// that also writes a row to the migrations metadata table to signify that
	// this migration was applied.
	Up UpMigration
	// UpConn is the non-transactional form of `Up`. This should be used in
	// rare situations where a migration cannot run inside a transaction, e.g.
	// a `CREATE UNIQUE INDEX CONCURRENTLY` statement.
	UpConn UpMigrationConn
	// contains filtered or unexported fields
}

Migration represents an individual migration to be applied; typically as a set of SQL statements.

func NewMigration

func NewMigration(opts ...MigrationOption) (*Migration, error)

NewMigration creates a new migration from a variadic slice of options.

func (Migration) Compact

func (m Migration) Compact() string

Compact gives a "limited" representation of the migration

func (Migration) ExtendedDescription

func (m Migration) ExtendedDescription() string

ExtendedDescription is an extended form of `m.Description` that also incorporates other information like whether `m` is a milestone.

func (Migration) InvokeUp

func (m Migration) InvokeUp(ctx context.Context, pool *db.Connection, tx *sql.Tx) error

InvokeUp dispatches to `Up` or `UpConn`, depending on which is set. If both or neither is set, that is considered an error. If `UpConn` needs to be invoked, this lazily creates a new connection from a pool. It's crucial that the pool sets the relevant timeouts when creating a new connection to make sure migrations don't cause disruptions in application performance due to accidentally holding locks for an extended period.

func (Migration) Like

func (m Migration) Like(other Migration) bool

Like is "almost" an equality check, it compares the `Previous` and `Revision`.

type MigrationOption

type MigrationOption = func(*Migration) error

MigrationOption describes options used to create a new migration.

func OptAlwaysError

func OptAlwaysError(err error) MigrationOption

OptAlwaysError returns an option that always returns an error.

func OptDescription

func OptDescription(description string) MigrationOption

OptDescription sets the description on a migration.

func OptMilestone

func OptMilestone(milestone bool) MigrationOption

OptMilestone sets the milestone flag on a migration.

func OptPrevious

func OptPrevious(previous string) MigrationOption

OptPrevious sets the previous on a migration.

func OptRevision

func OptRevision(revision string) MigrationOption

OptRevision sets the revision on a migration.

func OptUp

func OptUp(up UpMigration) MigrationOption

OptUp sets the `up` function on a migration.

func OptUpConn

func OptUpConn(up UpMigrationConn) MigrationOption

OptUpConn sets the non-transactional `up` function on a migration.

func OptUpConnFromFile

func OptUpConnFromFile(filename string) MigrationOption

OptUpConnFromFile returns an option that sets the non-transctional `up` function to execute a SQL statement that is stored in a file.

func OptUpConnFromSQL

func OptUpConnFromSQL(statement string) MigrationOption

OptUpConnFromSQL returns an option that sets the non-transctional `up` function to execute a SQL statement.

func OptUpFromFile

func OptUpFromFile(filename string) MigrationOption

OptUpFromFile returns an option that sets the `up` function to execute a SQL statement that is stored in a file.

func OptUpFromSQL

func OptUpFromSQL(statement string) MigrationOption

OptUpFromSQL returns an option that sets the `up` function to execute a SQL statement.

type Migrations

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

Migrations represents a sequence of migrations to be applied.

func NewSequence

func NewSequence(root Migration) (*Migrations, error)

NewSequence creates a new sequence of migrations rooted in a single base / root migration.

func (*Migrations) All

func (m *Migrations) All() []Migration

All produces the migrations in the sequence, in order.

NOTE: This does not verify or enforce the invariant that there must be

exactly one migration without a previous migration. This invariant is
enforced by the exported methods such as `Register()` and
`RegisterMany()` and the constructor `NewSequence()`.

func (*Migrations) Get

func (m *Migrations) Get(revision string) *Migration

Get retrieves a revision from the sequence, if present. If not, returns `nil`.

func (*Migrations) Register

func (m *Migrations) Register(migration Migration) error

Register adds a new migration to an existing sequence of migrations, if possible. The new migration must have a previous migration and have a valid revision that is not already registered.

func (*Migrations) RegisterMany

func (m *Migrations) RegisterMany(ms ...Migration) error

RegisterMany attempts to register multiple migrations (in order) with an existing sequence.

func (*Migrations) RegisterManyOpt

func (m *Migrations) RegisterManyOpt(manyOpts ...[]MigrationOption) error

RegisterManyOpt attempts to register multiple migrations (in order) with an existing sequence. It differs from `RegisterMany()` in that the construction of `Migration` objects is handled directly here by taking a slice of option slices.

func (*Migrations) Revisions

func (m *Migrations) Revisions() []string

Revisions produces the revisions in the sequence, in order.

This utilizes `All()` and just extracts the revisions.

func (*Migrations) Root

func (m *Migrations) Root() Migration

Root does a linear scan of every migration in the sequence and returns the root migration. In the "general" case such a scan would be expensive, but the number of migrations should always be a small number.

NOTE: This does not verify or enforce the invariant that there must be exactly one migration without a previous migration. This invariant is enforced by the exported methods such as `Register()` and `RegisterMany()` and the constructor `NewSequence()`.

func (*Migrations) Since

func (m *Migrations) Since(revision string) (int, []Migration, error)

Since returns the migrations that occur **after** `revision`.

This utilizes `All()` and returns all migrations after the one that matches `revision`. If none match, an error will be returned. If `revision` is the **last** migration, the migrations returned will be an empty slice.

type PlanEvent

type PlanEvent struct {
	Revision string
	Body     string
	Status   PlanStatus
	Labels   []string
}

func (PlanEvent) Color

func (pe PlanEvent) Color() ansi.Color

func (PlanEvent) Decompose

func (pe PlanEvent) Decompose() map[string]interface{}

Decompose implements logger.JSONWritable.

func (PlanEvent) GetFlag

func (PlanEvent) GetFlag() string

func (PlanEvent) Result

func (pe PlanEvent) Result() string

func (PlanEvent) WriteText

func (pe PlanEvent) WriteText(tf logger.TextFormatter, wr io.Writer)

WriteText writes the migration event as text.

type PlanStatus

type PlanStatus string
const (
	PlanStatusUnset   PlanStatus = ""
	PlanStatusFailed  PlanStatus = migration.StatFailed
	PlanStatusApplied PlanStatus = migration.StatApplied
)

type UpMigration

type UpMigration = func(context.Context, *db.Connection, *sql.Tx) error

UpMigration defines a function interface to be used for up / forward migrations. The SQL transaction will be started **before** `UpMigration` is invoked and will be committed **after** the `UpMigration` exits without error. In addition to the contents of `UpMigration`, a row will be written to the migrations metadata table as part of the transaction.

The expectation is that the migration runs SQL statements within the transaction. If a migration cannot run inside a transaction, e.g. a `CREATE UNIQUE INDEX CONCURRENTLY` statement, then the `UpMigration` interface should be used.

type UpMigrationConn

type UpMigrationConn = func(context.Context, *db.Connection) error

UpMigrationConn defines a function interface to be used for up / forward migrations. This is the non-transactional form of `UpMigration` and should only be used in rare situations.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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