Monorepo for Tangled tangled.org

add migration handler

Changed files
+55
appview
db
+55
appview/db/db.go
··· 3 3 import ( 4 4 "context" 5 5 "database/sql" 6 + "log" 6 7 7 8 _ "github.com/mattn/go-sqlite3" 8 9 ) ··· 122 123 unique(starred_by_did, repo_at) 123 124 ); 124 125 126 + create table if not exists migrations ( 127 + id integer primary key autoincrement, 128 + name text unique 129 + ) 125 130 `) 126 131 if err != nil { 127 132 return nil, err 128 133 } 134 + 135 + // run migrations 136 + runMigration(db, "add-description-to-repos", func(tx *sql.Tx) error { 137 + tx.Exec(` 138 + alter table repos add column description text check (length(description) <= 200); 139 + `) 140 + return nil 141 + }) 142 + 129 143 return &DB{db}, nil 130 144 } 145 + 146 + type migrationFn = func(*sql.Tx) error 147 + 148 + func runMigration(d *sql.DB, name string, migrationFn migrationFn) error { 149 + tx, err := d.Begin() 150 + if err != nil { 151 + return err 152 + } 153 + defer tx.Rollback() 154 + 155 + var exists bool 156 + err = tx.QueryRow("select exists (select 1 from migrations where name = ?)", name).Scan(&exists) 157 + if err != nil { 158 + return err 159 + } 160 + 161 + if !exists { 162 + // run migration 163 + err = migrationFn(tx) 164 + if err != nil { 165 + log.Printf("Failed to run migration %s: %v", name, err) 166 + return err 167 + } 168 + 169 + // mark migration as complete 170 + _, err = tx.Exec("insert into migrations (name) values (?)", name) 171 + if err != nil { 172 + log.Printf("Failed to mark migration %s as complete: %v", name, err) 173 + return err 174 + } 175 + 176 + // commit the transaction 177 + if err := tx.Commit(); err != nil { 178 + return err 179 + } 180 + } else { 181 + log.Printf("skipped migration %s, already applied", name) 182 + } 183 + 184 + return nil 185 + }