diff --git a/controller/collection/collection.go b/controller/collection/collection.go index fbf2fbdc..73a4cb7c 100644 --- a/controller/collection/collection.go +++ b/controller/collection/collection.go @@ -46,7 +46,6 @@ func (i *itemT) Less(item btree.Item, ctx int) bool { // the values match so we will compare the ids, which are always unique. return i.id < item.(*itemT).id } - } func (i *itemT) Rect() (minX, minY, maxX, maxY float64) { @@ -412,3 +411,5 @@ func (c *Collection) Intersects(cursor uint64, sparse uint8, obj geojson.Object, return true }) } +func (c *Collection) SearchValues(pivot string, desc bool, iterator func(id string, obj geojson.Object, fields []float64) bool) { +} diff --git a/controller/controller.go b/controller/controller.go index 9a78c2e0..9c92c680 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -329,7 +329,7 @@ func (c *Controller) handleInputCommand(conn *server.Conn, msg *server.Message, if c.config.ReadOnly { return writeErr(errors.New("read only")) } - case "get", "keys", "scan", "nearby", "within", "intersects", "hooks": + case "get", "keys", "scan", "nearby", "within", "intersects", "hooks": //, "search": // read operations c.mu.RLock() defer c.mu.RUnlock() @@ -434,6 +434,8 @@ func (c *Controller) command(msg *server.Message, w io.Writer) (res string, d co res, err = c.cmdWithin(msg) case "intersects": res, err = c.cmdIntersects(msg) + case "search": + res, err = c.cmdSearch(msg) case "get": res, err = c.cmdGet(msg) case "keys": diff --git a/controller/search.go b/controller/search.go index 2690e982..fa0a76fe 100644 --- a/controller/search.go +++ b/controller/search.go @@ -311,7 +311,9 @@ func (c *Controller) cmdWithinOrIntersects(cmd string, msg *server.Message) (res if sw.col == nil { return "", errKeyNotFound } - wr.WriteString(`{"ok":true`) + if msg.OutputType == server.JSON { + wr.WriteString(`{"ok":true`) + } sw.writeHead() if cmd == "within" { s.cursor = sw.col.Within(s.cursor, s.sparse, s.o, s.minLat, s.minLon, s.maxLat, s.maxLon, @@ -327,6 +329,101 @@ func (c *Controller) cmdWithinOrIntersects(cmd string, msg *server.Message) (res ) } sw.writeFoot(s.cursor) - wr.WriteString(`,"elapsed":"` + time.Now().Sub(start).String() + "\"}") + if msg.OutputType == server.JSON { + wr.WriteString(`,"elapsed":"` + time.Now().Sub(start).String() + "\"}") + } + return string(wr.Bytes()), nil +} + +func (c *Controller) cmdSearch(msg *server.Message) (res string, err error) { + start := time.Now() + vs := msg.Values[1:] + var ok bool + var key string + if vs, key, ok = tokenval(vs); !ok || key == "" { + err = errInvalidNumberOfArguments + return + } + col := c.getCol(key) + if col == nil { + err = errKeyNotFound + return + } + var tok string + var pivot string + var pivoton bool + var limiton bool + var limit int + var descon bool + var desc bool + for { + if vs, tok, ok = tokenval(vs); !ok || tok == "" { + break + } + switch strings.ToLower(tok) { + default: + err = errInvalidArgument(tok) + return + case "pivot": + if pivoton { + err = errInvalidArgument(tok) + return + } + pivoton = true + if vs, pivot, ok = tokenval(vs); !ok || pivot == "" { + err = errInvalidNumberOfArguments + return + } + case "limit": + if limiton { + err = errInvalidArgument(tok) + return + } + limiton = true + if vs, tok, ok = tokenval(vs); !ok || tok == "" { + err = errInvalidNumberOfArguments + return + } + n, err2 := strconv.ParseUint(tok, 10, 64) + if err2 != nil { + err = errInvalidArgument(tok) + return + } + limit = int(n) + case "asc", "desc": + if descon { + err = errInvalidArgument(tok) + return + } + descon = true + switch strings.ToLower(tok) { + case "asc": + desc = false + case "desc": + desc = true + } + } + } + println(pivoton, pivot) + println(limiton, limit) + println(descon, desc) + wr := &bytes.Buffer{} + if msg.OutputType == server.JSON { + wr.WriteString(`{"ok":true,"objects":[`) + } + n := 0 + col.SearchValues(pivot, desc, func(id string, obj geojson.Object, fields []float64) bool { + if msg.OutputType == server.JSON { + if n > 0 { + wr.WriteString(`,`) + } + wr.WriteString(`{"id":` + jsonString(id) + `,"object":` + obj.JSON() + `}`) + n++ + } + return true + }) + if msg.OutputType == server.JSON { + wr.WriteString(`],"elapsed":"` + time.Now().Sub(start).String() + "\"}") + } return string(wr.Bytes()), nil } diff --git a/controller/server/anyreader.go b/controller/server/anyreader.go index 6865e3cf..7e90d8b4 100644 --- a/controller/server/anyreader.go +++ b/controller/server/anyreader.go @@ -159,6 +159,16 @@ reading: values = append(values, resp.StringValue(string(line))) break } + if line[0] == '"' && line[len(line)-1] == '"' { + if len(values) > 0 && + strings.ToLower(values[0].String()) == "set" && + strings.ToLower(values[len(values)-1].String()) == "string" { + // Setting a string value that is contained inside double quotes. + // This is only because of the boundary issues of the native protocol. + values = append(values, resp.StringValue(string(line[1:len(line)-1]))) + break + } + } i := 0 for ; i < len(line); i++ { if line[i] == ' ' {