forked from pressly/goose
-
Notifications
You must be signed in to change notification settings - Fork 0
/
provider_options.go
198 lines (177 loc) · 5.9 KB
/
provider_options.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package goose
import (
"errors"
"fmt"
"github.com/pressly/goose/v3/database"
"github.com/pressly/goose/v3/lock"
)
const (
// DefaultTablename is the default name of the database table used to track history of applied
// migrations.
DefaultTablename = "goose_db_version"
)
// ProviderOption is a configuration option for a goose goose.
type ProviderOption interface {
apply(*config) error
}
// WithStore configures the provider with a custom [database.Store] implementation.
//
// By default, the provider uses the [database.NewStore] function to create a store backed by the
// given dialect. However, this option allows users to provide their own implementation or call
// [database.NewStore] with custom options, such as setting the table name.
//
// Example:
//
// // Create a store with a custom table name.
// store, err := database.NewStore(database.DialectPostgres, "my_custom_table_name")
// if err != nil {
// return err
// }
// // Create a provider with the custom store.
// provider, err := goose.NewProvider("", db, nil, goose.WithStore(store))
// if err != nil {
// return err
// }
func WithStore(store database.Store) ProviderOption {
return configFunc(func(c *config) error {
if c.store != nil {
return fmt.Errorf("store already set: %T", c.store)
}
if store == nil {
return errors.New("store must not be nil")
}
if store.Tablename() == "" {
return errors.New("store implementation must set the table name")
}
c.store = store
return nil
})
}
// WithVerbose enables verbose logging.
func WithVerbose(b bool) ProviderOption {
return configFunc(func(c *config) error {
c.verbose = b
return nil
})
}
// WithSessionLocker enables locking using the provided SessionLocker.
//
// If WithSessionLocker is not called, locking is disabled.
func WithSessionLocker(locker lock.SessionLocker) ProviderOption {
return configFunc(func(c *config) error {
if c.lockEnabled {
return errors.New("lock already enabled")
}
if c.sessionLocker != nil {
return errors.New("session locker already set")
}
if locker == nil {
return errors.New("session locker must not be nil")
}
c.lockEnabled = true
c.sessionLocker = locker
return nil
})
}
// WithExcludeNames excludes the given file name from the list of migrations. If called multiple
// times, the list of excludes is merged.
func WithExcludeNames(excludes []string) ProviderOption {
return configFunc(func(c *config) error {
for _, name := range excludes {
if _, ok := c.excludePaths[name]; ok {
return fmt.Errorf("duplicate exclude file name: %s", name)
}
c.excludePaths[name] = true
}
return nil
})
}
// WithExcludeVersions excludes the given versions from the list of migrations. If called multiple
// times, the list of excludes is merged.
func WithExcludeVersions(versions []int64) ProviderOption {
return configFunc(func(c *config) error {
for _, version := range versions {
if version < 1 {
return errInvalidVersion
}
if _, ok := c.excludeVersions[version]; ok {
return fmt.Errorf("duplicate excludes version: %d", version)
}
c.excludeVersions[version] = true
}
return nil
})
}
// WithGoMigrations registers Go migrations with the provider. If a Go migration with the same
// version has already been registered, an error will be returned.
//
// Go migrations must be constructed using the [NewGoMigration] function.
func WithGoMigrations(migrations ...*Migration) ProviderOption {
return configFunc(func(c *config) error {
for _, m := range migrations {
if _, ok := c.registered[m.Version]; ok {
return fmt.Errorf("go migration with version %d already registered", m.Version)
}
if err := checkGoMigration(m); err != nil {
return fmt.Errorf("invalid go migration: %w", err)
}
c.registered[m.Version] = m
}
return nil
})
}
// WithDisableGlobalRegistry prevents the provider from registering Go migrations from the global
// registry. By default, goose will register all Go migrations including those registered globally.
func WithDisableGlobalRegistry(b bool) ProviderOption {
return configFunc(func(c *config) error {
c.disableGlobalRegistry = b
return nil
})
}
// WithAllowOutofOrder allows the provider to apply missing (out-of-order) migrations. By default,
// goose will raise an error if it encounters a missing migration.
//
// For example: migrations 1,3 are applied and then version 2,6 are introduced. If this option is
// true, then goose will apply 2 (missing) and 6 (new) instead of raising an error. The final order
// of applied migrations will be: 1,3,2,6. Out-of-order migrations are always applied first,
// followed by new migrations.
func WithAllowOutofOrder(b bool) ProviderOption {
return configFunc(func(c *config) error {
c.allowMissing = b
return nil
})
}
// WithDisableVersioning disables versioning. Disabling versioning allows applying migrations
// without tracking the versions in the database schema table. Useful for tests, seeding a database
// or running ad-hoc queries. By default, goose will track all versions in the database schema
// table.
func WithDisableVersioning(b bool) ProviderOption {
return configFunc(func(c *config) error {
c.disableVersioning = b
return nil
})
}
type config struct {
store database.Store
verbose bool
excludePaths map[string]bool
excludeVersions map[int64]bool
// Go migrations registered by the user. These will be merged/resolved against the globally
// registered migrations.
registered map[int64]*Migration
// Locking options
lockEnabled bool
sessionLocker lock.SessionLocker
// Feature
disableVersioning bool
allowMissing bool
disableGlobalRegistry bool
// Let's not expose the Logger just yet. Ideally we consolidate on the std lib slog package
// added in go1.21 and then expose that (if that's even necessary). For now, just use the std
// lib log package.
logger Logger
}
type configFunc func(*config) error
func (f configFunc) apply(cfg *config) error {
return f(cfg)
}