@@ -55,12 +55,71 @@ func (e ErrDirty) Error() string {
5555 return fmt .Sprintf ("Dirty database version %v. Fix and force version." , e .Version )
5656}
5757
58+ // PostStepCallback is a callback function type that can be used to execute a
59+ // Golang based migration step after a SQL based migration step has been
60+ // executed. The callback function receives the migration and the database
61+ // driver as arguments.
62+ type PostStepCallback func (migr * Migration , driver database.Driver ) error
63+
64+ // options is a set of optional options that can be set when a Migrate instance
65+ // is created.
66+ type options struct {
67+ // postStepCallbacks is a map of PostStepCallback functions that can be
68+ // used to execute a Golang based migration step after a SQL based
69+ // migration step has been executed. The key is the migration version
70+ // and the value is the callback function that should be run _after_ the
71+ // step was executed (but within the same database transaction).
72+ postStepCallbacks map [uint ]PostStepCallback
73+ }
74+
75+ // defaultOptions returns a new options struct with default values.
76+ func defaultOptions () options {
77+ return options {
78+ postStepCallbacks : make (map [uint ]PostStepCallback ),
79+ }
80+ }
81+
82+ // Option is a function that can be used to set options on a Migrate instance.
83+ type Option func (* options )
84+
85+ // WithPostStepCallbacks is an option that can be used to set a map of
86+ // PostStepCallback functions that can be used to execute a Golang based
87+ // migration step after a SQL based migration step has been executed. The key is
88+ // the migration version and the value is the callback function that should be
89+ // run _after_ the step was executed (but before the version is marked as
90+ // cleanly executed). An error returned from the callback will cause the
91+ // migration to fail and the step to be marked as dirty.
92+ func WithPostStepCallbacks (
93+ postStepCallbacks map [uint ]PostStepCallback ) Option {
94+
95+ return func (o * options ) {
96+ o .postStepCallbacks = postStepCallbacks
97+ }
98+ }
99+
100+ // WithPostStepCallback is an option that can be used to set a PostStepCallback
101+ // function that can be used to execute a Golang based migration step after the
102+ // SQL based migration step with the given version number has been executed. The
103+ // callback is the function that should be run _after_ the step was executed
104+ // (but before the version is marked as cleanly executed). An error returned
105+ // from the callback will cause the migration to fail and the step to be marked
106+ // as dirty.
107+ func WithPostStepCallback (version uint , callback PostStepCallback ) Option {
108+ return func (o * options ) {
109+ o .postStepCallbacks [version ] = callback
110+ }
111+ }
112+
58113type Migrate struct {
59114 sourceName string
60115 sourceDrv source.Driver
61116 databaseName string
62117 databaseDrv database.Driver
63118
119+ // opts is a set of options that can be used to modify the behavior
120+ // of the Migrate instance.
121+ opts options
122+
64123 // Log accepts a Logger interface
65124 Log Logger
66125
@@ -84,8 +143,8 @@ type Migrate struct {
84143
85144// New returns a new Migrate instance from a source URL and a database URL.
86145// The URL scheme is defined by each driver.
87- func New (sourceURL , databaseURL string ) (* Migrate , error ) {
88- m := newCommon ( )
146+ func New (sourceURL , databaseURL string , opts ... Option ) (* Migrate , error ) {
147+ m := newMigrateWithOptions ( opts )
89148
90149 sourceName , err := iurl .SchemeFromURL (sourceURL )
91150 if err != nil {
@@ -118,8 +177,10 @@ func New(sourceURL, databaseURL string) (*Migrate, error) {
118177// and an existing database instance. The source URL scheme is defined by each driver.
119178// Use any string that can serve as an identifier during logging as databaseName.
120179// You are responsible for closing the underlying database client if necessary.
121- func NewWithDatabaseInstance (sourceURL string , databaseName string , databaseInstance database.Driver ) (* Migrate , error ) {
122- m := newCommon ()
180+ func NewWithDatabaseInstance (sourceURL string , databaseName string ,
181+ databaseInstance database.Driver , opts ... Option ) (* Migrate , error ) {
182+
183+ m := newMigrateWithOptions (opts )
123184
124185 sourceName , err := iurl .SchemeFromURL (sourceURL )
125186 if err != nil {
@@ -144,8 +205,10 @@ func NewWithDatabaseInstance(sourceURL string, databaseName string, databaseInst
144205// and a database URL. The database URL scheme is defined by each driver.
145206// Use any string that can serve as an identifier during logging as sourceName.
146207// You are responsible for closing the underlying source client if necessary.
147- func NewWithSourceInstance (sourceName string , sourceInstance source.Driver , databaseURL string ) (* Migrate , error ) {
148- m := newCommon ()
208+ func NewWithSourceInstance (sourceName string , sourceInstance source.Driver ,
209+ databaseURL string , opts ... Option ) (* Migrate , error ) {
210+
211+ m := newMigrateWithOptions (opts )
149212
150213 databaseName , err := iurl .SchemeFromURL (databaseURL )
151214 if err != nil {
@@ -170,8 +233,11 @@ func NewWithSourceInstance(sourceName string, sourceInstance source.Driver, data
170233// database instance. Use any string that can serve as an identifier during logging
171234// as sourceName and databaseName. You are responsible for closing down
172235// the underlying source and database client if necessary.
173- func NewWithInstance (sourceName string , sourceInstance source.Driver , databaseName string , databaseInstance database.Driver ) (* Migrate , error ) {
174- m := newCommon ()
236+ func NewWithInstance (sourceName string , sourceInstance source.Driver ,
237+ databaseName string , databaseInstance database.Driver ,
238+ opts ... Option ) (* Migrate , error ) {
239+
240+ m := newMigrateWithOptions (opts )
175241
176242 m .sourceName = sourceName
177243 m .databaseName = databaseName
@@ -182,8 +248,13 @@ func NewWithInstance(sourceName string, sourceInstance source.Driver, databaseNa
182248 return m , nil
183249}
184250
185- func newCommon () * Migrate {
251+ func newMigrateWithOptions (optFunctions []Option ) * Migrate {
252+ opts := defaultOptions ()
253+ for _ , opt := range optFunctions {
254+ opt (& opts )
255+ }
186256 return & Migrate {
257+ opts : opts ,
187258 GracefulStop : make (chan bool , 1 ),
188259 PrefetchMigrations : DefaultPrefetchMigrations ,
189260 LockTimeout : DefaultLockTimeout ,
@@ -746,6 +817,25 @@ func (m *Migrate) runMigrations(ret <-chan interface{}) error {
746817 if err := m .databaseDrv .Run (migr .BufferedBody ); err != nil {
747818 return err
748819 }
820+
821+ // If there is a post execution function for
822+ // this migration, run it now.
823+ cb , ok := m .opts .postStepCallbacks [migr .Version ]
824+ if ok {
825+ m .logVerbosePrintf ("Running post step " +
826+ "callback for %v\n " , migr .LogString ())
827+
828+ err := cb (migr , m .databaseDrv )
829+ if err != nil {
830+ return fmt .Errorf ("failed to " +
831+ "execute post " +
832+ "step callback: %w" ,
833+ err )
834+ }
835+
836+ m .logVerbosePrintf ("Post step callback " +
837+ "finished for %v\n " , migr .LogString ())
838+ }
749839 }
750840
751841 // set clean state
0 commit comments