@@ -55,12 +55,71 @@ func (e ErrDirty) Error() string {
55
55
return fmt .Sprintf ("Dirty database version %v. Fix and force version." , e .Version )
56
56
}
57
57
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
+
58
113
type Migrate struct {
59
114
sourceName string
60
115
sourceDrv source.Driver
61
116
databaseName string
62
117
databaseDrv database.Driver
63
118
119
+ // opts is a set of options that can be used to modify the behavior
120
+ // of the Migrate instance.
121
+ opts options
122
+
64
123
// Log accepts a Logger interface
65
124
Log Logger
66
125
@@ -84,8 +143,8 @@ type Migrate struct {
84
143
85
144
// New returns a new Migrate instance from a source URL and a database URL.
86
145
// 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 )
89
148
90
149
sourceName , err := iurl .SchemeFromURL (sourceURL )
91
150
if err != nil {
@@ -118,8 +177,10 @@ func New(sourceURL, databaseURL string) (*Migrate, error) {
118
177
// and an existing database instance. The source URL scheme is defined by each driver.
119
178
// Use any string that can serve as an identifier during logging as databaseName.
120
179
// 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 )
123
184
124
185
sourceName , err := iurl .SchemeFromURL (sourceURL )
125
186
if err != nil {
@@ -144,8 +205,10 @@ func NewWithDatabaseInstance(sourceURL string, databaseName string, databaseInst
144
205
// and a database URL. The database URL scheme is defined by each driver.
145
206
// Use any string that can serve as an identifier during logging as sourceName.
146
207
// 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 )
149
212
150
213
databaseName , err := iurl .SchemeFromURL (databaseURL )
151
214
if err != nil {
@@ -170,8 +233,11 @@ func NewWithSourceInstance(sourceName string, sourceInstance source.Driver, data
170
233
// database instance. Use any string that can serve as an identifier during logging
171
234
// as sourceName and databaseName. You are responsible for closing down
172
235
// 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 )
175
241
176
242
m .sourceName = sourceName
177
243
m .databaseName = databaseName
@@ -182,8 +248,13 @@ func NewWithInstance(sourceName string, sourceInstance source.Driver, databaseNa
182
248
return m , nil
183
249
}
184
250
185
- func newCommon () * Migrate {
251
+ func newMigrateWithOptions (optFunctions []Option ) * Migrate {
252
+ opts := defaultOptions ()
253
+ for _ , opt := range optFunctions {
254
+ opt (& opts )
255
+ }
186
256
return & Migrate {
257
+ opts : opts ,
187
258
GracefulStop : make (chan bool , 1 ),
188
259
PrefetchMigrations : DefaultPrefetchMigrations ,
189
260
LockTimeout : DefaultLockTimeout ,
@@ -746,6 +817,25 @@ func (m *Migrate) runMigrations(ret <-chan interface{}) error {
746
817
if err := m .databaseDrv .Run (migr .BufferedBody ); err != nil {
747
818
return err
748
819
}
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
+ }
749
839
}
750
840
751
841
// set clean state
0 commit comments