go-sonic/sonic/search.go
2021-01-25 16:10:22 +03:00

101 lines
2.6 KiB
Go

package sonic
import (
"fmt"
"strings"
)
// Searchable is used for querying the search index.
type Searchable interface {
// Query the database, return a list of object, represented as a string.
// Sonic default limit is 10.
// Command syntax QUERY <collection> <bucket> "<terms>" [LIMIT(<count>)]? [OFFSET(<count>)]? [LANG(<locale>)]?.
Query(collection, bucket, terms string, limit, offset int, lang Lang) (results []string, err error)
// Suggest auto-completes word, return a list of words as a string.
// Command syntax SUGGEST <collection> <bucket> "<word>" [LIMIT(<count>)]?.
Suggest(collection, bucket, word string, limit int) (results []string, err error)
// Quit refer to the Base interface
Quit() (err error)
// Ping refer to the Base interface
Ping() (err error)
}
type searchCommands string
const (
query searchCommands = "QUERY"
suggest searchCommands = "SUGGEST"
)
type searchChannel struct {
*driver
}
// NewSearch create a new driver instance with a searchChannel instance.
// Only way to get a Searchable implementation.
func NewSearch(host string, port int, password string) (Searchable, error) {
driver := &driver{
Host: host,
Port: port,
Password: password,
channel: Search,
}
err := driver.Connect()
if err != nil {
return nil, err
}
return searchChannel{
driver: driver,
}, nil
}
func (s searchChannel) Query(collection, bucket, term string, limit, offset int, lang Lang) (results []string, err error) {
err = s.write(fmt.Sprintf("%s %s %s \"%s\" LIMIT(%d) OFFSET(%d)"+langFormat(lang), query, collection, bucket, term, limit, offset, lang))
if err != nil {
return nil, err
}
// pending, should be PENDING ID_EVENT
_, err = s.read()
if err != nil {
return nil, err
}
// event query, should be EVENT QUERY ID_EVENT RESULT1 RESULT2 ...
read, err := s.read()
if err != nil {
return nil, err
}
return getSearchResults(read, string(query)), nil
}
func (s searchChannel) Suggest(collection, bucket, word string, limit int) (results []string, err error) {
err = s.write(fmt.Sprintf("%s %s %s \"%s\" LIMIT(%d)", suggest, collection, bucket, word, limit))
if err != nil {
return nil, err
}
// pending, should be PENDING ID_EVENT
_, err = s.read()
if err != nil {
return nil, err
}
// event query, should be EVENT SUGGEST ID_EVENT RESULT1 RESULT2 ...
read, err := s.read()
if err != nil {
return nil, err
}
return getSearchResults(read, string(suggest)), nil
}
func getSearchResults(line string, eventType string) []string {
if strings.HasPrefix(line, "EVENT "+eventType) {
return strings.Split(line, " ")[3:]
}
return []string{}
}