github.com/gocaveman/caveman@v0.0.0-20191211162744-0ddf99dbdf6e/ddl/ddl-tmpl-migration.go (about) 1 package ddl 2 3 import ( 4 "bytes" 5 "database/sql" 6 "fmt" 7 "html/template" 8 "reflect" 9 ) 10 11 type DDLTmplMigrationList []DDLTmplMigration 12 13 // AppendTo is a helper to append a list of migrations to any slices whose element type 14 // is compatible with (*DDLTmplMigration). This makes it a single simple function call 15 // to add your DDLTmplMigrations to a migrate.MigrationList. 16 // The argument must be a pointer to a slice, any incorrect type (not a pointer to 17 // a slice or element type not compatible) will result in a panic. 18 func (l DDLTmplMigrationList) AppendTo(slicePtr interface{}) { 19 vptr := reflect.ValueOf(slicePtr) 20 if vptr.Kind() != reflect.Ptr { 21 panic("value provided is not a pointer") 22 } 23 vd := vptr.Elem() // deref pointer 24 if vd.Kind() != reflect.Slice { 25 panic("value provided does not point to a slice") 26 } 27 28 newSliceV := vd 29 for i := range l { 30 newSliceV = reflect.Append(newSliceV, reflect.ValueOf(&l[i])) 31 } 32 vd.Set(newSliceV) 33 } 34 35 // DDLTmplMigration implements the migrate.Migration interface and supports templates. 36 // It is does the same thing as migrate.SQLTmplMigration but it's here in the ddl 37 // package so we don't have unnecessary dependencies. 38 type DDLTmplMigration struct { 39 DriverNameValue string 40 CategoryValue string 41 VersionValue string 42 UpSQL []string 43 DownSQL []string 44 45 // a common reason to use DDLTmplMigration is be able to configure the table prefix 46 TablePrefix string `autowire:"db.TablePrefix,optional"` 47 // other custom data needed by the template(s) can go here 48 Data interface{} 49 } 50 51 func (m *DDLTmplMigration) DriverName() string { return m.DriverNameValue } 52 func (m *DDLTmplMigration) Category() string { return m.CategoryValue } 53 func (m *DDLTmplMigration) Version() string { return m.VersionValue } 54 55 func (m *DDLTmplMigration) tmplExec(dsn string, stmts []string) error { 56 57 db, err := sql.Open(m.DriverNameValue, dsn) 58 if err != nil { 59 return err 60 } 61 defer db.Close() 62 63 for n, s := range stmts { 64 65 t := template.New("sql") 66 t, err := t.Parse(s) 67 if err != nil { 68 return fmt.Errorf("DDLTmplMigration (driverName=%q, category=%q, version=%q, stmtidx=%d) template parse on dsn=%q failed with error: %v\nSQL Statement:\n%s", 69 m.DriverNameValue, m.CategoryValue, m.VersionValue, n, dsn, err, s) 70 } 71 72 var buf bytes.Buffer 73 err = t.Execute(&buf, m) 74 if err != nil { 75 return fmt.Errorf("DDLTmplMigration (driverName=%q, category=%q, version=%q, stmtidx=%d) template execute on dsn=%q failed with error: %v\nSQL Statement:\n%s", 76 m.DriverNameValue, m.CategoryValue, m.VersionValue, n, dsn, err, s) 77 } 78 79 newS := buf.String() 80 81 _, err = db.Exec(newS) 82 if err != nil { 83 return fmt.Errorf("DDLTmplMigration (driverName=%q, category=%q, version=%q, stmtidx=%d) Exec on dsn=%q failed with error: %v\nSQL Statement:\n%s", 84 m.DriverNameValue, m.CategoryValue, m.VersionValue, n, dsn, err, newS) 85 } 86 } 87 88 return nil 89 } 90 91 // ExecUp will run the up migration statements. 92 func (m *DDLTmplMigration) ExecUp(dsn string) error { 93 return m.tmplExec(dsn, m.UpSQL) 94 } 95 96 // ExecUp will run the down migration statements. 97 func (m *DDLTmplMigration) ExecDown(dsn string) error { 98 return m.tmplExec(dsn, m.DownSQL) 99 }