Просмотр исходного кода

More progress on db schema setup and migrations, tricky stuff

Torkel Ödegaard 11 лет назад
Родитель
Сommit
68a77c4051

+ 3 - 1
docker/blocks/mysql/fig

@@ -1,7 +1,9 @@
-db:
+mysql:
   image: mysql:latest
   environment:
     MYSQL_ROOT_PASSWORD: rootpass
     MYSQL_DATABASE: grafana
     MYSQL_USER: grafana
     MYSQL_PASSWORD: password
+  ports:
+    - "3306:3306"

+ 9 - 0
docker/blocks/mysql_tests/fig

@@ -0,0 +1,9 @@
+mysqltests:
+  image: mysql:latest
+  environment:
+    MYSQL_ROOT_PASSWORD: rootpass
+    MYSQL_DATABASE: grafana_tests
+    MYSQL_USER: grafana
+    MYSQL_PASSWORD: password
+  ports:
+    - "3306:3306"

+ 7 - 7
docker/fig.yml

@@ -1,10 +1,10 @@
-openldap:
-  image: cnry/openldap
+mysqltests:
+  image: mysql:latest
   environment:
-    SLAPD_PASSWORD: grafana
-    SLAPD_DOMAIN: grafana.org
+    MYSQL_ROOT_PASSWORD: rootpass
+    MYSQL_DATABASE: grafana_tests
+    MYSQL_USER: grafana
+    MYSQL_PASSWORD: password
   ports:
-    - "389:389"
-
-
+    - "3306:3306"
 

+ 2 - 4
pkg/api/account.go

