From b6bd4fe02d2a5580a0153706d66329dbcba23ea5 Mon Sep 17 00:00:00 2001 From: Matthias Kadenbach Date: Thu, 9 Feb 2017 19:42:48 -0800 Subject: [PATCH] add comments for source --- database/testing/testing.go | 4 ++++ source/driver.go | 34 ++++++++++++++++++++++++++++++++++ source/driver_test.go | 8 ++++++++ source/migration.go | 21 ++++++++++++++++++--- source/migration_test.go | 33 +++++++++++++++++++++++++++++++++ source/parse.go | 17 +++++++++++------ source/testing/testing.go | 12 ++++++++---- 7 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 source/driver_test.go create mode 100644 source/migration_test.go diff --git a/database/testing/testing.go b/database/testing/testing.go index 66740c7..0e087c6 100644 --- a/database/testing/testing.go +++ b/database/testing/testing.go @@ -1,3 +1,6 @@ +// Package testing has the database tests. +// All database drivers must pass the Test function. +// This lives in it's own package so it stays a test dependency. package testing import ( @@ -8,6 +11,7 @@ import ( "github.com/mattes/migrate/database" ) +// Test runs tests against database implementations. func Test(t *testing.T, d database.Driver, migration []byte) { if migration == nil { panic("test must provide migration reader") diff --git a/source/driver.go b/source/driver.go index 5143644..3d7abb1 100644 --- a/source/driver.go +++ b/source/driver.go @@ -1,3 +1,7 @@ +// Package source provides the Source interface. +// All source drivers must implement this interface, register themselves, +// optionally provide a `WithInstance` function and pass the tests +// in package source/testing. package source import ( @@ -10,22 +14,51 @@ import ( var driversMu sync.RWMutex var drivers = make(map[string]Driver) +// Driver is an interface every driver must implement. +// The driver implementation must pass the `Test` in source/testing. +// Optionally provide a `WithInstance` function, so users can bypass `Open` +// and use an existing source instance. type Driver interface { + // Open returns a a new driver instance configured with parameters + // coming from the URL string. Migrate will call this function + // only once per instance. Open(url string) (Driver, error) + // Close closes the underlying source instance managed by the driver. + // Migrate will call this function only once per instance. Close() error + // First returns the very first migration version available to the driver. + // Migrate will call this function multiple times. + // If there is no version available, it must return os.ErrNotExist. First() (version uint, err error) + // Prev returns the previous version for a given version available to the driver. + // Migrate will call this function multiple times. + // If there is no previous version available, it must return os.ErrNotExist. Prev(version uint) (prevVersion uint, err error) + // Next returns the next version for a given version available to the driver. + // Migrate will call this function multiple times. + // If there is no next version available, it must return os.ErrNotExist. Next(version uint) (nextVersion uint, err error) + // ReadUp returns the UP migration body and an identifier that helps + // finding this migration in the source for a given version. + // If there is no up migration available for this version, + // it must return os.ErrNotExist. + // Do not start reading, just return the ReadCloser! ReadUp(version uint) (r io.ReadCloser, identifier string, err error) + // ReadDown returns the DOWN migration body and an identifier that helps + // finding this migration in the source for a given version. + // If there is no down migration available for this version, + // it must return os.ErrNotExist. + // Do not start reading, just return the ReadCloser! ReadDown(version uint) (r io.ReadCloser, identifier string, err error) } +// Open returns a new driver instance. func Open(url string) (Driver, error) { u, err := nurl.Parse(url) if err != nil { @@ -46,6 +79,7 @@ func Open(url string) (Driver, error) { return d.Open(url) } +// Register globally registers a driver. func Register(name string, driver Driver) { driversMu.Lock() defer driversMu.Unlock() diff --git a/source/driver_test.go b/source/driver_test.go new file mode 100644 index 0000000..82284a0 --- /dev/null +++ b/source/driver_test.go @@ -0,0 +1,8 @@ +package source + +func ExampleDriver() { + // see source/stub for an example + + // source/stub/stub.go has the driver implementation + // source/stub/stub_test.go runs source/testing/test.go:Test +} diff --git a/source/migration.go b/source/migration.go index 4c9e7d6..5d10b93 100644 --- a/source/migration.go +++ b/source/migration.go @@ -4,6 +4,7 @@ import ( "sort" ) +// Direction is either up or down. type Direction string const ( @@ -11,13 +12,27 @@ const ( Up = "up" ) +// Migration is a helper struct for source drivers that need to +// build the full directory tree in memory. +// Migration is fully independent from migrate.Migration. type Migration struct { - Version uint + // Version is the version of this migration. + Version uint + + // Identifier can be any string that helps identifying + // this migration in the source. Identifier string - Direction Direction - Raw string + + // Direction is either Up or Down. + Direction Direction + + // Raw holds the raw location path to this migration in source. + // ReadUp and ReadDown will use this. + Raw string } +// Migrations wraps Migration and has an internal index +// to keep track of Migration order. type Migrations struct { index uintSlice migrations map[uint]map[Direction]*Migration diff --git a/source/migration_test.go b/source/migration_test.go new file mode 100644 index 0000000..2cbcaa8 --- /dev/null +++ b/source/migration_test.go @@ -0,0 +1,33 @@ +package source + +import ( + "testing" +) + +func TestNewMigrations(t *testing.T) { + // TODO +} + +func TestAppend(t *testing.T) { + // TODO +} + +func TestBuildIndex(t *testing.T) { + // TODO +} + +func TestFirst(t *testing.T) { + // TODO +} + +func TestPrev(t *testing.T) { + // TODO +} + +func TestUp(t *testing.T) { + // TODO +} + +func TestDown(t *testing.T) { + // TODO +} diff --git a/source/parse.go b/source/parse.go index e4f4d03..ed26295 100644 --- a/source/parse.go +++ b/source/parse.go @@ -6,16 +6,21 @@ import ( "strconv" ) -var ErrParse = fmt.Errorf("no match") +var ( + ErrParse = fmt.Errorf("no match") +) -var DefaultParse = Parse +var ( + DefaultParse = Parse + DefaultRegex = Regex +) -var DefaultRegex = Regex - -// filename example: `123_name.up.ext` -// filename example: `123_name.down.ext` +// Regex matches the following pattern: +// 123_name.up.ext +// 123_name.down.ext var Regex = regexp.MustCompile(`^([0-9]+)_(.*)\.(` + string(Down) + `|` + string(Up) + `)\.(.*)$`) +// Parse returns Migration for matching Regex pattern. func Parse(raw string) (*Migration, error) { m := Regex.FindStringSubmatch(raw) if len(m) == 5 { diff --git a/source/testing/testing.go b/source/testing/testing.go index baf5838..3cc003c 100644 --- a/source/testing/testing.go +++ b/source/testing/testing.go @@ -1,3 +1,6 @@ +// Package testing has the source tests. +// All source drivers must pass the Test function. +// This lives in it's own package so it stays a test dependency. package testing import ( @@ -7,13 +10,14 @@ import ( "github.com/mattes/migrate/source" ) -// Test tests a driver implementation -// It assumes the following migration "files" -// -// u = up file, d = down file, n = version +// Test runs tests against source implementations. +// It assumes that the driver tests has access to the following migrations: // +// u = up migration, d = down migration, n = version // | 1 | - | 3 | 4 | 5 | - | 7 | // | u d | - | u | u d | d | - | u d | +// +// See source/stub/stub_test.go or source/file/file_test.go for an example. func Test(t *testing.T, d source.Driver) { TestFirst(t, d) TestPrev(t, d)