summaryrefslogtreecommitdiff
path: root/system/search/search.go
diff options
context:
space:
mode:
authorSteve Manuel <nilslice@gmail.com>2017-04-13 13:29:18 -0700
committerSteve Manuel <nilslice@gmail.com>2017-04-13 13:29:18 -0700
commitade7c2d69c9884c493fbc2f66f6a7405c0f4f96b (patch)
tree39d5fb68b9e959b55ec3a0dbde05375f8e4ef962 /system/search/search.go
parentfe9938cc4ce7885533bf751de5b2eb65a962e99c (diff)
moving search into own package and renaming funcs throughout
Diffstat (limited to 'system/search/search.go')
-rw-r--r--system/search/search.go162
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
+}