mirror of https://github.com/tidwall/tile38.git
Merge pull request #652 from tidwall/geofence-where
Allow WHERE for geofence detection
This commit is contained in:
commit
d2953307a0
|
@ -191,8 +191,10 @@ func (c *Collection) Set(
|
||||||
oldFieldValues = c.fieldValues.get(oldItem.fieldValuesSlot)
|
oldFieldValues = c.fieldValues.get(oldItem.fieldValuesSlot)
|
||||||
newFieldValues = oldFieldValues
|
newFieldValues = oldFieldValues
|
||||||
newItem.fieldValuesSlot = oldItem.fieldValuesSlot
|
newItem.fieldValuesSlot = oldItem.fieldValuesSlot
|
||||||
|
if len(oldFieldValues) > 0 {
|
||||||
|
oldFieldValues = append([]float64{}, oldFieldValues...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if fields == nil {
|
if fields == nil {
|
||||||
if len(values) > 0 {
|
if len(values) > 0 {
|
||||||
newFieldValues = values
|
newFieldValues = values
|
||||||
|
|
|
@ -294,6 +294,7 @@ func (s *Server) queueHooks(d *commandDetails) error {
|
||||||
for _, hook := range candidates {
|
for _, hook := range candidates {
|
||||||
// Calculate all matching fence messages for all candidates and append
|
// Calculate all matching fence messages for all candidates and append
|
||||||
// them to the appropriate message slice
|
// them to the appropriate message slice
|
||||||
|
hook.ScanWriter.loadWheres()
|
||||||
msgs := FenceMatch(hook.Name, hook.ScanWriter, hook.Fence, hook.Metas, d)
|
msgs := FenceMatch(hook.Name, hook.ScanWriter, hook.Fence, hook.Metas, d)
|
||||||
if len(msgs) > 0 {
|
if len(msgs) > 0 {
|
||||||
if hook.channel {
|
if hook.channel {
|
||||||
|
|
|
@ -105,9 +105,18 @@ func fenceMatch(
|
||||||
}
|
}
|
||||||
detect = "roam"
|
detect = "roam"
|
||||||
} else {
|
} else {
|
||||||
|
var nocross bool
|
||||||
// not using roaming
|
// not using roaming
|
||||||
match1 := fenceMatchObject(fence, details.oldObj)
|
match1 := fenceMatchObject(fence, details.oldObj)
|
||||||
|
if match1 {
|
||||||
|
match1, _, _ = sw.testObject(details.id, details.oldObj, details.oldFields)
|
||||||
|
nocross = !match1
|
||||||
|
}
|
||||||
match2 := fenceMatchObject(fence, details.obj)
|
match2 := fenceMatchObject(fence, details.obj)
|
||||||
|
if match2 {
|
||||||
|
match2, _, _ = sw.testObject(details.id, details.obj, details.fields)
|
||||||
|
nocross = !match2
|
||||||
|
}
|
||||||
if match1 && match2 {
|
if match1 && match2 {
|
||||||
detect = "inside"
|
detect = "inside"
|
||||||
} else if match1 && !match2 {
|
} else if match1 && !match2 {
|
||||||
|
@ -121,7 +130,7 @@ func fenceMatch(
|
||||||
if details.command != "fset" {
|
if details.command != "fset" {
|
||||||
// Maybe the old object and new object create a line that crosses the fence.
|
// Maybe the old object and new object create a line that crosses the fence.
|
||||||
// Must detect for that possibility.
|
// Must detect for that possibility.
|
||||||
if details.oldObj != nil {
|
if !nocross && details.oldObj != nil {
|
||||||
ls := geojson.NewLineString(geometry.NewLine(
|
ls := geojson.NewLineString(geometry.NewLine(
|
||||||
[]geometry.Point{
|
[]geometry.Point{
|
||||||
details.oldObj.Center(),
|
details.oldObj.Center(),
|
||||||
|
@ -176,6 +185,7 @@ func fenceMatch(
|
||||||
o: details.obj,
|
o: details.obj,
|
||||||
fields: details.fields,
|
fields: details.fields,
|
||||||
noLock: true,
|
noLock: true,
|
||||||
|
noTest: true,
|
||||||
distance: distance,
|
distance: distance,
|
||||||
distOutput: fence.distance,
|
distOutput: fence.distance,
|
||||||
})
|
})
|
||||||
|
|
|
@ -33,6 +33,7 @@ type scanWriter struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
s *Server
|
s *Server
|
||||||
wr *bytes.Buffer
|
wr *bytes.Buffer
|
||||||
|
key string
|
||||||
msg *Message
|
msg *Message
|
||||||
col *collection.Collection
|
col *collection.Collection
|
||||||
fmap map[string]int
|
fmap map[string]int
|
||||||
|
@ -58,6 +59,8 @@ type scanWriter struct {
|
||||||
values []resp.Value
|
values []resp.Value
|
||||||
matchValues bool
|
matchValues bool
|
||||||
respOut resp.Value
|
respOut resp.Value
|
||||||
|
orgWheres []whereT
|
||||||
|
orgWhereins []whereinT
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScanWriterParams ...
|
// ScanWriterParams ...
|
||||||
|
@ -68,6 +71,7 @@ type ScanWriterParams struct {
|
||||||
distance float64
|
distance float64
|
||||||
distOutput bool // query or fence requested distance output
|
distOutput bool // query or fence requested distance output
|
||||||
noLock bool
|
noLock bool
|
||||||
|
noTest bool
|
||||||
ignoreGlobMatch bool
|
ignoreGlobMatch bool
|
||||||
clip geojson.Object
|
clip geojson.Object
|
||||||
skipTesting bool
|
skipTesting bool
|
||||||
|
@ -96,6 +100,7 @@ func (s *Server) newScanWriter(
|
||||||
sw := &scanWriter{
|
sw := &scanWriter{
|
||||||
s: s,
|
s: s,
|
||||||
wr: wr,
|
wr: wr,
|
||||||
|
key: key,
|
||||||
msg: msg,
|
msg: msg,
|
||||||
limit: limit,
|
limit: limit,
|
||||||
cursor: cursor,
|
cursor: cursor,
|
||||||
|
@ -113,34 +118,48 @@ func (s *Server) newScanWriter(
|
||||||
sw.globSingle = true
|
sw.globSingle = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sw.col = s.getCol(key)
|
sw.orgWheres = wheres
|
||||||
|
sw.orgWhereins = whereins
|
||||||
|
sw.loadWheres()
|
||||||
|
return sw, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sw *scanWriter) loadWheres() {
|
||||||
|
sw.fmap = nil
|
||||||
|
sw.farr = nil
|
||||||
|
sw.wheres = nil
|
||||||
|
sw.whereins = nil
|
||||||
|
sw.fvals = nil
|
||||||
|
sw.col = sw.s.getCol(sw.key)
|
||||||
if sw.col != nil {
|
if sw.col != nil {
|
||||||
sw.fmap = sw.col.FieldMap()
|
sw.fmap = sw.col.FieldMap()
|
||||||
sw.farr = sw.col.FieldArr()
|
sw.farr = sw.col.FieldArr()
|
||||||
// This fills index value in wheres/whereins
|
// This fills index value in wheres/whereins
|
||||||
// so we don't have to map string field names for each tested object
|
// so we don't have to map string field names for each tested object
|
||||||
var ok bool
|
var ok bool
|
||||||
if len(wheres) > 0 {
|
if len(sw.orgWheres) > 0 {
|
||||||
sw.wheres = make([]whereT, len(wheres))
|
sw.wheres = make([]whereT, len(sw.orgWheres))
|
||||||
for i, where := range wheres {
|
for i, where := range sw.orgWheres {
|
||||||
if where.index, ok = sw.fmap[where.field]; !ok {
|
if where.index, ok = sw.fmap[where.field]; !ok {
|
||||||
where.index = math.MaxInt32
|
where.index = math.MaxInt32
|
||||||
}
|
}
|
||||||
sw.wheres[i] = where
|
sw.wheres[i] = where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(whereins) > 0 {
|
if len(sw.orgWhereins) > 0 {
|
||||||
sw.whereins = make([]whereinT, len(whereins))
|
sw.whereins = make([]whereinT, len(sw.orgWhereins))
|
||||||
for i, wherein := range whereins {
|
for i, wherein := range sw.orgWhereins {
|
||||||
if wherein.index, ok = sw.fmap[wherein.field]; !ok {
|
if wherein.index, ok = sw.fmap[wherein.field]; !ok {
|
||||||
wherein.index = math.MaxInt32
|
wherein.index = math.MaxInt32
|
||||||
}
|
}
|
||||||
sw.whereins[i] = wherein
|
sw.whereins[i] = wherein
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if len(sw.farr) > 0 {
|
||||||
sw.fvals = make([]float64, len(sw.farr))
|
sw.fvals = make([]float64, len(sw.farr))
|
||||||
return sw, nil
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sw *scanWriter) hasFieldsOutput() bool {
|
func (sw *scanWriter) hasFieldsOutput() bool {
|
||||||
|
@ -373,10 +392,15 @@ func (sw *scanWriter) writeObject(opts ScanWriterParams) bool {
|
||||||
sw.mu.Lock()
|
sw.mu.Lock()
|
||||||
defer sw.mu.Unlock()
|
defer sw.mu.Unlock()
|
||||||
}
|
}
|
||||||
ok, keepGoing, _ := sw.testObject(opts.id, opts.o, opts.fields)
|
|
||||||
|
keepGoing := true
|
||||||
|
if !opts.noTest {
|
||||||
|
var ok bool
|
||||||
|
ok, keepGoing, _ = sw.testObject(opts.id, opts.o, opts.fields)
|
||||||
if !ok {
|
if !ok {
|
||||||
return keepGoing
|
return keepGoing
|
||||||
}
|
}
|
||||||
|
}
|
||||||
sw.count++
|
sw.count++
|
||||||
if sw.output == outputCount {
|
if sw.output == outputCount {
|
||||||
return sw.count < sw.limit
|
return sw.count < sw.limit
|
||||||
|
|
Loading…
Reference in New Issue