@@ -8,9 +8,8 @@ import (
 
 func GetAccount(c *middleware.Context) {
 	query := m.GetAccountInfoQuery{Id: c.AccountId}
-	err := bus.Dispatch(&query)
 
-	if err != nil {
+	if err := bus.Dispatch(&query); err != nil {
 		c.JsonApiErr(500, "Failed to fetch collaboratos", err)
 		return
 	}
@@ -31,9 +30,8 @@ func UpdateAccount(c *middleware.Context, cmd m.UpdateAccountCommand) {
 
 func GetOtherAccounts(c *middleware.Context) {
 	query := m.GetOtherAccountsQuery{AccountId: c.AccountId}
-	err := bus.Dispatch(&query)
 
-	if err != nil {
+	if err := bus.Dispatch(&query); err != nil {
 		c.JsonApiErr(500, "Failed to get other accounts", err)
 		return
 	}

+ 23 - 0
pkg/services/sqlstore/migrations/builder.go

@@ -3,9 +3,27 @@ package migrations
 type migration struct {
 	desc        string
 	sqlite      string
+	mysql       string
 	verifyTable string
 }
 
+type columnType string
+
+const (
+	DB_TYPE_STRING columnType = "String"
+)
+
+func (m *migration) getSql(dbType string) string {
+	switch dbType {
+	case "mysql":
+		return m.mysql
+	case "sqlite3":
+		return m.sqlite
+	}
+
+	panic("db type not supported")
+}
+
 type migrationBuilder struct {
 	migration *migration
 }
@@ -15,6 +33,11 @@ func (b *migrationBuilder) sqlite(sql string) *migrationBuilder {
 	return b
 }
 
+func (b *migrationBuilder) mysql(sql string) *migrationBuilder {
+	b.migration.mysql = sql
+	return b
+}
+
 func (b *migrationBuilder) verifyTable(name string) *migrationBuilder {
 	b.migration.verifyTable = name
 	return b

+ 23 - 6
pkg/services/sqlstore/migrations/engine.go

@@ -4,8 +4,12 @@ import (
 	"errors"
 	"fmt"
 
-	"github.com/go-xorm/xorm"
 	"github.com/torkelo/grafana-pro/pkg/services/sqlstore/sqlsyntax"
+
+	_ "github.com/go-sql-driver/mysql"
+	"github.com/go-xorm/xorm"
+	_ "github.com/lib/pq"
+	_ "github.com/mattn/go-sqlite3"
 )
 
 var x *xorm.Engine
@@ -29,9 +33,18 @@ func getSchemaVersion() (int, error) {
 	return v.Version, err
 }
 
-func StartMigration(engine *xorm.Engine) error {
+func setEngineAndDialect(engine *xorm.Engine) {
 	x = engine
-	dialect = new(sqlsyntax.Sqlite3)
+	switch x.DriverName() {
+	case "mysql":
+		dialect = new(sqlsyntax.Mysql)
+	case "sqlite3":
+		dialect = new(sqlsyntax.Sqlite3)
+	}
+}
+
+func StartMigration(engine *xorm.Engine) error {
+	setEngineAndDialect(engine)
 
 	_, err := getSchemaVersion()
 	if err != nil {
@@ -49,16 +62,21 @@ func StartMigration(engine *xorm.Engine) error {
 
 func execMigration(m *migration) error {
 	err := inTransaction(func(sess *xorm.Session) error {
-		_, err := sess.Exec(m.sqlite)
+		_, err := sess.Exec(m.getSql(x.DriverName()))
 		if err != nil {
 			return err
 		}
 		return nil
 	})
+
 	if err != nil {
 		return err
 	}
-	// verify
+
+	return verifyMigration(m)
+}
+
+func verifyMigration(m *migration) error {
 	if m.verifyTable != "" {
 		sqlStr, args := dialect.TableCheckSql(m.verifyTable)
 		results, err := x.Query(sqlStr, args...)
@@ -66,7 +84,6 @@ func execMigration(m *migration) error {
 			return errors.New(fmt.Sprintf("Verify failed: table %v does not exist", m.verifyTable))
 		}
 	}
-
 	return nil
 }
 

+ 13 - 2
pkg/services/sqlstore/migrations/migrations.go

@@ -4,13 +4,24 @@ var migrationList []*migration
 
 func init() {
 	new(migrationBuilder).
+		// ------------------------------
 		desc("Create account table").
 		sqlite(`
 		  CREATE TABLE account (
-		  	id INTEGER PRIMARY KEY
+		  	id INTEGER PRIMARY KEY AUTOINCREMENT
 			)
 		`).
-		verifyTable("account")
+		mysql(`
+		  CREATE TABLE account (
+		  	id BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY (id)
+		  )
+		`).
+		verifyTable("account").add()
+	// ------------------------------
+	//		desc("Add name column to account table").
+	// table("account").addColumn("name").colType(DB_TYPE_STRING)
+	// sqlite("ALTER TABLE account ADD COLUMN name TEXT").
+	// mysql("ALTER TABLE account ADD COLUMN name NVARCHAR(255)").
 }
 
 type SchemaVersion struct {

+ 53 - 20
pkg/services/sqlstore/migrations/migrations_test.go

@@ -1,22 +1,55 @@
 package migrations
 
-// import (
-// 	"testing"
-//
-// 	"github.com/go-xorm/xorm"
-//
-// 	. "github.com/smartystreets/goconvey/convey"
-// )
-//
-// func TestMigrationsSqlite(t *testing.T) {
-//
-// 	Convey("Initial SQLite3 migration", t, func() {
-// 		x, err := xorm.NewEngine("sqlite3", ":memory:")
-// 		StartMigration(x)
-//
-// 		tables, err := x.DBMetas()
-// 		So(err, ShouldBeNil)
-//
-// 		So(len(tables), ShouldEqual, 1)
-// 	})
-// }
+import (
+	"fmt"
+	"testing"
+
+	"github.com/go-xorm/xorm"
+
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func cleanDB(x *xorm.Engine) {
+	tables, _ := x.DBMetas()
+	sess := x.NewSession()
+	defer sess.Close()
+
+	for _, table := range tables {
+		if _, err := sess.Exec("SET FOREIGN_KEY_CHECKS = 0"); err != nil {
+			panic("Failed to disable foreign key checks")
+		}
+		if _, err := sess.Exec("DROP TABLE " + table.Name); err != nil {
+			panic(fmt.Sprintf("Failed to delete table: %v, err: %v", table.Name, err))
+		}
+		if _, err := sess.Exec("SET FOREIGN_KEY_CHECKS = 1"); err != nil {
+			panic("Failed to disable foreign key checks")
+		}
+	}
+}
+
+func TestMigrationsSqlite(t *testing.T) {
+	testDBs := [][]string{
+		[]string{"sqlite3", ":memory:"},
+		[]string{"mysql", "grafana:password@tcp(localhost:3306)/grafana_tests?charset=utf8"},
+	}
+
+	for _, testDB := range testDBs {
+
+		Convey("Initial "+testDB[0]+" migration", t, func() {
+			x, err := xorm.NewEngine(testDB[0], testDB[1])
+			So(err, ShouldBeNil)
+
+			if testDB[0] == "mysql" {
+				cleanDB(x)
+			}
+
+			StartMigration(x)
+
+			tables, err := x.DBMetas()
+			So(err, ShouldBeNil)
+
+			So(len(tables), ShouldEqual, 2)
+		})
+
+	}
+}

+ 13 - 0
pkg/services/sqlstore/sqlsyntax/dialect.go

@@ -8,11 +8,24 @@ type Dialect interface {
 type Sqlite3 struct {
 }
 
+type Mysql struct {
+}
+
 func (db *Sqlite3) DBType() string {
 	return "sqlite3"
 }
 
+func (db *Mysql) DBType() string {
+	return "mysql"
+}
+
 func (db *Sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
 	args := []interface{}{tableName}
 	return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args
 }
+
+func (db *Mysql) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{"grafana", tableName}
+	sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
+	return sql, args
+}