diff --git a/pkg/database/migrate/sqlite.go b/pkg/database/migrate/sqlite.go index 20330ac36..cbd8c7767 100644 --- a/pkg/database/migrate/sqlite.go +++ b/pkg/database/migrate/sqlite.go @@ -16,15 +16,15 @@ func SQLite(tx *sql.Tx) Operation { } func (s *SQLiteDriver) Exec(query string, args ...interface{}) (sql.Result, error) { - return s.Tx.Exec(query, args) + return s.Tx.Exec(query, args...) } func (s *SQLiteDriver) Query(query string, args ...interface{}) (*sql.Rows, error) { - return s.Tx.Query(query, args) + return s.Tx.Query(query, args...) } func (s *SQLiteDriver) QueryRow(query string, args ...interface{}) *sql.Row { - return s.Tx.QueryRow(query, args) + return s.Tx.QueryRow(query, args...) } func (s *SQLiteDriver) CreateTable(tableName string, args []string) (sql.Result, error) { @@ -241,14 +241,14 @@ func (s *SQLiteDriver) getDDLFromIndex(tableName string) ([]string, error) { for rows.Next() { var sql string if err := rows.Scan(&sql); err != nil { + // This error came from autoindex, since its sql value is null, + // we want to continue. if strings.Contains(err.Error(), "Scan pair: -> *string") { continue } return sqls, err } - if len(sql) > 0 { - sqls = append(sqls, sql) - } + sqls = append(sqls, sql) } if err := rows.Err(); err != nil { diff --git a/pkg/database/migrate/sqlite_test.go b/pkg/database/migrate/sqlite_test.go index af81588f7..651ecbbcc 100644 --- a/pkg/database/migrate/sqlite_test.go +++ b/pkg/database/migrate/sqlite_test.go @@ -117,7 +117,72 @@ func (r *revision4) Revision() int64 { return 4 } -// ---------- +// ---------- end of revision 4 + +// ---------- revision 5 + +type revision5 struct{} + +func (r *revision5) Up(op Operation) error { + _, err := op.Exec(`CREATE INDEX samples_url_name_ix ON samples (url, name)`) + return err +} + +func (r *revision5) Down(op Operation) error { + _, err := op.Exec(`DROP INDEX samples_url_name_ix`) + return err +} + +func (r *revision5) Revision() int64 { + return 5 +} + +// ---------- end of revision 5 + +// ---------- revision 6 +type revision6 struct{} + +func (r *revision6) Up(op Operation) error { + _, err := op.RenameColumns("samples", map[string]string{ + "url": "host", + }) + return err +} + +func (r *revision6) Down(op Operation) error { + _, err := op.RenameColumns("samples", map[string]string{ + "host": "url", + }) + return err +} + +func (r *revision6) Revision() int64 { + return 6 +} + +// ---------- end of revision 6 + +// ---------- revision 7 +type revision7 struct{} + +func (r *revision7) Up(op Operation) error { + _, err := op.DropColumns("samples", []string{"host", "num"}) + return err +} + +func (r *revision7) Down(op Operation) error { + if _, err := op.AddColumn("samples", "host VARCHAR(255)"); err != nil { + return err + } + _, err := op.AddColumn("samples", "num INSTEGER") + return err +} + +func (r *revision7) Revision() int64 { + return 7 +} + +// ---------- end of revision 7 var db *sql.DB @@ -305,6 +370,66 @@ func TestMigrateExistingTable(t *testing.T) { } } +type sqliteMaster struct { + Sql interface{} `meddler:"sql"` +} + +func TestIndexOperations(t *testing.T) { + defer tearDown() + if err := setUp(); err != nil { + t.Fatalf("Error preparing database: %q", err) + } + + Driver = SQLite + + mgr := New(db) + + // Migrate, create index + if err := mgr.Add(&revision1{}, &revision3{}, &revision5{}).Migrate(); err != nil { + t.Errorf("Can not migrate: %q", err) + } + + var esquel []*sqliteMaster + // Query sqlite_master, check if index is exists. + query := `SELECT sql FROM sqlite_master WHERE type='index' and tbl_name='samples'` + if err := meddler.QueryAll(db, &esquel, query); err != nil { + t.Errorf("Can not find index: %q", err) + } + + indexStatement := `CREATE INDEX samples_url_name_ix ON samples (url, name)` + if string(esquel[1].Sql.([]byte)) != indexStatement { + t.Errorf("Can not find index") + } + + // Migrate, rename indexed columns + if err := mgr.Add(&revision6{}).Migrate(); err != nil { + t.Errorf("Can not migrate: %q", err) + } + + var esquel1 []*sqliteMaster + if err := meddler.QueryAll(db, &esquel1, query); err != nil { + t.Errorf("Can not find index: %q", err) + } + + indexStatement = `CREATE INDEX samples_host_name_ix ON samples (host, name)` + if string(esquel1[1].Sql.([]byte)) != indexStatement { + t.Errorf("Can not find index, got: %s", esquel[0]) + } + + if err := mgr.Add(&revision7{}).Migrate(); err != nil { + t.Errorf("Can not migrate: %q", err) + } + + var esquel2 []*sqliteMaster + if err := meddler.QueryAll(db, &esquel2, query); err != nil { + t.Errorf("Can not find index: %q", err) + } + + if len(esquel2) != 1 { + t.Errorf("Expect row length equal to %d, got %d", 1, len(esquel2)) + } +} + func setUp() error { var err error db, err = sql.Open("sqlite3", "migration_tests.sqlite") diff --git a/pkg/database/migrate/util.go b/pkg/database/migrate/util.go index a0f6bfb59..d2001a071 100644 --- a/pkg/database/migrate/util.go +++ b/pkg/database/migrate/util.go @@ -6,12 +6,12 @@ import ( ) func fetchColumns(sql string) ([]string, error) { - if !strings.HasPrefix(sql, "CREATE TABLE ") { + if !strings.HasPrefix(sql, "CREATE ") { return []string{}, fmt.Errorf("Sql input is not a DDL statement.") } parenIdx := strings.Index(sql, "(") - return strings.Split(sql[parenIdx+1:len(sql)-1], ","), nil + return strings.Split(sql[parenIdx+1:strings.LastIndex(sql, ")")], ","), nil } func selectName(columns []string) []string {