mirror of https://github.com/tidwall/tile38.git
Added distance to NEARBY command
This commit is contained in:
parent
c02609ad44
commit
1b20a4c590
|
@ -149,7 +149,13 @@ func fenceMatch(hookName string, sw *scanWriter, fence *liveFenceSwitches, metas
|
|||
sw.fmap = details.fmap
|
||||
sw.fullFields = true
|
||||
sw.msg.OutputType = server.JSON
|
||||
sw.writeObject(details.id, details.obj, details.fields, true)
|
||||
sw.writeObject(ScanWriterParams{
|
||||
id:details.id,
|
||||
o: details.obj,
|
||||
fields: details.fields,
|
||||
noLock: true,
|
||||
})
|
||||
|
||||
if sw.wr.Len() == 0 {
|
||||
sw.mu.Unlock()
|
||||
return nil
|
||||
|
|
|
@ -50,14 +50,22 @@ func (c *Controller) cmdScan(msg *server.Message) (res string, err error) {
|
|||
if g.Limits[0] == "" && g.Limits[1] == "" {
|
||||
s.cursor = sw.col.Scan(s.cursor, s.desc,
|
||||
func(id string, o geojson.Object, fields []float64) bool {
|
||||
return sw.writeObject(id, o, fields, false)
|
||||
return sw.writeObject(ScanWriterParams{
|
||||
id: id,
|
||||
o: o,
|
||||
fields: fields,
|
||||
})
|
||||
},
|
||||
)
|
||||
} else {
|
||||
s.cursor = sw.col.ScanRange(
|
||||
s.cursor, g.Limits[0], g.Limits[1], s.desc,
|
||||
func(id string, o geojson.Object, fields []float64) bool {
|
||||
return sw.writeObject(id, o, fields, false)
|
||||
return sw.writeObject(ScanWriterParams{
|
||||
id: id,
|
||||
o: o,
|
||||
fields: fields,
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -54,6 +54,14 @@ type scanWriter struct {
|
|||
matchValues bool
|
||||
}
|
||||
|
||||
type ScanWriterParams struct {
|
||||
id string
|
||||
o geojson.Object
|
||||
fields []float64
|
||||
distance float64
|
||||
noLock bool
|
||||
}
|
||||
|
||||
func (c *Controller) newScanWriter(
|
||||
wr *bytes.Buffer, msg *server.Message, key string, output outputT,
|
||||
precision uint64, globPattern string, matchValues bool,
|
||||
|
@ -233,24 +241,25 @@ func (sw *scanWriter) fieldMatch(fields []float64, o geojson.Object) ([]float64,
|
|||
return sw.fvals, true
|
||||
}
|
||||
|
||||
func (sw *scanWriter) writeObject(id string, o geojson.Object, fields []float64, noLock bool) bool {
|
||||
if !noLock {
|
||||
//id string, o geojson.Object, fields []float64, noLock bool
|
||||
func (sw *scanWriter) writeObject(opts ScanWriterParams) bool {
|
||||
if !opts.noLock {
|
||||
sw.mu.Lock()
|
||||
defer sw.mu.Unlock()
|
||||
}
|
||||
keepGoing := true
|
||||
if !sw.globEverything {
|
||||
if sw.globSingle {
|
||||
if sw.globPattern != id {
|
||||
if sw.globPattern != opts.id {
|
||||
return true
|
||||
}
|
||||
keepGoing = false // return current object and stop iterating
|
||||
} else {
|
||||
var val string
|
||||
if sw.matchValues {
|
||||
val = o.String()
|
||||
val = opts.o.String()
|
||||
} else {
|
||||
val = id
|
||||
val = opts.id
|
||||
}
|
||||
ok, _ := glob.Match(sw.globPattern, val)
|
||||
if !ok {
|
||||
|
@ -258,7 +267,7 @@ func (sw *scanWriter) writeObject(id string, o geojson.Object, fields []float64,
|
|||
}
|
||||
}
|
||||
}
|
||||
nfields, ok := sw.fieldMatch(fields, o)
|
||||
nfields, ok := sw.fieldMatch(opts.fields, opts.o)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
|
@ -282,12 +291,12 @@ func (sw *scanWriter) writeObject(id string, o geojson.Object, fields []float64,
|
|||
jsfields = `,"fields":{`
|
||||
var i int
|
||||
for field, idx := range sw.fmap {
|
||||
if len(fields) > idx {
|
||||
if fields[idx] != 0 {
|
||||
if len(opts.fields) > idx {
|
||||
if opts.fields[idx] != 0 {
|
||||
if i > 0 {
|
||||
jsfields += `,`
|
||||
}
|
||||
jsfields += jsonString(field) + ":" + strconv.FormatFloat(fields[idx], 'f', -1, 64)
|
||||
jsfields += jsonString(field) + ":" + strconv.FormatFloat(opts.fields[idx], 'f', -1, 64)
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
@ -307,38 +316,44 @@ func (sw *scanWriter) writeObject(id string, o geojson.Object, fields []float64,
|
|||
}
|
||||
}
|
||||
if sw.output == outputIDs {
|
||||
wr.WriteString(jsonString(id))
|
||||
wr.WriteString(jsonString(opts.id))
|
||||
} else {
|
||||
wr.WriteString(`{"id":` + jsonString(id))
|
||||
wr.WriteString(`{"id":` + jsonString(opts.id))
|
||||
switch sw.output {
|
||||
case outputObjects:
|
||||
wr.WriteString(`,"object":` + o.JSON())
|
||||
wr.WriteString(`,"object":` + opts.o.JSON())
|
||||
case outputPoints:
|
||||
wr.WriteString(`,"point":` + o.CalculatedPoint().ExternalJSON())
|
||||
wr.WriteString(`,"point":` + opts.o.CalculatedPoint().ExternalJSON())
|
||||
case outputHashes:
|
||||
p, err := o.Geohash(int(sw.precision))
|
||||
p, err := opts.o.Geohash(int(sw.precision))
|
||||
if err != nil {
|
||||
p = ""
|
||||
}
|
||||
wr.WriteString(`,"hash":"` + p + `"`)
|
||||
case outputBounds:
|
||||
wr.WriteString(`,"bounds":` + o.CalculatedBBox().ExternalJSON())
|
||||
wr.WriteString(`,"bounds":` + opts.o.CalculatedBBox().ExternalJSON())
|
||||
}
|
||||
|
||||
wr.WriteString(jsfields)
|
||||
|
||||
if opts.distance > 0 {
|
||||
wr.WriteString(`,"distance":` + strconv.FormatFloat(opts.distance, 'f', 2, 64))
|
||||
}
|
||||
|
||||
wr.WriteString(`}`)
|
||||
}
|
||||
sw.wr.Write(wr.Bytes())
|
||||
case server.RESP:
|
||||
vals := make([]resp.Value, 1, 3)
|
||||
vals[0] = resp.StringValue(id)
|
||||
vals[0] = resp.StringValue(opts.id)
|
||||
if sw.output == outputIDs {
|
||||
sw.values = append(sw.values, vals[0])
|
||||
} else {
|
||||
switch sw.output {
|
||||
case outputObjects:
|
||||
vals = append(vals, resp.StringValue(o.String()))
|
||||
vals = append(vals, resp.StringValue(opts.o.String()))
|
||||
case outputPoints:
|
||||
point := o.CalculatedPoint()
|
||||
point := opts.o.CalculatedPoint()
|
||||
if point.Z != 0 {
|
||||
vals = append(vals, resp.ArrayValue([]resp.Value{
|
||||
resp.FloatValue(point.Y),
|
||||
|
@ -352,13 +367,13 @@ func (sw *scanWriter) writeObject(id string, o geojson.Object, fields []float64,
|
|||
}))
|
||||
}
|
||||
case outputHashes:
|
||||
p, err := o.Geohash(int(sw.precision))
|
||||
p, err := opts.o.Geohash(int(sw.precision))
|
||||
if err != nil {
|
||||
p = ""
|
||||
}
|
||||
vals = append(vals, resp.StringValue(p))
|
||||
case outputBounds:
|
||||
bbox := o.CalculatedBBox()
|
||||
bbox := opts.o.CalculatedBBox()
|
||||
vals = append(vals, resp.ArrayValue([]resp.Value{
|
||||
resp.ArrayValue([]resp.Value{
|
||||
resp.FloatValue(bbox.Min.Y),
|
||||
|
@ -371,7 +386,7 @@ func (sw *scanWriter) writeObject(id string, o geojson.Object, fields []float64,
|
|||
}))
|
||||
}
|
||||
|
||||
fvs := orderFields(sw.fmap, fields)
|
||||
fvs := orderFields(sw.fmap, opts.fields)
|
||||
if len(fvs) > 0 {
|
||||
fvals := make([]resp.Value, 0, len(fvs)*2)
|
||||
for i, fv := range fvs {
|
||||
|
@ -381,6 +396,10 @@ func (sw *scanWriter) writeObject(id string, o geojson.Object, fields []float64,
|
|||
vals = append(vals, resp.ArrayValue(fvals))
|
||||
}
|
||||
|
||||
if opts.distance > 0 {
|
||||
vals = append(vals, resp.FloatValue(opts.distance))
|
||||
}
|
||||
|
||||
sw.values = append(sw.values, resp.ArrayValue(vals))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -291,7 +291,18 @@ func (c *Controller) cmdNearby(msg *server.Message) (res string, err error) {
|
|||
sw.writeHead()
|
||||
if sw.col != nil {
|
||||
s.cursor = sw.col.Nearby(s.cursor, s.sparse, s.lat, s.lon, s.meters, minZ, maxZ, func(id string, o geojson.Object, fields []float64) bool {
|
||||
return sw.writeObject(id, o, fields, false)
|
||||
// Calculate distance if we need to
|
||||
distance := 0.0
|
||||
if s.distance {
|
||||
distance = o.CalculatedPoint().DistanceTo(geojson.Position{X: s.lon, Y: s.lat, Z: 0})
|
||||
}
|
||||
|
||||
return sw.writeObject(ScanWriterParams{
|
||||
id: id,
|
||||
o: o,
|
||||
fields: fields,
|
||||
distance: distance,
|
||||
})
|
||||
})
|
||||
}
|
||||
sw.writeFoot(s.cursor)
|
||||
|
@ -337,13 +348,21 @@ func (c *Controller) cmdWithinOrIntersects(cmd string, msg *server.Message) (res
|
|||
if cmd == "within" {
|
||||
s.cursor = sw.col.Within(s.cursor, s.sparse, s.o, s.minLat, s.minLon, s.maxLat, s.maxLon, minZ, maxZ,
|
||||
func(id string, o geojson.Object, fields []float64) bool {
|
||||
return sw.writeObject(id, o, fields, false)
|
||||
return sw.writeObject(ScanWriterParams{
|
||||
id: id,
|
||||
o: o,
|
||||
fields: fields,
|
||||
})
|
||||
},
|
||||
)
|
||||
} else if cmd == "intersects" {
|
||||
s.cursor = sw.col.Intersects(s.cursor, s.sparse, s.o, s.minLat, s.minLon, s.maxLat, s.maxLon, minZ, maxZ,
|
||||
func(id string, o geojson.Object, fields []float64) bool {
|
||||
return sw.writeObject(id, o, fields, false)
|
||||
return sw.writeObject(ScanWriterParams{
|
||||
id: id,
|
||||
o: o,
|
||||
fields: fields,
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -394,7 +413,11 @@ func (c *Controller) cmdSearch(msg *server.Message) (res string, err error) {
|
|||
if g.Limits[0] == "" && g.Limits[1] == "" {
|
||||
s.cursor = sw.col.SearchValues(s.cursor, s.desc,
|
||||
func(id string, o geojson.Object, fields []float64) bool {
|
||||
return sw.writeObject(id, o, fields, false)
|
||||
return sw.writeObject(ScanWriterParams{
|
||||
id: id,
|
||||
o: o,
|
||||
fields: fields,
|
||||
})
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -404,7 +427,11 @@ func (c *Controller) cmdSearch(msg *server.Message) (res string, err error) {
|
|||
s.cursor = sw.col.SearchValuesRange(
|
||||
s.cursor, g.Limits[0], g.Limits[1], s.desc,
|
||||
func(id string, o geojson.Object, fields []float64) bool {
|
||||
return sw.writeObject(id, o, fields, false)
|
||||
return sw.writeObject(ScanWriterParams{
|
||||
id: id,
|
||||
o: o,
|
||||
fields: fields,
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -163,6 +163,7 @@ type searchScanBaseTokens struct {
|
|||
precision uint64
|
||||
lineout string
|
||||
fence bool
|
||||
distance bool
|
||||
detect map[string]bool
|
||||
accept map[string]bool
|
||||
glob string
|
||||
|
@ -304,6 +305,14 @@ func parseSearchScanBaseTokens(cmd string, vs []resp.Value) (vsout []resp.Value,
|
|||
t.accept = nil
|
||||
}
|
||||
continue
|
||||
} else if (wtok[0] == 'D' || wtok[0] == 'd') && strings.ToLower(wtok) == "distance" {
|
||||
vs = nvs
|
||||
if t.distance {
|
||||
err = errDuplicateArgument(strings.ToUpper(wtok))
|
||||
return
|
||||
}
|
||||
t.distance = true
|
||||
continue
|
||||
} else if (wtok[0] == 'D' || wtok[0] == 'd') && strings.ToLower(wtok) == "detect" {
|
||||
vs = nvs
|
||||
if t.detect != nil {
|
||||
|
|
Loading…
Reference in New Issue