diff options
author | Steve Manuel <nilslice@gmail.com> | 2017-04-13 13:29:18 -0700 |
---|---|---|
committer | Steve Manuel <nilslice@gmail.com> | 2017-04-13 13:29:18 -0700 |
commit | ade7c2d69c9884c493fbc2f66f6a7405c0f4f96b (patch) | |
tree | 39d5fb68b9e959b55ec3a0dbde05375f8e4ef962 /system/search/search.go | |
parent | fe9938cc4ce7885533bf751de5b2eb65a962e99c (diff) |
moving search into own package and renaming funcs throughout
Diffstat (limited to 'system/search/search.go')
-rw-r--r-- | system/search/search.go | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/system/search/search.go b/system/search/search.go new file mode 100644 index 0000000..6d538ed --- /dev/null +++ b/system/search/search.go @@ -0,0 +1,162 @@ +package search + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/ponzu-cms/ponzu/system/item" + + "encoding/json" + + "github.com/blevesearch/bleve" + "github.com/blevesearch/bleve/mapping" +) + +var ( + // Search tracks all search indices to use throughout system + Search map[string]bleve.Index + + // ErrNoIndex is for failed checks for an index in Search map + ErrNoIndex = errors.New("No search index found for type provided") +) + +// Searchable ... +type Searchable interface { + SearchMapping() (*mapping.IndexMappingImpl, error) + IndexContent() bool +} + +func init() { + Search = make(map[string]bleve.Index) +} + +// MapIndex creates the mapping for a type and tracks the index to be used within +// the system for adding/deleting/checking data +func MapIndex(typeName string) error { + // type assert for Searchable, get configuration (which can be overridden) + // by Ponzu user if defines own SearchMapping() + it, ok := item.Types[typeName] + if !ok { + return fmt.Errorf("[search] MapIndex Error: Failed to MapIndex for %s, type doesn't exist", typeName) + } + s, ok := it().(Searchable) + if !ok { + return fmt.Errorf("[search] MapIndex Error: Item type %s doesn't implement search.Searchable", typeName) + } + + // skip setting or using index for types that shouldn't be indexed + if !s.IndexContent() { + return nil + } + + mapping, err := s.SearchMapping() + if err != nil { + return err + } + + idxName := typeName + ".index" + var idx bleve.Index + + // check if index exists, use it or create new one + pwd, err := os.Getwd() + if err != nil { + return err + } + + searchPath := filepath.Join(pwd, "search") + + err = os.MkdirAll(searchPath, os.ModeDir|os.ModePerm) + if err != nil { + return err + } + + idxPath := filepath.Join(searchPath, idxName) + if _, err = os.Stat(idxPath); os.IsNotExist(err) { + idx, err = bleve.New(idxPath, mapping) + if err != nil { + return err + } + idx.SetName(idxName) + } else { + idx, err = bleve.Open(idxPath) + if err != nil { + return err + } + } + + // add the type name to the index and track the index + Search[typeName] = idx + + return nil +} + +// UpdateIndex sets data into a content type's search index at the given +// identifier +func UpdateIndex(id string, data interface{}) error { + // check if there is a search index to work with + target := strings.Split(id, ":") + ns := target[0] + + idx, ok := Search[ns] + if ok { + // unmarshal json to struct, error if not registered + it, ok := item.Types[ns] + if !ok { + return fmt.Errorf("[search] UpdateIndex Error: type '%s' doesn't exist", ns) + } + + p := it() + err := json.Unmarshal(data.([]byte), &p) + if err != nil { + return err + } + + // add data to search index + return idx.Index(id, p) + } + + return nil +} + +// DeleteIndex removes data from a content type's search index at the +// given identifier +func DeleteIndex(id string) error { + // check if there is a search index to work with + target := strings.Split(id, ":") + ns := target[0] + + idx, ok := Search[ns] + if ok { + // add data to search index + return idx.Delete(id) + } + + return nil +} + +// TypeQuery conducts a search and returns a set of Ponzu "targets", Type:ID pairs, +// and an error. If there is no search index for the typeName (Type) provided, +// db.ErrNoIndex will be returned as the error +func TypeQuery(typeName, query string) ([]string, error) { + idx, ok := Search[typeName] + if !ok { + return nil, ErrNoIndex + } + + q := bleve.NewQueryStringQuery(query) + req := bleve.NewSearchRequest(q) + res, err := idx.Search(req) + if err != nil { + return nil, err + } + + var results []string + for _, hit := range res.Hits { + results = append(results, hit.ID) + } + + return results, nil +} |