Preliminary MySQL support. Barely tested.
Requirements: MySQL/MariaDB need to be configured with this settings: innodb_file_format = Barracuda innodb_file_per_table = On innodb_large_prefix = On to support key prefix length up to 3042 bytes. MySQL/MariaDB DSN will need this parameter: parseTime=true as per [1] The migration system itself mostly inspired by Rails (ActiveRecord), but it still rough at the edges. Could use some inputs. Next Todo: more testing! [1] https://github.com/go-sql-driver/mysql#parsetime
This commit is contained in:
parent
5903eb8f04
commit
7cf4f2eb89
8 changed files with 96 additions and 35 deletions
|
@ -51,7 +51,9 @@ func Init(name, datasource string) error {
|
|||
}
|
||||
|
||||
migration := migrate.New(db)
|
||||
migration.All().Migrate()
|
||||
if err := migration.All().Migrate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ func (r *rev1st) Up(mg *MigrationDriver) error {
|
|||
|
||||
if _, err := mg.CreateTable("repos", []string{
|
||||
t.Integer("id", PRIMARYKEY, AUTOINCREMENT),
|
||||
t.Varchar("slug", 1024, UNIQUE),
|
||||
t.String("slug", UNIQUE),
|
||||
t.String("host"),
|
||||
t.String("owner"),
|
||||
t.String("name"),
|
||||
|
@ -113,7 +113,7 @@ func (r *rev1st) Up(mg *MigrationDriver) error {
|
|||
}
|
||||
|
||||
_, err := mg.CreateTable("settings", []string{
|
||||
t.Integer("id", PRIMARYKEY),
|
||||
t.Integer("id", PRIMARYKEY, AUTOINCREMENT),
|
||||
t.String("github_key"),
|
||||
t.String("github_secret"),
|
||||
t.String("bitbucket_key"),
|
||||
|
|
|
@ -13,11 +13,11 @@ func (r *rev2nd) Up(mg *MigrationDriver) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if _, err := mg.AddIndex("members", []string{"team_id"}, ""); err != nil {
|
||||
if _, err := mg.AddIndex("members", []string{"team_id"}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := mg.AddIndex("members", []string{"user_id"}, ""); err != nil {
|
||||
if _, err := mg.AddIndex("members", []string{"user_id"}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -25,27 +25,27 @@ func (r *rev2nd) Up(mg *MigrationDriver) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if _, err := mg.AddIndex("commits", []string{"repo_id"}, ""); err != nil {
|
||||
if _, err := mg.AddIndex("commits", []string{"repo_id"}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := mg.AddIndex("commits", []string{"repo_id", "branch"}, ""); err != nil {
|
||||
if _, err := mg.AddIndex("commits", []string{"repo_id", "branch"}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := mg.AddIndex("repos", []string{"team_id"}, ""); err != nil {
|
||||
if _, err := mg.AddIndex("repos", []string{"team_id"}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := mg.AddIndex("repos", []string{"user_id"}, ""); err != nil {
|
||||
if _, err := mg.AddIndex("repos", []string{"user_id"}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := mg.AddIndex("builds", []string{"commit_id"}, ""); err != nil {
|
||||
if _, err := mg.AddIndex("builds", []string{"commit_id"}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := mg.AddIndex("builds", []string{"commit_id", "slug"}, "")
|
||||
_, err := mg.AddIndex("builds", []string{"commit_id", "slug"})
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ type Operation interface {
|
|||
|
||||
RenameColumns(tableName string, columnChanges map[string]string) (sql.Result, error)
|
||||
|
||||
AddIndex(tableName string, columns []string, flag string) (sql.Result, error)
|
||||
AddIndex(tableName string, columns []string, flags ...string) (sql.Result, error)
|
||||
|
||||
DropIndex(tableName string, columns []string) (sql.Result, error)
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import (
|
|||
|
||||
const migrationTableStmt = `
|
||||
CREATE TABLE IF NOT EXISTS migration (
|
||||
revision NUMBER PRIMARY KEY
|
||||
revision BIGINT PRIMARY KEY
|
||||
)
|
||||
`
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@ package migrate
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type mysqlDriver struct {
|
||||
|
@ -13,41 +14,96 @@ func MySQL(tx *sql.Tx) *MigrationDriver {
|
|||
return &MigrationDriver{
|
||||
Tx: tx,
|
||||
Operation: &mysqlDriver{Tx: tx},
|
||||
T: &columnType{
|
||||
AttrMap: map[int]string{AUTOINCREMENT: "AUTO_INCREMENT"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mysqlDriver) CreateTable(tableName string, args []string) (sql.Result, error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
return m.Tx.Exec(fmt.Sprintf("CREATE TABLE %s (%s) ROW_FORMAT=DYNAMIC", tableName, strings.Join(args, ", ")))
|
||||
}
|
||||
|
||||
func (m *mysqlDriver) RenameTable(tableName, newName string) (sql.Result, error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
return m.Tx.Exec(fmt.Sprintf("ALTER TABLE %s RENAME TO %s", tableName, newName))
|
||||
}
|
||||
|
||||
func (m *mysqlDriver) DropTable(tableName string) (sql.Result, error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
return m.Tx.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", tableName))
|
||||
}
|
||||
|
||||
func (m *mysqlDriver) AddColumn(tableName, columnSpec string) (sql.Result, error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
return m.Tx.Exec(fmt.Sprintf("ALTER TABLE %s ADD COLUMN (%s)", tableName, columnSpec))
|
||||
}
|
||||
|
||||
func (m *mysqlDriver) ChangeColumn(tableName, columnName, newSpecs string) (sql.Result, error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
return m.Tx.Exec(fmt.Sprintf("ALTER TABLE %s MODIFY %s %s", tableName, columnName, newSpecs))
|
||||
}
|
||||
|
||||
func (m *mysqlDriver) DropColumns(tableName string, columnsToDrop []string) (sql.Result, error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
for k, v := range columnsToDrop {
|
||||
columnsToDrop[k] = fmt.Sprintf("DROP %s", v)
|
||||
}
|
||||
return m.Tx.Exec(fmt.Sprintf("ALTER TABLE %s %s", tableName, strings.Join(columnsToDrop, ", ")))
|
||||
}
|
||||
|
||||
func (m *mysqlDriver) RenameColumns(tableName string, columnChanges map[string]string) (sql.Result, error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
var columns []string
|
||||
|
||||
tableSQL, err := m.getTableDefinition(tableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
columns, err = fetchColumns(tableSQL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var colspec []string
|
||||
for k, v := range columnChanges {
|
||||
for _, col := range columns {
|
||||
col = strings.Trim(col, " \n")
|
||||
cols := strings.SplitN(col, " ", 2)
|
||||
if quote(k) == cols[0] {
|
||||
colspec = append(colspec, fmt.Sprintf("CHANGE %s %s %s", k, v, cols[1]))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m.Tx.Exec(fmt.Sprintf("ALTER TABLE %s %s", tableName, strings.Join(colspec, ", ")))
|
||||
}
|
||||
|
||||
func (m *mysqlDriver) AddIndex(tableName string, columns []string, flag string) (sql.Result, error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
func (m *mysqlDriver) AddIndex(tableName string, columns []string, flags ...string) (sql.Result, error) {
|
||||
flag := ""
|
||||
if len(flags) > 0 {
|
||||
switch strings.ToUpper(flags[0]) {
|
||||
case "UNIQUE":
|
||||
fallthrough
|
||||
case "FULLTEXT":
|
||||
fallthrough
|
||||
case "SPATIAL":
|
||||
flag = flags[0]
|
||||
}
|
||||
}
|
||||
return m.Tx.Exec(fmt.Sprintf("CREATE %s INDEX %s ON %s (%s)", flag,
|
||||
indexName(tableName, columns), tableName, strings.Join(columns, ", ")))
|
||||
}
|
||||
|
||||
func (m *mysqlDriver) DropIndex(tableName string, columns []string) (sql.Result, error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
return m.Tx.Exec(fmt.Sprintf("DROP INDEX %s on %s", indexName(tableName, columns), tableName))
|
||||
}
|
||||
|
||||
func (m *mysqlDriver) getTableDefinition(tableName string) (string, error) {
|
||||
var name, def string
|
||||
st := fmt.Sprintf("SHOW CREATE TABLE %s", tableName)
|
||||
if err := m.Tx.QueryRow(st).Scan(&name, &def); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return def, nil
|
||||
}
|
||||
|
||||
func quote(name string) string {
|
||||
return fmt.Sprintf("`%s`", name)
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ func (p *postgresqlDriver) RenameColumns(tableName string, columnChanges map[str
|
|||
return nil, errors.New("not implemented yet")
|
||||
}
|
||||
|
||||
func (p *postgresqlDriver) AddIndex(tableName string, columns []string, flag string) (sql.Result, error) {
|
||||
func (p *postgresqlDriver) AddIndex(tableName string, columns []string, flags ...string) (sql.Result, error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
}
|
||||
|
||||
|
|
|
@ -19,19 +19,19 @@ func SQLite(tx *sql.Tx) *MigrationDriver {
|
|||
}
|
||||
|
||||
func (s *sqliteDriver) CreateTable(tableName string, args []string) (sql.Result, error) {
|
||||
return s.Tx.Exec(fmt.Sprintf("CREATE TABLE %s (%s);", tableName, strings.Join(args, ", ")))
|
||||
return s.Tx.Exec(fmt.Sprintf("CREATE TABLE %s (%s)", tableName, strings.Join(args, ", ")))
|
||||
}
|
||||
|
||||
func (s *sqliteDriver) RenameTable(tableName, newName string) (sql.Result, error) {
|
||||
return s.Tx.Exec(fmt.Sprintf("ALTER TABLE %s RENAME TO %s;", tableName, newName))
|
||||
return s.Tx.Exec(fmt.Sprintf("ALTER TABLE %s RENAME TO %s", tableName, newName))
|
||||
}
|
||||
|
||||
func (s *sqliteDriver) DropTable(tableName string) (sql.Result, error) {
|
||||
return s.Tx.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s;", tableName))
|
||||
return s.Tx.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", tableName))
|
||||
}
|
||||
|
||||
func (s *sqliteDriver) AddColumn(tableName, columnSpec string) (sql.Result, error) {
|
||||
return s.Tx.Exec(fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s;", tableName, columnSpec))
|
||||
return s.Tx.Exec(fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s", tableName, columnSpec))
|
||||
}
|
||||
|
||||
func (s *sqliteDriver) ChangeColumn(tableName, columnName, newType string) (sql.Result, error) {
|
||||
|
@ -173,7 +173,7 @@ func (s *sqliteDriver) DropColumns(tableName string, columnsToDrop []string) (sq
|
|||
}
|
||||
|
||||
// Move data from old table
|
||||
if result, err = s.Tx.Exec(fmt.Sprintf("INSERT INTO %s SELECT %s FROM %s;", tableName,
|
||||
if result, err = s.Tx.Exec(fmt.Sprintf("INSERT INTO %s SELECT %s FROM %s", tableName,
|
||||
strings.Join(selectName(preparedColumns), ", "), proxy)); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
@ -291,9 +291,12 @@ func (s *sqliteDriver) RenameColumns(tableName string, columnChanges map[string]
|
|||
return result, err
|
||||
}
|
||||
|
||||
func (s *sqliteDriver) AddIndex(tableName string, columns []string, flag string) (sql.Result, error) {
|
||||
if strings.ToUpper(flag) != "UNIQUE" {
|
||||
flag = ""
|
||||
func (s *sqliteDriver) AddIndex(tableName string, columns []string, flags ...string) (sql.Result, error) {
|
||||
flag := ""
|
||||
if len(flags) > 0 {
|
||||
if strings.ToUpper(flags[0]) == "UNIQUE" {
|
||||
flag = flags[0]
|
||||
}
|
||||
}
|
||||
return s.Tx.Exec(fmt.Sprintf("CREATE %s INDEX %s ON %s (%s)", flag, indexName(tableName, columns),
|
||||
tableName, strings.Join(columns, ", ")))
|
||||
|
@ -305,7 +308,7 @@ func (s *sqliteDriver) DropIndex(tableName string, columns []string) (sql.Result
|
|||
|
||||
func (s *sqliteDriver) getTableDefinition(tableName string) (string, error) {
|
||||
var sql string
|
||||
query := `SELECT sql FROM sqlite_master WHERE type='table' and name=?;`
|
||||
query := `SELECT sql FROM sqlite_master WHERE type='table' and name=?`
|
||||
err := s.Tx.QueryRow(query, tableName).Scan(&sql)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -316,7 +319,7 @@ func (s *sqliteDriver) getTableDefinition(tableName string) (string, error) {
|
|||
func (s *sqliteDriver) getIndexDefinition(tableName string) ([]string, error) {
|
||||
var sqls []string
|
||||
|
||||
query := `SELECT sql FROM sqlite_master WHERE type='index' and tbl_name=?;`
|
||||
query := `SELECT sql FROM sqlite_master WHERE type='index' and tbl_name=?`
|
||||
rows, err := s.Tx.Query(query, tableName)
|
||||
if err != nil {
|
||||
return sqls, err
|
||||
|
|
Loading…
Reference in a new issue