Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 03a4023

Browse files
committedJun 30, 2022
Introduce DoStep
1 parent 176e818 commit 03a4023

File tree

3 files changed

+78
-271
lines changed

3 files changed

+78
-271
lines changed
 

‎dbump.go

Lines changed: 30 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -51,28 +51,24 @@ type Migrator interface {
5151
LockDB(ctx context.Context) error
5252
// UnlockDB to allow running other migrators later.
5353
UnlockDB(ctx context.Context) error
54+
5455
// Init the dbump database where database state is saved.
5556
// What is created by this method completely depends on migrator implementation
5657
// and might be different between databases.
5758
Init(ctx context.Context) error
5859

5960
// Version of the migration. Used only once in the beginning.
6061
Version(ctx context.Context) (version int, err error)
61-
// SetVersion is run after each migration.
62-
SetVersion(ctx context.Context, version int) error
63-
64-
// Begin the transaction before migration.
65-
// Might be no-op if DisableTx is set or transaction are not supported by database.
66-
Begin(ctx context.Context) error
67-
// Commit the transaction after migration.
68-
// Might be no-op if DisableTx is set or transaction are not supported by database.
69-
Commit(ctx context.Context) error
70-
// Rollback the transaction on migration fail.
71-
// Might be no-op if DisableTx is set or transaction are not supported by database.
72-
Rollback(ctx context.Context) error
73-
74-
// Exec the given query and params.
75-
Exec(ctx context.Context, query string, args ...interface{}) error
62+
63+
// DoStep runs the given query and sets a new version on success.
64+
DoStep(ctx context.Context, step Step) error
65+
}
66+
67+
// Step represents exact thing that is going to run.
68+
type Step struct {
69+
Version int
70+
Query string
71+
DisableTx bool
7672
}
7773

7874
// Loader returns migrations to be applied on a database.
@@ -197,50 +193,13 @@ func (m *mig) runMigrationsLocked(ctx context.Context, ms []*Migration) error {
197193
}
198194

199195
for _, step := range m.prepareSteps(curr, target, ms) {
200-
if err := m.execStep(ctx, step); err != nil {
196+
if err := m.DoStep(ctx, step); err != nil {
201197
return err
202198
}
203199
}
204200
return nil
205201
}
206202

