github.com/dannyzhou2015/migrate/v4@v4.15.2/source/driver.go (about) 1 // Package source provides the Source interface. 2 // All source drivers must implement this interface, register themselves, 3 // optionally provide a `WithInstance` function and pass the tests 4 // in package source/testing. 5 package source 6 7 import ( 8 "fmt" 9 "io" 10 nurl "net/url" 11 "sync" 12 ) 13 14 var driversMu sync.RWMutex 15 var drivers = make(map[string]Driver) 16 17 // Driver is the interface every source driver must implement. 18 // 19 // How to implement a source driver? 20 // 1. Implement this interface. 21 // 2. Optionally, add a function named `WithInstance`. 22 // This function should accept an existing source instance and a Config{} struct 23 // and return a driver instance. 24 // 3. Add a test that calls source/testing.go:Test() 25 // 4. Add own tests for Open(), WithInstance() (when provided) and Close(). 26 // All other functions are tested by tests in source/testing. 27 // Saves you some time and makes sure all source drivers behave the same way. 28 // 5. Call Register in init(). 29 // 30 // Guidelines: 31 // * All configuration input must come from the URL string in func Open() 32 // or the Config{} struct in WithInstance. Don't os.Getenv(). 33 // * Drivers are supposed to be read only. 34 // * Ideally don't load any contents (into memory) in Open or WithInstance. 35 type Driver interface { 36 // Open returns a new driver instance configured with parameters 37 // coming from the URL string. Migrate will call this function 38 // only once per instance. 39 Open(url string) (Driver, error) 40 41 // Close closes the underlying source instance managed by the driver. 42 // Migrate will call this function only once per instance. 43 Close() error 44 45 // First returns the very first migration version available to the driver. 46 // Migrate will call this function multiple times. 47 // If there is no version available, it must return os.ErrNotExist. 48 First() (version uint, err error) 49 50 // Prev returns the previous version for a given version available to the driver. 51 // Migrate will call this function multiple times. 52 // If there is no previous version available, it must return os.ErrNotExist. 53 Prev(version uint) (prevVersion uint, err error) 54 55 // Next returns the next version for a given version available to the driver. 56 // Migrate will call this function multiple times. 57 // If there is no next version available, it must return os.ErrNotExist. 58 Next(version uint) (nextVersion uint, err error) 59 60 // ReadUp returns the UP migration body and an identifier that helps 61 // finding this migration in the source for a given version. 62 // If there is no up migration available for this version, 63 // it must return os.ErrNotExist. 64 // Do not start reading, just return the ReadCloser! 65 ReadUp(version uint) (r io.ReadCloser, identifier string, err error) 66 67 // ReadDown returns the DOWN migration body and an identifier that helps 68 // finding this migration in the source for a given version. 69 // If there is no down migration available for this version, 70 // it must return os.ErrNotExist. 71 // Do not start reading, just return the ReadCloser! 72 ReadDown(version uint) (r io.ReadCloser, identifier string, err error) 73 } 74 75 // Open returns a new driver instance. 76 func Open(url string) (Driver, error) { 77 u, err := nurl.Parse(url) 78 if err != nil { 79 return nil, err 80 } 81 82 if u.Scheme == "" { 83 return nil, fmt.Errorf("source driver: invalid URL scheme") 84 } 85 86 driversMu.RLock() 87 d, ok := drivers[u.Scheme] 88 driversMu.RUnlock() 89 if !ok { 90 return nil, fmt.Errorf("source driver: unknown driver '%s' (forgotten import?)", u.Scheme) 91 } 92 93 return d.Open(url) 94 } 95 96 // Register globally registers a driver. 97 func Register(name string, driver Driver) { 98 driversMu.Lock() 99 defer driversMu.Unlock() 100 if driver == nil { 101 panic("Register driver is nil") 102 } 103 if _, dup := drivers[name]; dup { 104 panic("Register called twice for driver " + name) 105 } 106 drivers[name] = driver 107 } 108 109 // List lists the registered drivers 110 func List() []string { 111 driversMu.RLock() 112 defer driversMu.RUnlock() 113 names := make([]string, 0, len(drivers)) 114 for n := range drivers { 115 names = append(names, n) 116 } 117 return names 118 }