From d8e5be5782b1d1fd52f4a0a308049761794b7d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 19 Jan 2015 10:44:16 +0100 Subject: [PATCH] Worked on database agnostic table creation for db migrations --- conf/grafana.dev.ini | 4 + pkg/models/account.go | 24 +++-- pkg/services/sqlstore/migrations/builder.go | 89 ++++++++--------- pkg/services/sqlstore/migrations/column.go | 62 ++++++++++++ pkg/services/sqlstore/migrations/dialect.go | 99 ++++++++++++++----- .../sqlstore/migrations/migrations.go | 83 ++++++---------- .../sqlstore/migrations/migrations_test.go | 2 +- pkg/services/sqlstore/migrations/migrator.go | 22 ++--- .../sqlstore/migrations/migrator_test.go | 78 --------------- .../sqlstore/migrations/mysql_dialect.go | 87 ++++++++++++++++ .../sqlstore/migrations/sqlite_dialect.go | 57 +++++++++++ pkg/services/sqlstore/migrations/types.go | 86 ++++++++++++++++ pkg/services/sqlstore/sqlstore.go | 10 +- 13 files changed, 473 insertions(+), 230 deletions(-) create mode 100644 pkg/services/sqlstore/migrations/column.go delete mode 100644 pkg/services/sqlstore/migrations/migrator_test.go create mode 100644 pkg/services/sqlstore/migrations/mysql_dialect.go create mode 100644 pkg/services/sqlstore/migrations/sqlite_dialect.go create mode 100644 pkg/services/sqlstore/migrations/types.go diff --git a/conf/grafana.dev.ini b/conf/grafana.dev.ini index 1f4d08190f4..67cf8a6f008 100644 --- a/conf/grafana.dev.ini +++ b/conf/grafana.dev.ini @@ -4,4 +4,8 @@ app_mode = development router_logging = false static_root_path = grafana/src +[log] +level = Trace + + diff --git a/pkg/models/account.go b/pkg/models/account.go index 0f7dd876949..73be1a5b7ad 100644 --- a/pkg/models/account.go +++ b/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 } // --------------------- diff --git a/pkg/services/sqlstore/migrations/builder.go b/pkg/services/sqlstore/migrations/builder.go index 06fc7711b80..dd5a9ceadb6 100644 --- a/pkg/services/sqlstore/migrations/builder.go +++ b/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 } diff --git a/pkg/services/sqlstore/migrations/column.go b/pkg/services/sqlstore/migrations/column.go new file mode 100644 index 00000000000..2034d6a210d --- /dev/null +++ b/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 +} diff --git a/pkg/services/sqlstore/migrations/dialect.go b/pkg/services/sqlstore/migrations/dialect.go index 2a7c7c569e0..4dc0fe5e9f5 100644 --- a/pkg/services/sqlstore/migrations/dialect.go +++ b/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" +} + +func (b *BaseDialect) EqStr() string { + return "=" +} + +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, " } - panic("Unsupported db type") -} - -func (db *Mysql) ToDBTypeSql(columnType ColumnType, length int) string { - switch columnType { - case DB_TYPE_STRING: - return fmt.Sprintf("NVARCHAR(%d)", length) + 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(",")))) } diff --git a/pkg/services/sqlstore/migrations/migrations.go b/pkg/services/sqlstore/migrations/migrations.go index edd35ec52a0..c1bc2094fe5 100644 --- a/pkg/services/sqlstore/migrations/migrations.go +++ b/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 { diff --git a/pkg/services/sqlstore/migrations/migrations_test.go b/pkg/services/sqlstore/migrations/migrations_test.go index 112e1aeb94d..e485292f4a4 100644 --- a/pkg/services/sqlstore/migrations/migrations_test.go +++ b/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:"}, } diff --git a/pkg/services/sqlstore/migrations/migrator.go b/pkg/services/sqlstore/migrations/migrator.go index 8bfc003e7a4..bf7df3d7e70 100644 --- a/pkg/services/sqlstore/migrations/migrator.go +++ b/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(), } diff --git a/pkg/services/sqlstore/migrations/migrator_test.go b/pkg/services/sqlstore/migrations/migrator_test.go deleted file mode 100644 index e5b71250176..00000000000 --- a/pkg/services/sqlstore/migrations/migrator_test.go +++ /dev/null @@ -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]) - // } - // } - // } - }) -} diff --git a/pkg/services/sqlstore/migrations/mysql_dialect.go b/pkg/services/sqlstore/migrations/mysql_dialect.go new file mode 100644 index 00000000000..782dc59f3f1 --- /dev/null +++ b/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 +} diff --git a/pkg/services/sqlstore/migrations/sqlite_dialect.go b/pkg/services/sqlstore/migrations/sqlite_dialect.go new file mode 100644 index 00000000000..f5b2e5960d5 --- /dev/null +++ b/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 +} diff --git a/pkg/services/sqlstore/migrations/types.go b/pkg/services/sqlstore/migrations/types.go new file mode 100644 index 00000000000..d983f14a698 --- /dev/null +++ b/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" +) diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go index eae66e1975b..25f9a139ba9 100644 --- a/pkg/services/sqlstore/sqlstore.go +++ b/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) }