From c7ed348ee85dc8f77ae3687c50402a5071aa9c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 16 Dec 2014 21:05:49 +0100 Subject: [PATCH] Lots of progress on command/query bus concept, in memory sql testing, datasource admin --- pkg/api/api_datasources.go | 1 + pkg/bus/bus.go | 2 - pkg/cmd/web.go | 7 +- pkg/models/account.go | 5 +- pkg/models/datasource.go | 4 +- pkg/stores/sqlstore/sqlstore.go | 112 ++++++++++++++------- pkg/stores/sqlstore/sqlstore_datasource.go | 37 ++++++- pkg/stores/sqlstore/sqlstore_test.go | 54 ++++++++++ 8 files changed, 170 insertions(+), 52 deletions(-) create mode 100644 pkg/stores/sqlstore/sqlstore_test.go diff --git a/pkg/api/api_datasources.go b/pkg/api/api_datasources.go index 45198cceab1..73b0658bc21 100644 --- a/pkg/api/api_datasources.go +++ b/pkg/api/api_datasources.go @@ -30,4 +30,5 @@ func AddDataSource(c *middleware.Context) { return } + c.Status(204) } diff --git a/pkg/bus/bus.go b/pkg/bus/bus.go index 90060dc6c15..c9ae790f254 100644 --- a/pkg/bus/bus.go +++ b/pkg/bus/bus.go @@ -2,7 +2,6 @@ package bus import ( "errors" - "fmt" "reflect" ) @@ -50,7 +49,6 @@ func (b *InProcBus) Dispatch(msg Msg) error { func (b *InProcBus) AddHandler(handler HandlerFunc) { handlerType := reflect.TypeOf(handler) queryTypeName := handlerType.In(0).Elem().Name() - fmt.Printf("QueryType %v\n", queryTypeName) b.handlers[queryTypeName] = handler } diff --git a/pkg/cmd/web.go b/pkg/cmd/web.go index 0a196dc090e..ce4cb4e078c 100644 --- a/pkg/cmd/web.go +++ b/pkg/cmd/web.go @@ -70,12 +70,7 @@ func runWeb(*cli.Context) { social.NewOAuthService() sqlstore.Init() - - // init database - sqlstore.LoadModelsConfig() - if err := sqlstore.NewEngine(); err != nil { - log.Fatal(4, "fail to initialize orm engine: %v", err) - } + sqlstore.NewEngine() m := newMacaron() api.Register(m) diff --git a/pkg/models/account.go b/pkg/models/account.go index 6689d147a49..1a7aca07fa4 100644 --- a/pkg/models/account.go +++ b/pkg/models/account.go @@ -37,6 +37,7 @@ type Account struct { Company string NextDashboardId int UsingAccountId int64 - Created time.Time `xorm:"CREATED"` - Updated time.Time `xorm:"UPDATED"` + + Created time.Time + Updated time.Time } diff --git a/pkg/models/datasource.go b/pkg/models/datasource.go index 0e0a53d437d..0c03eb3c4bb 100644 --- a/pkg/models/datasource.go +++ b/pkg/models/datasource.go @@ -6,8 +6,8 @@ const ( DS_GRAPHITE = "GRAPHITE" DS_INFLUXDB = "INFLUXDB" DS_ES = "ES" - DS_ACESSS_DIRECT = "DIRECT" - DS_ACESSS_PROXY = "PROXY" + DS_ACCESS_DIRECT = "DIRECT" + DS_ACCESS_PROXY = "PROXY" ) type DsType string diff --git a/pkg/stores/sqlstore/sqlstore.go b/pkg/stores/sqlstore/sqlstore.go index 54a46f8cfc2..c1a552e9295 100644 --- a/pkg/stores/sqlstore/sqlstore.go +++ b/pkg/stores/sqlstore/sqlstore.go @@ -6,6 +6,7 @@ import ( "path" "strings" + "github.com/torkelo/grafana-pro/pkg/log" m "github.com/torkelo/grafana-pro/pkg/models" "github.com/torkelo/grafana-pro/pkg/setting" @@ -26,10 +27,14 @@ var ( UseSQLite3 bool ) -func Init() { +func init() { + tables = make([]interface{}, 0) + tables = append(tables, new(m.Account), new(m.Dashboard), new(m.Collaborator), new(m.DataSource)) +} +func Init() { m.SaveAccount = SaveAccount m.GetAccount = GetAccount m.GetAccountByLogin = GetAccountByLogin @@ -42,55 +47,52 @@ func Init() { m.AddCollaborator = AddCollaborator } -func LoadModelsConfig() { - DbCfg.Type = setting.Cfg.MustValue("database", "type") - if DbCfg.Type == "sqlite3" { - UseSQLite3 = true - } - DbCfg.Host = setting.Cfg.MustValue("database", "host") - DbCfg.Name = setting.Cfg.MustValue("database", "name") - DbCfg.User = setting.Cfg.MustValue("database", "user") - if len(DbCfg.Pwd) == 0 { - DbCfg.Pwd = setting.Cfg.MustValue("database", "password") - } - DbCfg.SslMode = setting.Cfg.MustValue("database", "ssl_mode") - DbCfg.Path = setting.Cfg.MustValue("database", "path", "data/grafana.db") -} - func NewEngine() (err error) { - if err = SetEngine(); err != nil { - return err + x, err = getEngine() + + if err != nil { + return fmt.Errorf("sqlstore.init(fail to connect to database): %v", err) } - if err = x.Sync2(tables...); err != nil { - return fmt.Errorf("sync database struct error: %v\n", err) + + err = SetEngine(x, true) + + if err != nil { + log.Fatal(4, "fail to initialize orm engine: %v", err) } + return nil } -func SetEngine() (err error) { - x, err = getEngine() - if err != nil { - return fmt.Errorf("models.init(fail to connect to database): %v", err) +func SetEngine(engine *xorm.Engine, enableLog bool) (err error) { + x = engine + + if err := x.Sync2(tables...); err != nil { + return fmt.Errorf("sync database struct error: %v\n", err) } - logPath := path.Join(setting.LogRootPath, "xorm.log") - os.MkdirAll(path.Dir(logPath), os.ModePerm) + if enableLog { + logPath := path.Join(setting.LogRootPath, "xorm.log") + os.MkdirAll(path.Dir(logPath), os.ModePerm) - f, err := os.Create(logPath) - if err != nil { - return fmt.Errorf("models.init(fail to create xorm.log): %v", err) + f, err := os.Create(logPath) + if err != nil { + return fmt.Errorf("sqlstore.init(fail to create xorm.log): %v", err) + } + x.Logger = xorm.NewSimpleLogger(f) + + x.ShowSQL = true + x.ShowInfo = true + x.ShowDebug = true + x.ShowErr = true + x.ShowWarn = true } - x.Logger = xorm.NewSimpleLogger(f) - x.ShowSQL = true - x.ShowInfo = true - x.ShowDebug = true - x.ShowErr = true - x.ShowWarn = true return nil } func getEngine() (*xorm.Engine, error) { + LoadConfig() + cnnstr := "" switch DbCfg.Type { case "mysql": @@ -113,5 +115,45 @@ func getEngine() (*xorm.Engine, error) { default: return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type) } + return xorm.NewEngine(DbCfg.Type, cnnstr) } + +func LoadConfig() { + DbCfg.Type = setting.Cfg.MustValue("database", "type") + if DbCfg.Type == "sqlite3" { + UseSQLite3 = true + } + DbCfg.Host = setting.Cfg.MustValue("database", "host") + DbCfg.Name = setting.Cfg.MustValue("database", "name") + DbCfg.User = setting.Cfg.MustValue("database", "user") + if len(DbCfg.Pwd) == 0 { + DbCfg.Pwd = setting.Cfg.MustValue("database", "password") + } + DbCfg.SslMode = setting.Cfg.MustValue("database", "ssl_mode") + DbCfg.Path = setting.Cfg.MustValue("database", "path", "data/grafana.db") +} + +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 +} diff --git a/pkg/stores/sqlstore/sqlstore_datasource.go b/pkg/stores/sqlstore/sqlstore_datasource.go index c275a7ce4e5..d644b05ad09 100644 --- a/pkg/stores/sqlstore/sqlstore_datasource.go +++ b/pkg/stores/sqlstore/sqlstore_datasource.go @@ -1,20 +1,47 @@ package sqlstore import ( - "errors" + "time" + "github.com/torkelo/grafana-pro/pkg/bus" m "github.com/torkelo/grafana-pro/pkg/models" + + "github.com/go-xorm/xorm" ) func init() { - bus.AddHandler("sql", GetDataSourcesQuery) + bus.AddHandler("sql", GetDataSources) bus.AddHandler("sql", AddDataSource) } -func GetDataSourcesQuery(query *m.GetDataSourcesQuery) error { - return errors.New("Hello from query handler") +func GetDataSources(query *m.GetDataSourcesQuery) error { + sess := x.Limit(100, 0).Where("account_id=?", query.AccountId) + + query.Resp = make([]*m.DataSource, 0) + return sess.Find(&query.Resp) } func AddDataSource(cmd *m.AddDataSourceCommand) error { - return errors.New("Hello from command handler") + + return inTransaction(func(sess *xorm.Session) error { + var err error + + ds := m.DataSource{ + AccountId: cmd.AccountId, + Name: cmd.Name, + Type: cmd.Type, + Access: cmd.Access, + Url: cmd.Url, + Created: time.Now(), + Updated: time.Now(), + } + + if ds.Id == 0 { + _, err = sess.Insert(ds) + } else { + _, err = sess.Id(ds.Id).Update(ds) + } + + return err + }) } diff --git a/pkg/stores/sqlstore/sqlstore_test.go b/pkg/stores/sqlstore/sqlstore_test.go new file mode 100644 index 00000000000..aa9f02b2f33 --- /dev/null +++ b/pkg/stores/sqlstore/sqlstore_test.go @@ -0,0 +1,54 @@ +package sqlstore + +import ( + "testing" + + "github.com/go-xorm/xorm" + + . "github.com/smartystreets/goconvey/convey" + + m "github.com/torkelo/grafana-pro/pkg/models" +) + +func InitTestDB(t *testing.T) { + x, err := xorm.NewEngine("sqlite3", ":memory:") + + if err != nil { + t.Fatalf("Failed to init in memory sqllite3 db %v", err) + } + + SetEngine(x, false) +} + +type Test struct { + Id int64 + Name string +} + +func TestDataAccess(t *testing.T) { + + Convey("Testing DB", t, func() { + InitTestDB(t) + + Convey("Can add datasource", func() { + + err := AddDataSource(&m.AddDataSourceCommand{ + AccountId: 10, + Type: m.DS_GRAPHITE, + Access: m.DS_ACCESS_DIRECT, + Url: "http://test", + }) + + So(err, ShouldBeNil) + + query := m.GetDataSourcesQuery{AccountId: 10} + err = GetDataSources(&query) + So(err, ShouldBeNil) + + So(len(query.Resp), ShouldEqual, 1) + + }) + + }) + +}