فهرست منبع

Began work on real sql schema definitions, and migration engine

Torkel Ödegaard 11 سال پیش
والد
کامیت
1f987c1903

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

@@ -0,0 +1,31 @@
+package migrations
+
+type migration struct {
+	desc        string
+	sqlite      string
+	verifyTable string
+}
+
+type migrationBuilder struct {
+	migration *migration
+}
+
+func (b *migrationBuilder) sqlite(sql string) *migrationBuilder {
+	b.migration.sqlite = sql
+	return b
+}
+
+func (b *migrationBuilder) verifyTable(name string) *migrationBuilder {
+	b.migration.verifyTable = name
+	return b
+}
+
+func (b *migrationBuilder) add() *migrationBuilder {
+	migrationList = append(migrationList, b.migration)
+	return b
+}
+
+func (b *migrationBuilder) desc(desc string) *migrationBuilder {
+	b.migration = &migration{desc: desc}
+	return b
+}

+ 95 - 0
pkg/services/sqlstore/migrations/engine.go

@@ -0,0 +1,95 @@
+package migrations
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/go-xorm/xorm"
+	"github.com/torkelo/grafana-pro/pkg/services/sqlstore/sqlsyntax"
+)
+
+var x *xorm.Engine
+var dialect sqlsyntax.Dialect
+
+func getSchemaVersion() (int, error) {
+	exists, err := x.IsTableExist(new(SchemaVersion))
+	if err != nil {
+		return 0, err
+	}
+
+	if !exists {
+		if err := x.CreateTables(new(SchemaVersion)); err != nil {
+			return 0, err
+		}
+		return 0, nil
+	}
+
+	v := SchemaVersion{}
+	_, err = x.Table("schema_version").Limit(1, 0).Desc("version").Get(&v)
+	return v.Version, err
+}
+
+func StartMigration(engine *xorm.Engine) error {
+	x = engine
+	dialect = new(sqlsyntax.Sqlite3)
+
+	_, err := getSchemaVersion()
+	if err != nil {
+		return err
+	}
+
+	for _, m := range migrationList {
+		if err := execMigration(m); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func execMigration(m *migration) error {
+	err := inTransaction(func(sess *xorm.Session) error {
+		_, err := sess.Exec(m.sqlite)
+		if err != nil {
+			return err
+		}
+		return nil
+	})
+	if err != nil {
+		return err
+	}
+	// verify
+	if m.verifyTable != "" {
+		sqlStr, args := dialect.TableCheckSql(m.verifyTable)
+		results, err := x.Query(sqlStr, args...)
+		if err != nil || len(results) == 0 {
+			return errors.New(fmt.Sprintf("Verify failed: table %v does not exist", m.verifyTable))
+		}
+	}
+
+	return nil
+}
+
+type dbTransactionFunc func(sess *xorm.Session) error
+
+func inTransaction(callback dbTransactionFunc) error {
+	var err error
+
+	sess := x.NewSession()
+	defer sess.Close()
+
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+
+	err = callback(sess)
+
+	if err != nil {
+		sess.Rollback()
+		return err
+	} else if err = sess.Commit(); err != nil {
+		return err
+	}
+
+	return nil
+}

+ 26 - 0
pkg/services/sqlstore/migrations/migrations.go

@@ -0,0 +1,26 @@
+package migrations
+
+var migrationList []*migration
+
+func init() {
+	new(migrationBuilder).
+		desc("Create account table").
+		sqlite(`
+		  CREATE TABLE account (
+		  	id INTEGER PRIMARY KEY
+			)
+		`).
+		verifyTable("account")
+}
+
+type SchemaVersion struct {
+	Version int
+}
+
+type SchemaLog struct {
+	Id      int64
+	Version int64
+	Desc    string
+	Info    string
+	Error   bool
+}

+ 22 - 0
pkg/services/sqlstore/migrations/migrations_test.go

@@ -0,0 +1,22 @@
+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)
+// 	})
+// }

+ 0 - 6
pkg/services/sqlstore/sqlstore.go

@@ -31,12 +31,6 @@ var (
 	UseSQLite3 bool
 )
 
-type DashboardTag struct {
-	Id          int64
-	DashboardId int64
-	Term        string
-}
-
 func init() {
 	tables = make([]interface{}, 0)
 

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

@@ -0,0 +1,18 @@
+package sqlsyntax
+
+type Dialect interface {
+	DBType() string
+	TableCheckSql(tableName string) (string, []interface{})
+}
+
+type Sqlite3 struct {
+}
+
+func (db *Sqlite3) DBType() string {
+	return "sqlite3"
+}
+
+func (db *Sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{tableName}
+	return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args
+}

+ 9 - 0
pkg/services/sqlstore/tables.go

@@ -0,0 +1,9 @@
+package sqlstore
+
+// extra tables not required by the core/outside model
+
+type DashboardTag struct {
+	Id          int64
+	DashboardId int64
+	Term        string
+}