@@ -24,6 +24,11 @@ type Config struct {
24
24
// Set mode explicitly to show how migration should be done.
25
25
Mode MigratorMode
26
26
27
+ // DisableTx will run every migration not in a transaction.
28
+ // This completely depends on a specific Migrator implementation
29
+ // because not every database supports transaction, so this option can be no-op all the time.
30
+ DisableTx bool
31
+
27
32
// UseForce to get a lock on a database. MUST be used with the caution.
28
33
// Should be used when previous migration run didn't unlock the database,
29
34
// and this blocks subsequent runs.
@@ -44,6 +49,10 @@ type Migrator interface {
44
49
Version (ctx context.Context ) (version int , err error )
45
50
SetVersion (ctx context.Context , version int ) error
46
51
52
+ Begin (ctx context.Context ) error
53
+ Commit (ctx context.Context ) error
54
+ Rollback (ctx context.Context ) error
55
+
47
56
Exec (ctx context.Context , query string , args ... interface {}) error
48
57
}
49
58
@@ -176,18 +185,46 @@ func (m *mig) runMigrationLocked(ctx context.Context, ms []*Migration) error {
176
185
}
177
186
178
187
for _ , step := range m .prepareSteps (curr , target , ms ) {
179
- if step .IsQuery {
180
- err = m .Exec (ctx , step .Query )
181
- } else {
182
- err = step .QueryFn (ctx , m )
183
- }
184
- if err != nil {
188
+ if err := m .execStep (ctx , step ); err != nil {
185
189
return fmt .Errorf ("exec: %w" , err )
186
190
}
191
+ }
192
+ return nil
193
+ }
187
194
188
- if err := m .SetVersion (ctx , step .Version ); err != nil {
189
- return fmt .Errorf ("set version: %w" , err )
195
+ func (m * mig ) execStep (ctx context.Context , step step ) error {
196
+ if m .Config .DisableTx {
197
+ return m .execSimpleStep (ctx , step )
198
+ }
199
+ return m .execStepSafely (ctx , step )
200
+ }
201
+
202
+ func (m * mig ) execStepSafely (ctx context.Context , step step ) (err error ) {
203
+ if err := m .Migrator .Begin (ctx ); err != nil {
204
+ return fmt .Errorf ("begin tx: %w" , err )
205
+ }
206
+
207
+ defer func () {
208
+ if err != nil {
209
+ if errRollback := m .Migrator .Rollback (ctx ); errRollback != nil {
210
+ err = fmt .Errorf ("rollback tx: %w" , errRollback )
211
+ }
190
212
}
213
+ }()
214
+
215
+ err = m .execSimpleStep (ctx , step )
216
+ if err == nil {
217
+ err = m .Commit (ctx )
218
+ }
219
+ return err
220
+ }
221
+
222
+ func (m * mig ) execSimpleStep (ctx context.Context , step step ) error {
223
+ if err := m .Exec (ctx , step .Query ); err != nil {
224
+ return fmt .Errorf ("exec: %w" , err )
225
+ }
226
+ if err := m .SetVersion (ctx , step .Version ); err != nil {
227
+ return fmt .Errorf ("set version: %w" , err )
191
228
}
192
229
return nil
193
230
}
@@ -261,7 +298,6 @@ type step struct {
261
298
Version int
262
299
IsQuery bool
263
300
Query string
264
- QueryFn MigrationFn
265
301
}
266
302
267
303
func (m * Migration ) toStep (up bool ) step {
@@ -283,15 +319,9 @@ type locklessMigrator struct {
283
319
m Migrator
284
320
}
285
321
286
- func (llm * locklessMigrator ) Init (ctx context.Context ) error {
287
- return llm .m .Init (ctx )
288
- }
289
- func (llm * locklessMigrator ) LockDB (ctx context.Context ) error {
290
- return nil
291
- }
292
- func (llm * locklessMigrator ) UnlockDB (ctx context.Context ) error {
293
- return nil
294
- }
322
+ func (llm * locklessMigrator ) Init (ctx context.Context ) error { return llm .m .Init (ctx ) }
323
+ func (llm * locklessMigrator ) LockDB (ctx context.Context ) error { return nil }
324
+ func (llm * locklessMigrator ) UnlockDB (ctx context.Context ) error { return nil }
295
325
296
326
func (llm * locklessMigrator ) Version (ctx context.Context ) (version int , err error ) {
297
327
return llm .m .Version (ctx )
@@ -300,6 +330,10 @@ func (llm *locklessMigrator) SetVersion(ctx context.Context, version int) error
300
330
return llm .m .SetVersion (ctx , version )
301
331
}
302
332
333
+ func (llm * locklessMigrator ) Begin (ctx context.Context ) error { return llm .Begin (ctx ) }
334
+ func (llm * locklessMigrator ) Commit (ctx context.Context ) error { return llm .Commit (ctx ) }
335
+ func (llm * locklessMigrator ) Rollback (ctx context.Context ) error { return llm .Rollback (ctx ) }
336
+
303
337
func (llm * locklessMigrator ) Exec (ctx context.Context , query string , args ... interface {}) error {
304
338
return llm .m .Exec (ctx , query , args ... )
305
339
}
0 commit comments