-
Notifications
You must be signed in to change notification settings - Fork 14
/
migrator.go
123 lines (110 loc) · 3.35 KB
/
migrator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package bunmigrator
import (
"context"
"database/sql"
"io/fs"
"os"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/migrate"
"github.com/peterldowns/pgtestdb"
"github.com/peterldowns/pgtestdb/migrators/common"
)
var _ pgtestdb.Migrator = (*BunMigrator)(nil)
// Option provides a way to configure the BunMigrator struct and its behaviour.
//
// bun migration documentation: https://bun.uptrace.dev/guide/migrations.html
//
// See:
// - [WithFS]
// - [WithBunDBOpts]
// - [WithMigratorOpts]
// - [WithMigrationOpts]
type Option func(*BunMigrator)
// WithFS specifies a `fs.FS` from which to read the migration files.
//
// Default: `<nil>` (reads from the real filesystem)
func WithFS(dir fs.FS) Option {
return func(bm *BunMigrator) {
bm.FS = dir
}
}
// WithBunDBOpts passes options to the bun.DB struct.
func WithBunDBOpts(opts ...bun.DBOption) Option {
return func(bm *BunMigrator) {
bm.BunDBOpts = opts
}
}
// WithMigratorOpts passes options to the migrate.Migrator.
func WithMigratorOpts(opts ...migrate.MigratorOption) Option {
return func(bm *BunMigrator) {
bm.MigratorOpts = opts
}
}
// WithMigrationOpts passes options to the migrate.Migrator.Migrate() func.
func WithMigrationOpts(opts ...migrate.MigrationOption) Option {
return func(bm *BunMigrator) {
bm.MigrationOpts = opts
}
}
// New returns a [BunMigrator], which is a pgtestdb.Migrator that
// uses bun to perform migrations.
//
// `migrationsDir` is the path to the directory containing migration files.
//
// You can configure the behaviour of bun by passing Options:
// - [WithFS] allows you to use an embedded filesystem.
// - [WithBunDBOpts] allows you to pass options to the underlying bun.DB struct.
// - [WithMigrationOpts] allows you to pass options to the Migrate() function.
// - [WithMigratorOpts] allows you to pass options to the Migrator struct.
func New(migrationsDir string, opts ...Option) *BunMigrator {
bm := &BunMigrator{
MigrationsDir: migrationsDir,
FS: nil,
}
for _, opt := range opts {
opt(bm)
}
return bm
}
// BunMigrator is a pgtestdb.Migrator that uses bun to perform migrations.
//
// Because Hash() requires calculating a unique hash based on the contents of
// the migrations, this implementation only supports reading migration files
// from disk or an embedded filesystem.
type BunMigrator struct {
MigrationsDir string
FS fs.FS
BunDBOpts []bun.DBOption
MigratorOpts []migrate.MigratorOption
MigrationOpts []migrate.MigrationOption
}
func (bm *BunMigrator) Hash() (string, error) {
return common.HashDirs(bm.FS, "*.sql", bm.MigrationsDir)
}
// Migrate migrates the template database.
func (bm *BunMigrator) Migrate(ctx context.Context, sqldb *sql.DB, _ pgtestdb.Config) error {
var err error
migrations := migrate.NewMigrations()
if bm.FS == nil {
err = migrations.Discover(os.DirFS(bm.MigrationsDir))
} else {
err = migrations.Discover(bm.FS)
}
if err != nil {
return err
}
db := bun.NewDB(sqldb, pgdialect.New(), bm.BunDBOpts...)
m := migrate.NewMigrator(db, migrations, bm.MigratorOpts...)
// Initialize the bun migrator, creating the tables that keep track of which
// migrations have been applied.
err = m.Init(ctx)
if err != nil {
return err
}
// Apply the migrations.
if _, err := m.Migrate(ctx, bm.MigrationOpts...); err != nil {
return err
}
return nil
}