207-
func (m *mig) execStep(ctx context.Context, step step) error {
208-
if m.Config.DisableTx {
209-
return m.execSimpleStep(ctx, step)
210-
}
211-
return m.execStepSafely(ctx, step)
212-
}
213-
214-
func (m *mig) execStepSafely(ctx context.Context, step step) (err error) {
215-
if err := m.Begin(ctx); err != nil {
216-
return fmt.Errorf("begin tx: %w", err)
217-
}
218-
219-
defer func() {
220-
if err != nil {
221-
if errRollback := m.Rollback(ctx); errRollback != nil {
222-
err = fmt.Errorf("(rollback tx: %v): %w", errRollback, err)
223-
}
224-
}
225-
}()
226-
227-
err = m.execSimpleStep(ctx, step)
228-
if err == nil {
229-
err = m.Commit(ctx)
230-
}
231-
return err
232-
}
233-
234-
func (m *mig) execSimpleStep(ctx context.Context, step step) error {
235-
if err := m.Exec(ctx, step.Query); err != nil {
236-
return fmt.Errorf("exec: %w", err)
237-
}
238-
if err := m.SetVersion(ctx, step.Version); err != nil {
239-
return fmt.Errorf("set version: %w", err)
240-
}
241-
return nil
242-
}
243-
244203
func (m *mig) getCurrAndTargetVersions(ctx context.Context, migrations int) (curr, target int, err error) {
245204
curr, err = m.Version(ctx)
246205
if err != nil {
@@ -278,11 +237,11 @@ func (m *mig) getCurrAndTargetVersions(ctx context.Context, migrations int) (cur
278237
return curr, target, nil
279238
}
280239

281-
func (m *mig) prepareSteps(curr, target int, ms []*Migration) []step {
240+
func (m *mig) prepareSteps(curr, target int, ms []*Migration) []Step {
282241
if curr == target {
283242
return nil
284243
}
285-
steps := []step{}
244+
steps := []Step{}
286245

287246
direction := 1
288247
if curr > target {
@@ -296,56 +255,44 @@ func (m *mig) prepareSteps(curr, target int, ms []*Migration) []step {
296255
idx--
297256
}
298257

299-
steps = append(steps, ms[idx].toStep(isUp))
258+
steps = append(steps, ms[idx].toStep(isUp, m.DisableTx))
300259
if m.ZigZag {
301260
steps = append(steps,
302-
ms[idx].toStep(!isUp),
303-
ms[idx].toStep(isUp))
261+
ms[idx].toStep(!isUp, m.DisableTx),
262+
ms[idx].toStep(isUp, m.DisableTx))
304263
}
305264
}
306265
return steps
307266
}
308267

309-
type step struct {
310-
Version int
311-
IsQuery bool
312-
Query string
313-
}
314-
315-
func (m *Migration) toStep(up bool) step {
268+
func (m *Migration) toStep(up, disableTx bool) Step {
316269
if up {
317-
return step{
318-
Version: m.ID,
319-
IsQuery: m.Apply != "",
320-
Query: m.Apply,
270+
return Step{
271+
Version: m.ID,
272+
Query: m.Apply,
273+
DisableTx: disableTx,
321274
}
322275
}
323-
return step{
324-
Version: m.ID - 1,
325-
IsQuery: m.Revert != "",
326-
Query: m.Revert,
276+
return Step{
277+
Version: m.ID - 1,
278+
Query: m.Revert,
279+
DisableTx: disableTx,
327280
}
328281
}
329282

330283
type locklessMigrator struct {
331284
m Migrator
332285
}
333286

334-
func (llm *locklessMigrator) Init(ctx context.Context) error { return llm.m.Init(ctx) }
335287
func (llm *locklessMigrator) LockDB(ctx context.Context) error { return nil }
336288
func (llm *locklessMigrator) UnlockDB(ctx context.Context) error { return nil }
337289

290+
func (llm *locklessMigrator) Init(ctx context.Context) error { return llm.m.Init(ctx) }
291+
338292
func (llm *locklessMigrator) Version(ctx context.Context) (version int, err error) {
339293
return llm.m.Version(ctx)
340294
}
341-
func (llm *locklessMigrator) SetVersion(ctx context.Context, version int) error {
342-
return llm.m.SetVersion(ctx, version)
343-
}
344-
345-
func (llm *locklessMigrator) Begin(ctx context.Context) error { return llm.m.Begin(ctx) }
346-
func (llm *locklessMigrator) Commit(ctx context.Context) error { return llm.m.Commit(ctx) }
347-
func (llm *locklessMigrator) Rollback(ctx context.Context) error { return llm.m.Rollback(ctx) }
348295

349-
func (llm *locklessMigrator) Exec(ctx context.Context, query string, args ...interface{}) error {
350-
return llm.m.Exec(ctx, query, args...)
296+
func (llm *locklessMigrator) DoStep(ctx context.Context, step Step) error {
297+
return llm.m.DoStep(ctx, step)
351298
}

‎dbump_test.go

Lines changed: 33 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ func TestRunCheck(t *testing.T) {
4747
func TestMigrateUp(t *testing.T) {
4848
wantLog := []string{
4949
"lockdb", "init", "getversion",
50-
"exec", "SELECT 1;", "[]", "setversion", "1",
51-
"exec", "SELECT 2;", "[]", "setversion", "2",
52-
"exec", "SELECT 3;", "[]", "setversion", "3",
53-
"exec", "SELECT 4;", "[]", "setversion", "4",
54-
"exec", "SELECT 5;", "[]", "setversion", "5",
50+
"dostep", "{v:1 q:'SELECT 1;' notx:true}",
51+
"dostep", "{v:2 q:'SELECT 2;' notx:true}",
52+
"dostep", "{v:3 q:'SELECT 3;' notx:true}",
53+
"dostep", "{v:4 q:'SELECT 4;' notx:true}",
54+
"dostep", "{v:5 q:'SELECT 5;' notx:true}",
5555
"unlockdb",
5656
}
5757

@@ -91,9 +91,7 @@ func TestMigrateUpOne(t *testing.T) {
9191
currVersion := 3
9292
wantLog := []string{
9393
"lockdb", "init", "getversion",
94-
"begin",
95-
"exec", "SELECT 4;", "[]", "setversion", "4",
96-
"commit",
94+
"dostep", "{v:4 q:'SELECT 4;' notx:false}",
9795
"unlockdb",
9896
}
9997

@@ -115,11 +113,11 @@ func TestMigrateUpOne(t *testing.T) {
115113
func TestMigrateDown(t *testing.T) {
116114
wantLog := []string{
117115
"lockdb", "init", "getversion",
118-
"exec", "SELECT 50;", "[]", "setversion", "4",
119-
"exec", "SELECT 40;", "[]", "setversion", "3",
120-
"exec", "SELECT 30;", "[]", "setversion", "2",
121-
"exec", "SELECT 20;", "[]", "setversion", "1",
122-
"exec", "SELECT 10;", "[]", "setversion", "0",
116+
"dostep", "{v:4 q:'SELECT 50;' notx:true}",
117+
"dostep", "{v:3 q:'SELECT 40;' notx:true}",
118+
"dostep", "{v:2 q:'SELECT 30;' notx:true}",
119+
"dostep", "{v:1 q:'SELECT 20;' notx:true}",
120+
"dostep", "{v:0 q:'SELECT 10;' notx:true}",
123121
"unlockdb",
124122
}
125123

@@ -163,9 +161,7 @@ func TestMigrateDownOne(t *testing.T) {
163161
currVersion := 3
164162
wantLog := []string{
165163
"lockdb", "init", "getversion",
166-
"begin",
167-
"exec", "SELECT 30;", "[]", "setversion", "2",
168-
"commit",
164+
"dostep", "{v:2 q:'SELECT 30;' notx:false}",
169165
"unlockdb",
170166
}
171167

@@ -188,8 +184,8 @@ func TestUseForce(t *testing.T) {
188184
currVersion := 3
189185
wantLog := []string{
190186
"lockdb", "unlockdb", "lockdb", "init", "getversion",
191-
"exec", "SELECT 4;", "[]", "setversion", "4",
192-
"exec", "SELECT 5;", "[]", "setversion", "5",
187+
"dostep", "{v:4 q:'SELECT 4;' notx:true}",
188+
"dostep", "{v:5 q:'SELECT 5;' notx:true}",
193189
"unlockdb",
194190
}
195191

@@ -225,25 +221,25 @@ func TestUseForce(t *testing.T) {
225221
func TestZigZag(t *testing.T) {
226222
wantLog := []string{
227223
"lockdb", "init", "getversion",
228-
"exec", "SELECT 1;", "[]", "setversion", "1",
229-
"exec", "SELECT 10;", "[]", "setversion", "0",
230-
"exec", "SELECT 1;", "[]", "setversion", "1",
224+
"dostep", "{v:1 q:'SELECT 1;' notx:true}",
225+
"dostep", "{v:0 q:'SELECT 10;' notx:true}",
226+
"dostep", "{v:1 q:'SELECT 1;' notx:true}",
231227

232-
"exec", "SELECT 2;", "[]", "setversion", "2",
233-
"exec", "SELECT 20;", "[]", "setversion", "1",
234-
"exec", "SELECT 2;", "[]", "setversion", "2",
228+
"dostep", "{v:2 q:'SELECT 2;' notx:true}",
229+
"dostep", "{v:1 q:'SELECT 20;' notx:true}",
230+
"dostep", "{v:2 q:'SELECT 2;' notx:true}",
235231

236-
"exec", "SELECT 3;", "[]", "setversion", "3",
237-
"exec", "SELECT 30;", "[]", "setversion", "2",
238-
"exec", "SELECT 3;", "[]", "setversion", "3",
232+
"dostep", "{v:3 q:'SELECT 3;' notx:true}",
233+
"dostep", "{v:2 q:'SELECT 30;' notx:true}",
234+
"dostep", "{v:3 q:'SELECT 3;' notx:true}",
239235

240-
"exec", "SELECT 4;", "[]", "setversion", "4",
241-
"exec", "SELECT 40;", "[]", "setversion", "3",
242-
"exec", "SELECT 4;", "[]", "setversion", "4",
236+
"dostep", "{v:4 q:'SELECT 4;' notx:true}",
237+
"dostep", "{v:3 q:'SELECT 40;' notx:true}",
238+
"dostep", "{v:4 q:'SELECT 4;' notx:true}",
243239

244-
"exec", "SELECT 5;", "[]", "setversion", "5",
245-
"exec", "SELECT 50;", "[]", "setversion", "4",
246-
"exec", "SELECT 5;", "[]", "setversion", "5",
240+
"dostep", "{v:5 q:'SELECT 5;' notx:true}",
241+
"dostep", "{v:4 q:'SELECT 50;' notx:true}",
242+
"dostep", "{v:5 q:'SELECT 5;' notx:true}",
247243
"unlockdb",
248244
}
249245

@@ -298,9 +294,7 @@ func TestFailOnUnlockDB(t *testing.T) {
298294
currVersion := 4
299295
wantLog := []string{
300296
"lockdb", "init", "getversion",
301-
"begin",
302-
"exec", "SELECT 5;", "[]", "setversion", "5",
303-
"commit",
297+
"dostep", "{v:5 q:'SELECT 5;' notx:false}",
304298
"unlockdb",
305299
}
306300
mm := &MockMigrator{
@@ -340,16 +334,14 @@ func TestFailOnGetVersionError(t *testing.T) {
340334
mustEqual(t, mm.log, wantLog)
341335
}
342336

343-
func TestFailOnSetVersionError(t *testing.T) {
337+
func TestFailOnDoStepError(t *testing.T) {
344338
wantLog := []string{
345339
"lockdb", "init", "getversion",
346-
"begin",
347-
"exec", "SELECT 1;", "[]", "setversion", "1",
348-
"rollback",
340+
"dostep", "{v:1 q:'SELECT 1;' notx:false}",
349341
"unlockdb",
350342
}
351343
mm := &MockMigrator{
352-
SetVersionFn: func(ctx context.Context, version int) error {
344+
DoStepFn: func(ctx context.Context, step Step) error {
353345
return errors.New("no access")
354346
},
355347
}
@@ -363,101 +355,6 @@ func TestFailOnSetVersionError(t *testing.T) {
363355
mustEqual(t, mm.log, wantLog)
364356
}
365357

366-
func TestFailOnBegin(t *testing.T) {
367-
wantLog := []string{
368-
"lockdb", "init", "getversion",
369-
"begin",
370-
"unlockdb",
371-
}
372-
mm := &MockMigrator{
373-
BeginFn: func(ctx context.Context) error {
374-
return errors.New("timeout")
375-
},
376-
}
377-
cfg := Config{
378-
Migrator: mm,
379-
Loader: NewSliceLoader(testdataMigrations),
380-
Mode: ModeUp,
381-
}
382-
383-
failIfOk(t, Run(context.Background(), cfg))
384-
mustEqual(t, mm.log, wantLog)
385-
}
386-
387-
func TestFailOnExec(t *testing.T) {
388-
wantLog := []string{
389-
"lockdb", "init", "getversion",
390-
"begin",
391-
"exec", "SELECT 1;", "[]",
392-
"rollback",
393-
"unlockdb",
394-
}
395-
mm := &MockMigrator{
396-
ExecFn: func(ctx context.Context, query string, args ...interface{}) error {
397-
return errors.New("syntax error")
398-
},
399-
}
400-
cfg := Config{
401-
Migrator: mm,
402-
Loader: NewSliceLoader(testdataMigrations),
403-
Mode: ModeUp,
404-
}
405-
406-
failIfOk(t, Run(context.Background(), cfg))
407-
mustEqual(t, mm.log, wantLog)
408-
}
409-
410-
func TestFailOnCommit(t *testing.T) {
411-
wantLog := []string{
412-
"lockdb", "init", "getversion",
413-
"begin",
414-
"exec", "SELECT 1;", "[]", "setversion", "1",
415-
"commit",
416-
"rollback",
417-
"unlockdb",
418-
}
419-
mm := &MockMigrator{
420-
CommitFn: func(ctx context.Context) error {
421-
return errors.New("constraint violation")
422-
},
423-
}
424-
cfg := Config{
425-
Migrator: mm,
426-
Loader: NewSliceLoader(testdataMigrations),
427-
Mode: ModeUp,
428-
}
429-
430-
failIfOk(t, Run(context.Background(), cfg))
431-
mustEqual(t, mm.log, wantLog)
432-
}
433-
434-
func TestFailOnRollback(t *testing.T) {
435-
wantLog := []string{
436-
"lockdb", "init", "getversion",
437-
"begin",
438-
"exec", "SELECT 1;", "[]", "setversion", "1",
439-
"commit",
440-
"rollback",
441-
"unlockdb",
442-
}
443-
mm := &MockMigrator{
444-
CommitFn: func(ctx context.Context) error {
445-
return errors.New("constraint violation")
446-
},
447-
RollbackFn: func(ctx context.Context) error {
448-
return errors.New("timeout")
449-
},
450-
}
451-
cfg := Config{
452-
Migrator: mm,
453-
Loader: NewSliceLoader(testdataMigrations),
454-
Mode: ModeUp,
455-
}
456-
457-
failIfOk(t, Run(context.Background(), cfg))
458-
mustEqual(t, mm.log, wantLog)
459-
}
460-
461358
func TestFailOnLoad(t *testing.T) {
462359
cfg := Config{
463360
Migrator: &MockMigrator{},

‎mock_test.go

Lines changed: 15 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,18 @@ package dbump
33
import (
44
"context"
55
"fmt"
6-
"strconv"
76
)
87

98
var _ Migrator = &MockMigrator{}
109

1110
type MockMigrator struct {
1211
log []string
1312

14-
InitFn func(ctx context.Context) error
1513
LockDBFn func(ctx context.Context) error
1614
UnlockDBFn func(ctx context.Context) error
17-
18-
VersionFn func(ctx context.Context) (version int, err error)
19-
SetVersionFn func(ctx context.Context, version int) error
20-
21-
BeginFn func(ctx context.Context) error
22-
CommitFn func(ctx context.Context) error
23-
RollbackFn func(ctx context.Context) error
24-
ExecFn func(ctx context.Context, query string, args ...interface{}) error
25-
}
26-
27-
func (mm *MockMigrator) Init(ctx context.Context) error {
28-
mm.log = append(mm.log, "init")
29-
if mm.InitFn == nil {
30-
return nil
31-
}
32-
return mm.InitFn(ctx)
15+
InitFn func(ctx context.Context) error
16+
VersionFn func(ctx context.Context) (version int, err error)
17+
DoStepFn func(ctx context.Context, step Step) error
3318
}
3419

3520
func (mm *MockMigrator) LockDB(ctx context.Context) error {
@@ -48,6 +33,14 @@ func (mm *MockMigrator) UnlockDB(ctx context.Context) error {
4833
return mm.UnlockDBFn(ctx)
4934
}
5035

36+
func (mm *MockMigrator) Init(ctx context.Context) error {
37+
mm.log = append(mm.log, "init")
38+
if mm.InitFn == nil {
39+
return nil
40+
}
41+
return mm.InitFn(ctx)
42+
}
43+
5144
func (mm *MockMigrator) Version(ctx context.Context) (version int, err error) {
5245
mm.log = append(mm.log, "getversion")
5346
if mm.VersionFn == nil {
@@ -56,42 +49,12 @@ func (mm *MockMigrator) Version(ctx context.Context) (version int, err error) {
5649
return mm.VersionFn(ctx)
5750
}
5851

59-
func (mm *MockMigrator) SetVersion(ctx context.Context, version int) error {
60-
mm.log = append(mm.log, "setversion", strconv.Itoa(version))
61-
if mm.SetVersionFn == nil {
62-
return nil
63-
}
64-
return mm.SetVersionFn(ctx, version)
65-
}
66-
67-
func (mm *MockMigrator) Begin(ctx context.Context) error {
68-
mm.log = append(mm.log, "begin")
69-
if mm.BeginFn == nil {
70-
return nil
71-
}
72-
return mm.BeginFn(ctx)
73-
}
74-
func (mm *MockMigrator) Commit(ctx context.Context) error {
75-
mm.log = append(mm.log, "commit")
76-
if mm.CommitFn == nil {
77-
return nil
78-
}
79-
return mm.CommitFn(ctx)
80-
}
81-
func (mm *MockMigrator) Rollback(ctx context.Context) error {
82-
mm.log = append(mm.log, "rollback")
83-
if mm.RollbackFn == nil {
84-
return nil
85-
}
86-
return mm.RollbackFn(ctx)
87-
}
88-
89-
func (mm *MockMigrator) Exec(ctx context.Context, query string, args ...interface{}) error {
90-
mm.log = append(mm.log, "exec", query, fmt.Sprintf("%+v", args))
91-
if mm.ExecFn == nil {
52+
func (mm *MockMigrator) DoStep(ctx context.Context, step Step) error {
53+
mm.log = append(mm.log, "dostep", fmt.Sprintf("{v:%d q:'%s' notx:%v}", step.Version, step.Query, step.DisableTx))
54+
if mm.DoStepFn == nil {
9255
return nil
9356
}
94-
return mm.ExecFn(ctx, query, args...)
57+
return mm.DoStepFn(ctx, step)
9558
}
9659

9760
type MockLoader struct {

0 commit comments

Comments
 (0)
Please sign in to comment.