From 6b68933c7228dd04d2e0336586c5e1378d10db0f Mon Sep 17 00:00:00 2001 From: Patrik Date: Thu, 17 Feb 2022 10:24:08 +0100 Subject: [PATCH] feat(popx): allow running custom go migrations (#468) --- popx/migration_box.go | 21 ++++-- popx/migration_box_gomigration_test.go | 92 ++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 popx/migration_box_gomigration_test.go diff --git a/popx/migration_box.go b/popx/migration_box.go index 9d34819e..19023336 100644 --- a/popx/migration_box.go +++ b/popx/migration_box.go @@ -20,8 +20,10 @@ type ( Dir fs.FS l *logrusx.Logger migrationContent MigrationContent + goMigrations Migrations } MigrationContent func(mf Migration, c *pop.Connection, r []byte, usingTemplate bool) (string, error) + GoMigration func(c *pop.Tx) error ) func WithTemplateValues(v map[string]interface{}) func(*MigrationBox) *MigrationBox { @@ -41,10 +43,17 @@ func WithMigrationContentMiddleware(middleware func(content string, err error) ( } } -// NewMigrationBox from a packr.Dir and a Connection. -// -// migrations, err := NewMigrationBox(pkger.Dir("/migrations")) -// +// WithGoMigrations adds migrations that have a custom migration runner. +// TEST THEM THOROUGHLY! +// It will be very hard to fix a buggy migration. +func WithGoMigrations(migrations Migrations) func(*MigrationBox) *MigrationBox { + return func(m *MigrationBox) *MigrationBox { + m.goMigrations = migrations + return m + } +} + +// NewMigrationBox creates a new migration box. func NewMigrationBox(dir fs.FS, m *Migrator, opts ...func(*MigrationBox) *MigrationBox) (*MigrationBox, error) { mb := &MigrationBox{ Migrator: m, @@ -79,6 +88,10 @@ func NewMigrationBox(dir fs.FS, m *Migrator, opts ...func(*MigrationBox) *Migrat return mb, err } + for _, migration := range mb.goMigrations { + mb.Migrations[migration.Direction] = append(mb.Migrations[migration.Direction], migration) + } + return mb, nil } diff --git a/popx/migration_box_gomigration_test.go b/popx/migration_box_gomigration_test.go new file mode 100644 index 00000000..dfff0902 --- /dev/null +++ b/popx/migration_box_gomigration_test.go @@ -0,0 +1,92 @@ +package popx_test + +import ( + "context" + "testing" + "time" + + "github.com/gobuffalo/pop/v6" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/ory/x/logrusx" + "github.com/ory/x/popx" +) + +func TestGoMigrations(t *testing.T) { + var called []time.Time + + goMigrations := popx.Migrations{ + { + Path: "gomigration_0", + Version: "20000101000000", + Name: "gomigration_0", + Direction: "up", + Type: "go", + DBType: "all", + Runner: func(migration popx.Migration, _ *pop.Connection, tx *pop.Tx) error { + called[0] = time.Now() + return nil + }, + }, + { + Path: "gomigration_0", + Version: "20000101000000", + Name: "gomigration_0", + Direction: "down", + Type: "go", + DBType: "all", + Runner: func(migration popx.Migration, _ *pop.Connection, tx *pop.Tx) error { + called[1] = time.Now() + return nil + }, + }, + { + Path: "gomigration_1", + Version: "20220215110652", + Name: "gomigration_1", + Direction: "up", + Type: "go", + DBType: "all", + Runner: func(migration popx.Migration, _ *pop.Connection, tx *pop.Tx) error { + called[2] = time.Now() + return nil + }, + }, + { + Path: "gomigration_1", + Version: "20220215110652", + Name: "gomigration_1", + Direction: "down", + Type: "go", + DBType: "all", + Runner: func(migration popx.Migration, _ *pop.Connection, tx *pop.Tx) error { + called[3] = time.Now() + return nil + }, + }, + } + + called = make([]time.Time, len(goMigrations)) + + c, err := pop.NewConnection(&pop.ConnectionDetails{ + URL: "sqlite://file::memory:?_fk=true", + }) + require.NoError(t, err) + require.NoError(t, c.Open()) + + mb, err := popx.NewMigrationBox(transactionalMigrations, popx.NewMigrator(c, logrusx.New("", ""), nil, 0), popx.WithGoMigrations(goMigrations)) + require.NoError(t, err) + require.NoError(t, mb.Up(context.Background())) + + assert.Zero(t, called[1]) + assert.Zero(t, called[3]) + assert.NotZero(t, called[0]) + assert.NotZero(t, called[2]) + assert.True(t, called[0].Before(called[2])) + + require.NoError(t, mb.Down(context.Background(), -1)) + assert.NotZero(t, called[1]) + assert.NotZero(t, called[3]) + assert.True(t, called[3].Before(called[1])) +}