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  }