github.com/gocaveman/caveman@v0.0.0-20191211162744-0ddf99dbdf6e/migrate/migratedbr/migratedbr.go (about) 1 package migratedbr 2 3 import ( 4 "fmt" 5 6 "github.com/gocraft/dbr" 7 ) 8 9 func New(driverName, dsn string) (*DbrVersioner, error) { 10 return NewTable(driverName, dsn, "migration_state") 11 } 12 13 func NewTable(driverName, dsn, tableName string) (*DbrVersioner, error) { 14 15 conn, err := dbr.Open(driverName, dsn, nil) 16 if err != nil { 17 return nil, err 18 } 19 20 // TODO: might need to do variations on this but for now this should work for mysql, postgres and sqlite3 21 // FIXME: category changed to 128 due to some obscure MariaDB encoding issue, needs more thought 22 // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=886756 23 _, err = conn.DB.Exec(` 24 CREATE TABLE IF NOT EXISTS ` + tableName + ` ( 25 category varchar(128), 26 version varchar(255), 27 status varchar(255), 28 PRIMARY KEY (category) 29 ) 30 `) 31 if err != nil { 32 return nil, err 33 } 34 35 return &DbrVersioner{ 36 Connection: conn, 37 TableName: tableName, 38 }, nil 39 } 40 41 type DbrVersioner struct { 42 Connection *dbr.Connection 43 TableName string 44 } 45 46 func (v *DbrVersioner) Close() error { 47 return v.Connection.Close() 48 } 49 50 func (v *DbrVersioner) Categories() ([]string, error) { 51 52 sess := v.Connection.NewSession(nil) 53 recs := []struct { 54 Category string `db:"category"` 55 }{} 56 n, err := sess.Select("category").From(v.TableName).Load(&recs) 57 if err != nil { 58 return nil, err 59 } 60 61 ret := make([]string, 0, n) 62 for _, rec := range recs { 63 ret = append(ret, rec.Category) 64 } 65 66 return ret, nil 67 } 68 69 func (v *DbrVersioner) Version(category string) (string, error) { 70 71 versionName := "" 72 73 sess := v.Connection.NewSession(nil) 74 err := sess.Select("version").From(v.TableName).Where("category = ?", category).LoadOne(&versionName) 75 76 // treat missing row as empty version 77 if err == dbr.ErrNotFound { 78 return "", nil 79 } 80 81 return versionName, err 82 } 83 84 func (v *DbrVersioner) StartVersionChange(category, currentVersion string) error { 85 86 sess := v.Connection.NewSession(nil) 87 88 // tx, err := v.DB.Begin() 89 // if err != nil { 90 // return err 91 // } 92 // defer tx.Rollback() 93 94 versionName := "" 95 96 err := sess.Select("version").From(v.TableName).Where("category = ?", category).LoadOne(&versionName) 97 if err == dbr.ErrNotFound { 98 99 _, err := sess.InsertInto(v.TableName).Columns("category", "version", "status").Values(category, "", "none").Exec() 100 if err != nil { 101 return err 102 } 103 104 } else if err != nil { 105 return err 106 } 107 108 // row := tx.QueryRow(`SELECT version FROM `+v.TableName+` WHERE category = ?`, category) 109 // err = row.Scan(&versionName) 110 // if err == sql.ErrNoRows { 111 // _, err := tx.Exec(`INSERT INTO `+v.TableName+`(category, version, status) VALUES(?,?,?)`, category, "", "none") 112 // if err != nil { 113 // return err 114 // } 115 // } else if err != nil { 116 // return err 117 // } 118 119 if versionName != currentVersion { 120 return fmt.Errorf("incorrect version, found %q expected %q", versionName, currentVersion) 121 } 122 123 res, err := sess.Update(v.TableName). 124 Set("status", "inprogress"). 125 Where(dbr.And( 126 dbr.Eq("category", category), 127 dbr.Eq("status", "none"), 128 dbr.Eq("version", currentVersion), 129 )). 130 Exec() 131 132 if err != nil { 133 return err 134 } 135 136 // res, err := tx.Exec(`UPDATE `+v.TableName+` SET status = ? WHERE category = ? AND status = ? AND version = ?`, "inprogress", category, "none", currentVersion) 137 // if err != nil { 138 // return err 139 // } 140 141 n, err := res.RowsAffected() 142 if err != nil { 143 return err 144 } 145 146 if n != 1 { 147 return fmt.Errorf("StartVersionChange UPDATE statement returned num rows affected %d (expected 1)", n) 148 } 149 150 // err = tx.Commit() 151 // if err != nil { 152 // return err 153 // } 154 155 return nil 156 157 } 158 159 func (v *DbrVersioner) EndVersionChange(category, newVersionName string) error { 160 161 // tx, err := v.DB.Begin() 162 // if err != nil { 163 // return err 164 // } 165 // defer tx.Rollback() 166 167 sess := v.Connection.NewSession(nil) 168 169 res, err := sess.Update(v.TableName). 170 Set("version", newVersionName). 171 Set("status", "none"). 172 Where(dbr.And(dbr.Eq("category", category), dbr.Eq("status", "inprogress"))). 173 Exec() 174 175 // res, err := tx.Exec(`UPDATE `+v.TableName+` SET version = ?, status = ? WHERE category = ? AND status = ?`, newVersionName, "none", category, "inprogress") 176 // if err != nil { 177 // return err 178 // } 179 180 n, err := res.RowsAffected() 181 if err != nil { 182 return err 183 } 184 185 if n != 1 { 186 return fmt.Errorf("EndVersionChange UPDATE statement returned num rows affected %d (expected 1)", n) 187 } 188 189 // err = tx.Commit() 190 // if err != nil { 191 // return err 192 // } 193 194 return nil 195 }