createDatabaseFromTemplate creates a new database from a template database. If templateDBName is empty, it will create a new template database based on the current migrations, and name it "tpl_ ". Or if it's already been created, it will use that.
(t TBSubset, connParams ConnectionParams, db *sql.DB, newDBName string, templateDBName string)
| 186 | // the current migrations, and name it "tpl_<migrations_hash>". Or if it's |
| 187 | // already been created, it will use that. |
| 188 | func createDatabaseFromTemplate(t TBSubset, connParams ConnectionParams, db *sql.DB, newDBName string, templateDBName string) error { |
| 189 | t.Helper() |
| 190 | |
| 191 | emptyTemplateDBName := templateDBName == "" |
| 192 | if emptyTemplateDBName { |
| 193 | templateDBName = fmt.Sprintf("tpl_%s", migrations.GetMigrationsHash()[:32]) |
| 194 | } |
| 195 | _, err := db.Exec("CREATE DATABASE " + newDBName + " WITH TEMPLATE " + templateDBName) |
| 196 | if err == nil { |
| 197 | // Template database already exists and we successfully created the new database. |
| 198 | return nil |
| 199 | } |
| 200 | tplDbDoesNotExistOccurred := strings.Contains(err.Error(), "template database") && strings.Contains(err.Error(), "does not exist") |
| 201 | if (tplDbDoesNotExistOccurred && !emptyTemplateDBName) || !tplDbDoesNotExistOccurred { |
| 202 | // First and case: user passed a templateDBName that doesn't exist. |
| 203 | // Second and case: some other error. |
| 204 | return xerrors.Errorf("create db with template: %w", err) |
| 205 | } |
| 206 | if !emptyTemplateDBName { |
| 207 | // sanity check |
| 208 | panic("templateDBName is not empty. there's a bug in the code above") |
| 209 | } |
| 210 | |
| 211 | // The templateDBName is empty, so we need to create the template database. |
| 212 | err = createAndInitDatabase(t, connParams, db, templateDBName, func(tplDb *sql.DB) error { |
| 213 | if err := migrations.Up(tplDb); err != nil { |
| 214 | return xerrors.Errorf("migrate template db: %w", err) |
| 215 | } |
| 216 | return nil |
| 217 | }) |
| 218 | if err != nil { |
| 219 | return xerrors.Errorf("create template database: %w", err) |
| 220 | } |
| 221 | |
| 222 | // Try to create the database again now that a template exists. |
| 223 | if _, err = db.Exec("CREATE DATABASE " + newDBName + " WITH TEMPLATE " + templateDBName); err != nil { |
| 224 | return xerrors.Errorf("create db with template after migrations: %w", err) |
| 225 | } |
| 226 | return nil |
| 227 | } |
| 228 | |
| 229 | func createAndInitDatabase(t TBSubset, connParams ConnectionParams, db *sql.DB, name string, initialize func(*sql.DB) error) error { |
| 230 | // We will use a tx to obtain a lock, so another test or process doesn't race with us. |
no test coverage detected