ソースを参照

Worked on database agnostic table creation for db migrations

Torkel Ödegaard 11 年 前
コミット
d8e5be5782

+ 4 - 0
conf/grafana.dev.ini

@@ -4,4 +4,8 @@ app_mode = development
 router_logging = false
 static_root_path = grafana/src
 
+[log]
+level = Trace
+
+
 

+ 11 - 13
pkg/models/account.go

@@ -12,19 +12,17 @@ var (
 
 // Directly mapped to db schema, Do not change field names lighly
 type Account struct {
-	Id              int64
-	Login           string `xorm:"UNIQUE NOT NULL"`
-	Email           string `xorm:"UNIQUE NOT NULL"`
-	Name            string
-	FullName        string
-	Password        string
-	IsAdmin         bool
-	Salt            string `xorm:"VARCHAR(10)"`
-	Company         string
-	NextDashboardId int
-	UsingAccountId  int64
-	Created         time.Time
-	Updated         time.Time
+	Id             int64
+	Login          string `xorm:"UNIQUE NOT NULL"`
+	Email          string `xorm:"UNIQUE NOT NULL"`
+	Name           string
+	Password       string
+	IsAdmin        bool
+	Salt           string `xorm:"VARCHAR(10)"`
+	Company        string
+	UsingAccountId int64
+	Created        time.Time
+	Updated        time.Time
 }
 
 // ---------------------

+ 42 - 47
pkg/services/sqlstore/migrations/builder.go

@@ -1,28 +1,5 @@
 package migrations
 
-import (
-	"fmt"
-	"strings"
-)
-
-const (
-	POSTGRES = "postgres"
-	SQLITE   = "sqlite3"
-	MYSQL    = "mysql"
-)
-
-type Migration interface {
-	Sql(dialect Dialect) string
-	Id() string
-	SetId(string)
-}
-
-type ColumnType string
-
-const (
-	DB_TYPE_STRING ColumnType = "String"
-)
-
 type MigrationBase struct {
 	id string
 }
@@ -65,10 +42,8 @@ func (m *RawSqlMigration) Mysql(sql string) *RawSqlMigration {
 
 type AddColumnMigration struct {
 	MigrationBase
-	tableName  string
-	columnName string
-	columnType ColumnType
-	length     int
+	tableName string
+	column    *Column
 }
 
 func (m *AddColumnMigration) Table(tableName string) *AddColumnMigration {
@@ -76,35 +51,23 @@ func (m *AddColumnMigration) Table(tableName string) *AddColumnMigration {
 	return m
 }
 
-func (m *AddColumnMigration) Length(length int) *AddColumnMigration {
-	m.length = length
-	return m
-}
-
-func (m *AddColumnMigration) Column(columnName string) *AddColumnMigration {
-	m.columnName = columnName
-	return m
-}
-
-func (m *AddColumnMigration) Type(columnType ColumnType) *AddColumnMigration {
-	m.columnType = columnType
+func (m *AddColumnMigration) Column(col *Column) *AddColumnMigration {
+	m.column = col
 	return m
 }
 
 func (m *AddColumnMigration) Sql(dialect Dialect) string {
-	return fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s %s", m.tableName, m.columnName, dialect.ToDBTypeSql(m.columnType, m.length))
+	return dialect.AddColumnSql(m.tableName, m.column)
 }
 
 type AddIndexMigration struct {
 	MigrationBase
 	tableName string
-	columns   string
-	indexName string
-	unique    string
+	index     Index
 }
 
 func (m *AddIndexMigration) Name(name string) *AddIndexMigration {
-	m.indexName = name
+	m.index.Name = name
 	return m
 }
 
@@ -114,15 +77,47 @@ func (m *AddIndexMigration) Table(tableName string) *AddIndexMigration {
 }
 
 func (m *AddIndexMigration) Unique() *AddIndexMigration {
-	m.unique = "UNIQUE"
+	m.index.Type = UniqueIndex
 	return m
 }
 
 func (m *AddIndexMigration) Columns(columns ...string) *AddIndexMigration {
-	m.columns = strings.Join(columns, ",")
+	m.index.Cols = columns
 	return m
 }
 
 func (m *AddIndexMigration) Sql(dialect Dialect) string {
-	return fmt.Sprintf("CREATE %s INDEX %s ON %s(%s)", m.unique, m.indexName, m.tableName, m.columns)
+	return dialect.CreateIndexSql(m.tableName, &m.index)
+}
+
+type AddTableMigration struct {
+	MigrationBase
+	table Table
+}
+
+func (m *AddTableMigration) Sql(d Dialect) string {
+	return d.CreateTableSql(&m.table)
+}
+
+func (m *AddTableMigration) Name(name string) *AddTableMigration {
+	m.table.Name = name
+	return m
+}
+
+func (m *AddTableMigration) WithColumns(columns ...*Column) *AddTableMigration {
+	for _, col := range columns {
+		m.table.Columns = append(m.table.Columns, col)
+		if col.IsPrimaryKey {
+			m.table.PrimaryKeys = append(m.table.PrimaryKeys, col.Name)
+		}
+	}
+	return m
+}
+
+func (m *AddTableMigration) WithColumn(col *Column) *AddTableMigration {
+	m.table.Columns = append(m.table.Columns, col)
+	if col.IsPrimaryKey {
+		m.table.PrimaryKeys = append(m.table.PrimaryKeys, col.Name)
+	}
+	return m
 }

+ 62 - 0
pkg/services/sqlstore/migrations/column.go

@@ -0,0 +1,62 @@
+package migrations
+
+// Notice
+// code based on parts from from https://github.com/go-xorm/core/blob/3e0fa232ab5c90996406c0cd7ae86ad0e5ecf85f/column.go
+
+type Column struct {
+	Name            string
+	Type            string
+	Length          int
+	Length2         int
+	Nullable        bool
+	IsPrimaryKey    bool
+	IsAutoIncrement bool
+	Default         string
+}
+
+func (col *Column) String(d Dialect) string {
+	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "
+
+	sql += d.SqlType(col) + " "
+
+	if col.IsPrimaryKey {
+		sql += "PRIMARY KEY "
+		if col.IsAutoIncrement {
+			sql += d.AutoIncrStr() + " "
+		}
+	}
+
+	if d.ShowCreateNull() {
+		if col.Nullable {
+			sql += "NULL "
+		} else {
+			sql += "NOT NULL "
+		}
+	}
+
+	if col.Default != "" {
+		sql += "DEFAULT " + col.Default + " "
+	}
+
+	return sql
+}
+
+func (col *Column) StringNoPk(d Dialect) string {
+	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "
+
+	sql += d.SqlType(col) + " "
+
+	if d.ShowCreateNull() {
+		if col.Nullable {
+			sql += "NULL "
+		} else {
+			sql += "NOT NULL "
+		}
+	}
+
+	if col.Default != "" {
+		sql += "DEFAULT " + col.Default + " "
+	}
+
+	return sql
+}

+ 71 - 26
pkg/services/sqlstore/migrations/dialect.go

@@ -1,52 +1,97 @@
 package migrations
 
-import "fmt"
+import (
+	"fmt"
+	"strings"
+)
 
 type Dialect interface {
 	DriverName() string
-	ToDBTypeSql(columnType ColumnType, length int) string
+	QuoteStr() string
+	Quote(string) string
+	AndStr() string
+	AutoIncrStr() string
+	OrStr() string
+	EqStr() string
+	ShowCreateNull() bool
+	SqlType(col *Column) string
+
+	CreateIndexSql(tableName string, index *Index) string
+	CreateTableSql(table *Table) string
+	AddColumnSql(tableName string, Col *Column) string
+
 	TableCheckSql(tableName string) (string, []interface{})
 }
 
-type Sqlite3 struct {
+type BaseDialect struct {
+	dialect    Dialect
+	driverName string
 }
 
-type Mysql struct {
+func (d *BaseDialect) DriverName() string {
+	return d.driverName
 }
 
-func (db *Sqlite3) DriverName() string {
-	return SQLITE
+func (b *BaseDialect) ShowCreateNull() bool {
+	return true
 }
 
-func (db *Mysql) DriverName() string {
-	return MYSQL
+func (b *BaseDialect) AndStr() string {
+	return "AND"
 }
 
-func (db *Sqlite3) ToDBTypeSql(columnType ColumnType, length int) string {
-	switch columnType {
-	case DB_TYPE_STRING:
-		return "TEXT"
-	}
+func (b *BaseDialect) OrStr() string {
+	return "OR"
+}
 
-	panic("Unsupported db type")
+func (b *BaseDialect) EqStr() string {
+	return "="
 }
 
-func (db *Mysql) ToDBTypeSql(columnType ColumnType, length int) string {
-	switch columnType {
-	case DB_TYPE_STRING:
-		return fmt.Sprintf("NVARCHAR(%d)", length)
+func (b *BaseDialect) CreateTableSql(table *Table) string {
+	var sql string
+	sql = "CREATE TABLE IF NOT EXISTS "
+	sql += b.dialect.Quote(table.Name) + " (\n"
+
+	pkList := table.PrimaryKeys
+
+	for _, col := range table.Columns {
+		if col.IsPrimaryKey && len(pkList) == 1 {
+			sql += col.String(b.dialect)
+		} else {
+			sql += col.StringNoPk(b.dialect)
+		}
+		sql = strings.TrimSpace(sql)
+		sql += "\n, "
+	}
+
+	if len(pkList) > 1 {
+		sql += "PRIMARY KEY ( "
+		sql += b.dialect.Quote(strings.Join(pkList, b.dialect.Quote(",")))
+		sql += " ), "
 	}
 
-	panic("Unsupported db type")
+	sql = sql[:len(sql)-2] + ")"
+	sql += ";"
+	return sql
 }
 
-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 *BaseDialect) AddColumnSql(tableName string, col *Column) string {
+	return fmt.Sprintf("alter table %s ADD COLUMN %s", tableName, col.StringNoPk(db.dialect))
 }
 
-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
+func (db *BaseDialect) CreateIndexSql(tableName string, index *Index) string {
+	quote := db.dialect.Quote
+	var unique string
+	var idxName string
+	if index.Type == UniqueIndex {
+		unique = " UNIQUE"
+		idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
+	} else {
+		idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
+	}
+
+	return fmt.Sprintf("CREATE%s INDEX %v ON %v (%v);", unique,
+		quote(idxName), quote(tableName),
+		quote(strings.Join(index.Cols, quote(","))))
 }

+ 31 - 52
pkg/services/sqlstore/migrations/migrations.go

@@ -2,61 +2,40 @@ package migrations
 
 import "time"
 
-// Id              int64
-// Login           string `xorm:"UNIQUE NOT NULL"`
-// Email           string `xorm:"UNIQUE NOT NULL"`
-// Name            string
-// FullName        string
-// Password        string
-// IsAdmin         bool
-// Salt            string `xorm:"VARCHAR(10)"`
-// Company         string
-// NextDashboardId int
-// UsingAccountId  int64
-// Created         time.Time
-// Updated         time.Time
-
 func AddMigrations(mg *Migrator) {
 
-	// TABLE Account
-	// -------------------------------
-	mg.AddMigration("create account table", new(RawSqlMigration).
-		Sqlite(`
-		  CREATE TABLE account (
-		  	id                INTEGER PRIMARY KEY AUTOINCREMENT,
-		  	login             TEXT NOT NULL,
-		  	email             TEXT NOT NULL,
-		  	name						  TEXT NULL,
-		  	password		 		  TEXT NULL,
-		  	salt							TEXT NULL,
-		  	company						TEXT NULL,
-		  	using_account_id  INTEGER NULL,
-		  	is_admin					INTEGER NOT NULL,
-		  	created           INTEGER NOT NULL,
-		  	updated           INTEGER NOT NULL
-			)
-		`).
-		Mysql(`
-		  CREATE TABLE account (
-		  	id								BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY (id),
-		  	login							VARCHAR(255) NOT NULL,
-		  	email							VARCHAR(255) NOT NULL,
-		  	name							VARCHAR(255) NULL,
-		    password					VARCHAR(50) NULL,
-				salt    					VARCHAR(50) NULL,
-				company      			VARCHAR(255) NULL,
-				using_account_id	BIGINT NULL,
-				is_admin	        BOOL NOT NULL,
-				created	          DATETIME NOT NULL,
-				update	          DATETIME NOT NULL
-		  )
-		`))
-	// ------------------------------
-	mg.AddMigration("add index UIX_account.login", new(AddIndexMigration).
+	//-------  migration_log table -------------------
+	mg.AddMigration("create migration_log table", new(AddTableMigration).
+		Name("migration_log").WithColumns(
+		&Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
+		&Column{Name: "migration_id", Type: DB_NVarchar, Length: 255},
+		&Column{Name: "sql", Type: DB_Text},
+		&Column{Name: "success", Type: DB_Bool},
+		&Column{Name: "error", Type: DB_Text},
+		&Column{Name: "timestamp", Type: DB_DateTime},
+	))
+
+	//-------  account table -------------------
+	mg.AddMigration("create account table", new(AddTableMigration).
+		Name("account").WithColumns(
+		&Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
+		&Column{Name: "login", Type: DB_NVarchar, Length: 255},
+		&Column{Name: "email", Type: DB_NVarchar, Length: 255},
+		&Column{Name: "name", Type: DB_NVarchar, Length: 255},
+		&Column{Name: "password", Type: DB_NVarchar, Length: 50},
+		&Column{Name: "salt", Type: DB_NVarchar, Length: 50},
+		&Column{Name: "company", Type: DB_NVarchar, Length: 255},
+		&Column{Name: "using_account_id", Type: DB_BigInt},
+		&Column{Name: "is_admin", Type: DB_Bool},
+		&Column{Name: "created", Type: DB_DateTime},
+		&Column{Name: "updated", Type: DB_DateTime},
+	))
+
+	//-------  account table indexes ------------------
+	mg.AddMigration("add unique index UIX_account.login", new(AddIndexMigration).
 		Name("UIX_account_login").Table("account").Columns("login"))
-	// ------------------------------
-	// mg.AddMigration("add column", new(AddColumnMigration).
-	// 	Table("account").Column("name").Type(DB_TYPE_STRING).Length(255))
+	mg.AddMigration("add unique index UIX_account.email", new(AddIndexMigration).
+		Name("UIX_account_email").Table("account").Columns("email"))
 }
 
 type MigrationLog struct {

+ 1 - 1
pkg/services/sqlstore/migrations/migrations_test.go

@@ -35,7 +35,7 @@ func TestMigrations(t *testing.T) {
 	log.NewLogger(0, "console", `{"level": 0}`)
 
 	testDBs := [][]string{
-		//[]string{"mysql", "grafana:password@tcp(localhost:3306)/grafana_tests?charset=utf8"},
+		[]string{"mysql", "grafana:password@tcp(localhost:3306)/grafana_tests?charset=utf8"},
 		[]string{"sqlite3", ":memory:"},
 	}
 

+ 11 - 11
pkg/services/sqlstore/migrations/migrator.go

@@ -23,9 +23,9 @@ func NewMigrator(engine *xorm.Engine) *Migrator {
 
 	switch mg.x.DriverName() {
 	case MYSQL:
-		mg.dialect = new(Mysql)
+		mg.dialect = NewMysqlDialect()
 	case SQLITE:
-		mg.dialect = new(Sqlite3)
+		mg.dialect = NewSqlite3Dialect()
 	}
 
 	return mg
@@ -37,20 +37,18 @@ func (mg *Migrator) AddMigration(id string, m Migration) {
 }
 
 func (mg *Migrator) GetMigrationLog() (map[string]MigrationLog, error) {
+	logMap := make(map[string]MigrationLog)
+	logItems := make([]MigrationLog, 0)
+
 	exists, err := mg.x.IsTableExist(new(MigrationLog))
 	if err != nil {
 		return nil, err
 	}
 
 	if !exists {
-		if err := mg.x.CreateTables(new(MigrationLog)); err != nil {
-			return nil, err
-		}
-		return nil, nil
+		return logMap, nil
 	}
 
-	logMap := make(map[string]MigrationLog)
-	logItems := make([]MigrationLog, 0)
 	if err = mg.x.Find(&logItems); err != nil {
 		return nil, err
 	}
@@ -66,7 +64,7 @@ func (mg *Migrator) GetMigrationLog() (map[string]MigrationLog, error) {
 }
 
 func (mg *Migrator) Start() error {
-	log.Info("Migrator::Start DB migration")
+	log.Info("Migrator::Starting DB migration")
 
 	logMap, err := mg.GetMigrationLog()
 	if err != nil {
@@ -76,13 +74,15 @@ func (mg *Migrator) Start() error {
 	for _, m := range mg.migrations {
 		_, exists := logMap[m.Id()]
 		if exists {
-			log.Info("Migrator:: Skipping migration: %v, Already executed", m.Id())
+			log.Debug("Migrator:: Skipping migration: %v, Already executed", m.Id())
 			continue
 		}
 
+		sql := m.Sql(mg.dialect)
+
 		record := MigrationLog{
 			MigrationId: m.Id(),
-			Sql:         m.Sql(mg.dialect),
+			Sql:         sql,
 			Timestamp:   time.Now(),
 		}
 

+ 0 - 78
pkg/services/sqlstore/migrations/migrator_test.go

@@ -1,78 +0,0 @@
-package migrations
-
-import (
-	"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")
-// 		}
-// 	}
-// }
-//
-// var indexTypes = []string{"Unknown", "", "UNIQUE"}
-//
-
-func TestMigrator(t *testing.T) {
-
-	Convey("Migrator", t, func() {
-		x, err := xorm.NewEngine(SQLITE, ":memory:")
-		So(err, ShouldBeNil)
-
-		mg := NewMigrator(x)
-
-		Convey("Given one migration", func() {
-			mg.AddMigration("test migration", new(RawSqlMigration).
-				Sqlite(`
-			    CREATE TABLE account (
-		       	id INTEGER PRIMARY KEY AUTOINCREMENT
-				  )`).
-				Mysql(`
-			   	CREATE TABLE account (
-						id BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY (id)
-					)`))
-
-			err := mg.Start()
-			So(err, ShouldBeNil)
-
-			log, err := mg.GetMigrationLog()
-			So(err, ShouldBeNil)
-			So(len(log), ShouldEqual, 1)
-		})
-
-		// So(err, ShouldBeNil)
-		//
-		// So(len(tables), ShouldEqual, 2)
-		// fmt.Printf("\nDB Schema after migration: table count: %v\n", len(tables))
-		//
-		// for _, table := range tables {
-		// 	fmt.Printf("\nTable: %v \n", table.Name)
-		// 	for _, column := range table.Columns() {
-		// 		fmt.Printf("\t %v \n", column.String(x.Dialect()))
-		// 	}
-		//
-		// 	if len(table.Indexes) > 0 {
-		// 		fmt.Printf("\n\tIndexes:\n")
-		// 		for _, index := range table.Indexes {
-		// 			fmt.Printf("\t %v (%v) %v \n", index.Name, strings.Join(index.Cols, ","), indexTypes[index.Type])
-		// 		}
-		// 	}
-		// }
-	})
-}

+ 87 - 0
pkg/services/sqlstore/migrations/mysql_dialect.go

@@ -0,0 +1,87 @@
+package migrations
+
+import (
+	"fmt"
+	"strconv"
+)
+
+type Mysql struct {
+	BaseDialect
+}
+
+func NewMysqlDialect() *Mysql {
+	d := Mysql{}
+	d.BaseDialect.dialect = &d
+	d.BaseDialect.driverName = MYSQL
+	return &d
+}
+
+func (db *Mysql) Quote(name string) string {
+	return "`" + name + "`"
+}
+
+func (db *Mysql) QuoteStr() string {
+	return "`"
+}
+
+func (db *Mysql) AutoIncrStr() string {
+	return "AUTO_INCREMENT"
+}
+
+func (db *Mysql) SqlType(c *Column) string {
+	var res string
+	switch c.Type {
+	case DB_Bool:
+		res = DB_TinyInt
+		c.Length = 1
+	case DB_Serial:
+		c.IsAutoIncrement = true
+		c.IsPrimaryKey = true
+		c.Nullable = false
+		res = DB_Int
+	case DB_BigSerial:
+		c.IsAutoIncrement = true
+		c.IsPrimaryKey = true
+		c.Nullable = false
+		res = DB_BigInt
+	case DB_Bytea:
+		res = DB_Blob
+	case DB_TimeStampz:
+		res = DB_Char
+		c.Length = 64
+	case DB_NVarchar:
+		res = DB_Varchar
+	default:
+		res = c.Type
+	}
+
+	var hasLen1 bool = (c.Length > 0)
+	var hasLen2 bool = (c.Length2 > 0)
+
+	if res == DB_BigInt && !hasLen1 && !hasLen2 {
+		c.Length = 20
+		hasLen1 = true
+	}
+
+	if hasLen2 {
+		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
+	} else if hasLen1 {
+		res += "(" + strconv.Itoa(c.Length) + ")"
+	}
+	return res
+}
+
+func (db *Mysql) ToDBTypeSql(columnType ColumnType, length int) string {
+	switch columnType {
+	case DB_TYPE_STRING:
+		return fmt.Sprintf("NVARCHAR(%d)", length)
+	}
+
+	panic("Unsupported db type")
+}
+
+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
+}

+ 57 - 0
pkg/services/sqlstore/migrations/sqlite_dialect.go

@@ -0,0 +1,57 @@
+package migrations
+
+import "github.com/go-xorm/core"
+
+type Sqlite3 struct {
+	BaseDialect
+}
+
+func NewSqlite3Dialect() *Sqlite3 {
+	d := Sqlite3{}
+	d.BaseDialect.dialect = &d
+	d.BaseDialect.driverName = SQLITE
+	return &d
+}
+
+func (db *Sqlite3) Quote(name string) string {
+	return "`" + name + "`"
+}
+
+func (db *Sqlite3) QuoteStr() string {
+	return "`"
+}
+
+func (db *Sqlite3) AutoIncrStr() string {
+	return "AUTOINCREMENT"
+}
+
+func (db *Sqlite3) SqlType(c *Column) string {
+	switch c.Type {
+	case DB_Date, DB_DateTime, DB_TimeStamp, DB_Time:
+		return DB_DateTime
+	case DB_TimeStampz:
+		return DB_Text
+	case DB_Char, DB_Varchar, DB_NVarchar, DB_TinyText, DB_Text, DB_MediumText, DB_LongText:
+		return core.Text
+	case DB_Bit, DB_TinyInt, DB_SmallInt, DB_MediumInt, DB_Int, DB_Integer, DB_BigInt, DB_Bool:
+		return DB_Integer
+	case DB_Float, DB_Double, DB_Real:
+		return DB_Real
+	case DB_Decimal, DB_Numeric:
+		return DB_Numeric
+	case DB_TinyBlob, DB_Blob, DB_MediumBlob, DB_LongBlob, DB_Bytea, DB_Binary, DB_VarBinary:
+		return DB_Blob
+	case DB_Serial, DB_BigSerial:
+		c.IsPrimaryKey = true
+		c.IsAutoIncrement = true
+		c.Nullable = false
+		return core.Integer
+	default:
+		return c.Type
+	}
+}
+
+func (db *Sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{tableName}
+	return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args
+}

+ 86 - 0
pkg/services/sqlstore/migrations/types.go

@@ -0,0 +1,86 @@
+package migrations
+
+const (
+	POSTGRES = "postgres"
+	SQLITE   = "sqlite3"
+	MYSQL    = "mysql"
+)
+
+type Migration interface {
+	Sql(dialect Dialect) string
+	Id() string
+	SetId(string)
+}
+
+type SQLType string
+
+type ColumnType string
+
+const (
+	DB_TYPE_STRING ColumnType = "String"
+)
+
+type Table struct {
+	Name        string
+	Columns     []*Column
+	PrimaryKeys []string
+}
+
+const (
+	IndexType = iota + 1
+	UniqueIndex
+)
+
+type Index struct {
+	Name string
+	Type int
+	Cols []string
+}
+
+var (
+	DB_Bit       = "BIT"
+	DB_TinyInt   = "TINYINT"
+	DB_SmallInt  = "SMALLINT"
+	DB_MediumInt = "MEDIUMINT"
+	DB_Int       = "INT"
+	DB_Integer   = "INTEGER"
+	DB_BigInt    = "BIGINT"
+
+	DB_Enum = "ENUM"
+	DB_Set  = "SET"
+
+	DB_Char       = "CHAR"
+	DB_Varchar    = "VARCHAR"
+	DB_NVarchar   = "NVARCHAR"
+	DB_TinyText   = "TINYTEXT"
+	DB_Text       = "TEXT"
+	DB_MediumText = "MEDIUMTEXT"
+	DB_LongText   = "LONGTEXT"
+	DB_Uuid       = "UUID"
+
+	DB_Date       = "DATE"
+	DB_DateTime   = "DATETIME"
+	DB_Time       = "TIME"
+	DB_TimeStamp  = "TIMESTAMP"
+	DB_TimeStampz = "TIMESTAMPZ"
+
+	DB_Decimal = "DECIMAL"
+	DB_Numeric = "NUMERIC"
+
+	DB_Real   = "REAL"
+	DB_Float  = "FLOAT"
+	DB_Double = "DOUBLE"
+
+	DB_Binary     = "BINARY"
+	DB_VarBinary  = "VARBINARY"
+	DB_TinyBlob   = "TINYBLOB"
+	DB_Blob       = "BLOB"
+	DB_MediumBlob = "MEDIUMBLOB"
+	DB_LongBlob   = "LONGBLOB"
+	DB_Bytea      = "BYTEA"
+
+	DB_Bool = "BOOL"
+
+	DB_Serial    = "SERIAL"
+	DB_BigSerial = "BIGSERIAL"
+)

+ 9 - 1
pkg/services/sqlstore/sqlstore.go

@@ -9,6 +9,7 @@ import (
 	"github.com/torkelo/grafana-pro/pkg/bus"
 	"github.com/torkelo/grafana-pro/pkg/log"
 	m "github.com/torkelo/grafana-pro/pkg/models"
+	"github.com/torkelo/grafana-pro/pkg/services/sqlstore/migrations"
 	"github.com/torkelo/grafana-pro/pkg/setting"
 	"github.com/torkelo/grafana-pro/pkg/util"
 
@@ -34,7 +35,7 @@ var (
 func init() {
 	tables = make([]interface{}, 0)
 
-	tables = append(tables, new(m.Account), new(m.Dashboard),
+	tables = append(tables, new(m.Dashboard),
 		new(m.Collaborator), new(m.DataSource), new(DashboardTag),
 		new(m.Token))
 }
@@ -77,6 +78,13 @@ func NewEngine() {
 func SetEngine(engine *xorm.Engine, enableLog bool) (err error) {
 	x = engine
 
+	migrator := migrations.NewMigrator(x)
+	migrations.AddMigrations(migrator)
+
+	if err := migrator.Start(); err != nil {
+		return fmt.Errorf("Sqlstore::Migration failed err: %v\n", err)
+	}
+
 	if err := x.Sync2(tables...); err != nil {
 		return fmt.Errorf("sync database struct error: %v\n", err)
 	}