frostfs-node/pkg/services/object/search/query/v1/v1.go
Alex Vanin 719075ca97 [#99] Fix no-root search matcher
Wrong boolean operation order made matcher return false
on `non-root` search query with non-regular objects. Instead
it should return true for `non-root` query and false for `root`
query.

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
2020-10-16 13:45:35 +03:00

90 lines
2.2 KiB
Go

package query
import (
"encoding/hex"
"github.com/nspcc-dev/neofs-api-go/pkg/container"
objectSDK "github.com/nspcc-dev/neofs-api-go/pkg/object"
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
"github.com/nspcc-dev/neofs-node/pkg/core/object"
"github.com/nspcc-dev/neofs-node/pkg/services/object/search/query"
)
type Query struct {
filters objectSDK.SearchFilters
}
func New(filters objectSDK.SearchFilters) query.Query {
return &Query{
filters: filters,
}
}
func idValue(id *objectSDK.ID) string {
return hex.EncodeToString(id.ToV2().GetValue())
}
func cidValue(id *container.ID) string {
return hex.EncodeToString(id.ToV2().GetValue())
}
func ownerIDValue(id *owner.ID) string {
return hex.EncodeToString(id.ToV2().GetValue())
}
func (q *Query) Match(obj *object.Object, handler func(*objectSDK.ID)) {
for par := (*object.Object)(nil); obj != nil; par, obj = obj, obj.GetParent() {
match := true
for i := 0; match && i < len(q.filters); i++ {
switch typ := q.filters[i].Operation(); typ {
default:
match = false
case objectSDK.MatchStringEqual:
switch key := q.filters[i].Header(); key {
default:
match = headerEqual(obj, key, q.filters[i].Value())
case objectSDK.KeyRoot:
match = (q.filters[i].Value() == objectSDK.ValRoot) == (!obj.HasParent() &&
obj.GetType() == objectSDK.TypeRegular)
case objectSDK.KeyLeaf:
match = (q.filters[i].Value() == objectSDK.ValLeaf) == (par == nil)
}
}
}
if match {
handler(obj.GetID())
}
}
}
func headerEqual(obj *object.Object, key, value string) bool {
switch key {
default:
for _, attr := range obj.GetAttributes() {
if attr.GetKey() == key && attr.GetValue() == value {
return true
}
}
return false
case objectSDK.HdrSysNameID:
return value == idValue(obj.GetID())
case objectSDK.HdrSysNameCID:
return value == cidValue(obj.GetContainerID())
case objectSDK.HdrSysNameOwnerID:
return value == ownerIDValue(obj.GetOwnerID())
case keyNoChildrenField:
return len(obj.GetChildren()) == 0
case keyParentIDField:
return idValue(obj.GetParentID()) == value
case keyParentField:
return len(obj.GetChildren()) > 0
// TODO: add other headers
}
}
func (q *Query) ToSearchFilters() objectSDK.SearchFilters {
return q.filters
}