Major refactorings around searching, moved to seperate package, trying to move stuff out of models package, extend search support searching different types of entities and different types of dashboards, #960

This commit is contained in:
Torkel Ödegaard
2015-05-13 13:36:24 +02:00
parent c8146e759f
commit 448a8b8d1c
19 changed files with 143 additions and 128 deletions
-134
View File
@@ -1,134 +0,0 @@
package search
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models"
)
type JsonDashIndex struct {
path string
orgsIds []int64
items []*JsonDashIndexItem
}
type JsonDashIndexItem struct {
TitleLower string
TagsCsv string
Path string
Dashboard *m.Dashboard
}
func NewJsonDashIndex(path string, orgIds string) *JsonDashIndex {
log.Info("Creating json dashboard index for path: ", path)
index := JsonDashIndex{}
index.path = path
index.updateIndex()
return &index
}
func (index *JsonDashIndex) Search(query *Query) ([]*m.DashboardSearchHit, error) {
results := make([]*m.DashboardSearchHit, 0)
for _, item := range index.items {
if len(results) > query.Limit {
break
}
// filter out results with tag filter
if query.Tag != "" {
if !strings.Contains(item.TagsCsv, query.Tag) {
continue
}
}
// add results with matchig title filter
if strings.Contains(item.TitleLower, query.Title) {
results = append(results, &m.DashboardSearchHit{
Type: m.DashTypeJson,
Title: item.Dashboard.Title,
Tags: item.Dashboard.GetTags(),
Uri: "file/" + item.Path,
})
}
}
return results, nil
}
func (index *JsonDashIndex) GetDashboard(path string) *m.Dashboard {
for _, item := range index.items {
if item.Path == path {
return item.Dashboard
}
}
return nil
}
func (index *JsonDashIndex) updateIndex() error {
index.items = make([]*JsonDashIndexItem, 0)
visitor := func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
if f.IsDir() {
return nil
}
if strings.HasSuffix(f.Name(), ".json") {
err = index.loadDashboardIntoCache(path)
if err != nil {
return err
}
}
return nil
}
if err := filepath.Walk(index.path, visitor); err != nil {
return err
}
return nil
}
func (index *JsonDashIndex) loadDashboardIntoCache(filename string) error {
dash, err := loadDashboardFromFile(filename)
if err != nil {
return err
}
index.items = append(index.items, dash)
return nil
}
func loadDashboardFromFile(filename string) (*JsonDashIndexItem, error) {
reader, err := os.Open(filename)
if err != nil {
return nil, err
}
defer reader.Close()
jsonParser := json.NewDecoder(reader)
var data map[string]interface{}
if err := jsonParser.Decode(&data); err != nil {
return nil, err
}
stat, _ := os.Stat(filename)
item := &JsonDashIndexItem{}
item.Dashboard = m.NewDashboardFromJson(data)
item.TitleLower = strings.ToLower(item.Dashboard.Title)
item.TagsCsv = strings.Join(item.Dashboard.GetTags(), ",")
item.Path = stat.Name()
return item, nil
}
-35
View File
@@ -1,35 +0,0 @@
package search
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestJsonDashIndex(t *testing.T) {
Convey("Given the json dash index", t, func() {
index := NewJsonDashIndex("../../../public/dashboards/", "*")
Convey("Should be able to update index", func() {
err := index.updateIndex()
So(err, ShouldBeNil)
})
Convey("Should be able to search index", func() {
res, err := index.Search(&Query{Title: "", Tag: "", Limit: 20})
So(err, ShouldBeNil)
So(len(res), ShouldEqual, 3)
})
Convey("Should be able to search index by title", func() {
res, err := index.Search(&Query{Title: "home", Tag: "", Limit: 20})
So(err, ShouldBeNil)
So(len(res), ShouldEqual, 1)
So(res[0].Title, ShouldEqual, "Home")
})
})
}
-96
View File
@@ -1,96 +0,0 @@
package search
import (
"path/filepath"
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
type Query struct {
Title string
Tag string
OrgId int64
UserId int64
Limit int
IsStarred bool
Result []*m.DashboardSearchHit
}
var jsonDashIndex *JsonDashIndex
func Init() {
bus.AddHandler("search", searchHandler)
jsonIndexCfg, _ := setting.Cfg.GetSection("dashboards.json")
jsonIndexEnabled := jsonIndexCfg.Key("enabled").MustBool(false)
if jsonIndexEnabled {
jsonFilesPath := jsonIndexCfg.Key("path").String()
if !filepath.IsAbs(jsonFilesPath) {
jsonFilesPath = filepath.Join(setting.HomePath, jsonFilesPath)
}
orgIds := jsonIndexCfg.Key("org_ids").String()
jsonDashIndex = NewJsonDashIndex(jsonFilesPath, orgIds)
}
}
func searchHandler(query *Query) error {
hits := make([]*m.DashboardSearchHit, 0)
dashQuery := m.SearchDashboardsQuery{
Title: query.Title,
Tag: query.Tag,
UserId: query.UserId,
Limit: query.Limit,
IsStarred: query.IsStarred,
OrgId: query.OrgId,
}
if err := bus.Dispatch(&dashQuery); err != nil {
return err
}
hits = append(hits, dashQuery.Result...)
if jsonDashIndex != nil {
jsonHits, err := jsonDashIndex.Search(query)
if err != nil {
return err
}
hits = append(hits, jsonHits...)
}
if err := setIsStarredFlagOnSearchResults(query.UserId, hits); err != nil {
return err
}
query.Result = hits
return nil
}
func setIsStarredFlagOnSearchResults(userId int64, hits []*m.DashboardSearchHit) error {
query := m.GetUserStarsQuery{UserId: userId}
if err := bus.Dispatch(&query); err != nil {
return err
}
for _, dash := range hits {
if _, exists := query.Result[dash.Id]; exists {
dash.IsStarred = true
}
}
return nil
}
func GetDashboardFromJsonIndex(filename string) *m.Dashboard {
if jsonDashIndex == nil {
return nil
}
return jsonDashIndex.GetDashboard(filename)
}
+6 -5
View File
@@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/metrics"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/search"
)
func init() {
@@ -119,7 +120,7 @@ type DashboardSearchProjection struct {
Term string
}
func SearchDashboards(query *m.SearchDashboardsQuery) error {
func SearchDashboards(query *search.FindPersistedDashboardsQuery) error {
var sql bytes.Buffer
params := make([]interface{}, 0)
@@ -166,17 +167,17 @@ func SearchDashboards(query *m.SearchDashboardsQuery) error {
return err
}
query.Result = make([]*m.DashboardSearchHit, 0)
hits := make(map[int64]*m.DashboardSearchHit)
query.Result = make([]*search.Hit, 0)
hits := make(map[int64]*search.Hit)
for _, item := range res {
hit, exists := hits[item.Id]
if !exists {
hit = &m.DashboardSearchHit{
hit = &search.Hit{
Id: item.Id,
Title: item.Title,
Uri: "db/" + item.Slug,
Type: m.DashTypeDB,
Type: search.DashHitDB,
Tags: []string{},
}
query.Result = append(query.Result, hit)
+5 -4
View File
@@ -6,6 +6,7 @@ import (
. "github.com/smartystreets/goconvey/convey"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/search"
)
func insertTestDashboard(title string, orgId int64, tags ...interface{}) *m.Dashboard {
@@ -85,7 +86,7 @@ func TestDashboardDataAccess(t *testing.T) {
})
Convey("Should be able to search for dashboard", func() {
query := m.SearchDashboardsQuery{
query := search.FindPersistedDashboardsQuery{
Title: "test",
OrgId: 1,
}
@@ -99,8 +100,8 @@ func TestDashboardDataAccess(t *testing.T) {
})
Convey("Should be able to search for dashboards using tags", func() {
query1 := m.SearchDashboardsQuery{Tag: "webapp", OrgId: 1}
query2 := m.SearchDashboardsQuery{Tag: "tagdoesnotexist", OrgId: 1}
query1 := search.FindPersistedDashboardsQuery{Tag: "webapp", OrgId: 1}
query2 := search.FindPersistedDashboardsQuery{Tag: "tagdoesnotexist", OrgId: 1}
err := SearchDashboards(&query1)
err = SearchDashboards(&query2)
@@ -146,7 +147,7 @@ func TestDashboardDataAccess(t *testing.T) {
})
Convey("Should be able to search for starred dashboards", func() {
query := m.SearchDashboardsQuery{OrgId: 1, UserId: 10, IsStarred: true}
query := search.FindPersistedDashboardsQuery{OrgId: 1, UserId: 10, IsStarred: true}
err := SearchDashboards(&query)
So(err, ShouldBeNil)