mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Worked on database agnostic table creation for db migrations
This commit is contained in:
parent
7d70ffe201
commit
d8e5be5782
@ -4,4 +4,8 @@ app_mode = development
|
||||
router_logging = false
|
||||
static_root_path = grafana/src
|
||||
|
||||
[log]
|
||||
level = Trace
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
|
@ -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
pkg/services/sqlstore/migrations/column.go
Normal file
62
pkg/services/sqlstore/migrations/column.go
Normal file
@ -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
|
||||
}
|
@ -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(","))))
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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:"},
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
}
|
||||
|
||||
|
@ -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
pkg/services/sqlstore/migrations/mysql_dialect.go
Normal file
87
pkg/services/sqlstore/migrations/mysql_dialect.go
Normal file
@ -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
pkg/services/sqlstore/migrations/sqlite_dialect.go
Normal file
57
pkg/services/sqlstore/migrations/sqlite_dialect.go
Normal file
@ -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
pkg/services/sqlstore/migrations/types.go
Normal file
86
pkg/services/sqlstore/migrations/types.go
Normal file
@ -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,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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user