mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-09-13 06:09:21 -04:00
When top-level AND conjuncts pin the query to a single root (driveId/RootID restrictions), only that space's index is asked; the restriction itself stays in the query, so this is purely an optimization. Conservative by design: any top-level OR, negated or group-nested restriction leaves the fan-out untouched, searching a space too many is wasted work while skipping one would be wrong. Mountpoints are kept for result path mapping. Costs one extra parse of the query in the service; parsing once and handing the AST to the engines (which currently re-parse per space) is a follow-up that changes the engine interface.
105 lines
3.1 KiB
Go
105 lines
3.1 KiB
Go
package query
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
|
|
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
|
"reflect"
|
|
|
|
"github.com/opencloud-eu/opencloud/pkg/ast"
|
|
"github.com/opencloud-eu/opencloud/services/search/pkg/query/mimetype"
|
|
"github.com/opencloud-eu/opencloud/services/search/pkg/search"
|
|
)
|
|
|
|
// Normalize is the shared KQL lowering pass between parse and compile: it
|
|
// resolves keys to real field names (via resolve) and expands media-type
|
|
// restrictions, so the backends compile a plain field:value AST.
|
|
func Normalize(a *ast.Ast, resolve func(string) string) *ast.Ast {
|
|
a.Nodes = normalizeNodes(a.Nodes, resolve, "")
|
|
return a
|
|
}
|
|
|
|
// normalizeNodes rewrites nodes in place. defaultKey is what a bare restriction
|
|
// inherits: its enclosing group's key, or "" at the top level.
|
|
func normalizeNodes(nodes []ast.Node, resolve func(string) string, defaultKey string) []ast.Node {
|
|
resolveKey := func(key string) string {
|
|
if key == "" && defaultKey != "" {
|
|
return defaultKey // bare child inherits the group key
|
|
}
|
|
return resolve(key)
|
|
}
|
|
|
|
out := make([]ast.Node, 0, len(nodes))
|
|
for _, n := range nodes {
|
|
n = toPointer(n) // ensure a pointer so in-place key rewrites persist
|
|
switch node := n.(type) {
|
|
case *ast.StringNode:
|
|
node.Key = resolveKey(node.Key)
|
|
if FieldValueIsNormalized(node.Key) {
|
|
node.Value = strings.ToLower(node.Value)
|
|
}
|
|
if node.Key == "Type" {
|
|
node.Value = resourceType(node.Value)
|
|
}
|
|
if node.Key == "RootID" {
|
|
node.Value = search.CompleteRootID(node.Value)
|
|
}
|
|
if exp := mimetype.Expand(node.Key, node.Value); exp != nil {
|
|
out = append(out, normalizeNodes(exp, resolve, defaultKey)...)
|
|
continue
|
|
}
|
|
node.CaseInsensitive = FieldIsCaseInsensitive(node.Key)
|
|
out = append(out, node)
|
|
case *ast.DateTimeNode:
|
|
node.Key = resolveKey(node.Key)
|
|
out = append(out, node)
|
|
case *ast.BooleanNode:
|
|
node.Key = resolveKey(node.Key)
|
|
out = append(out, node)
|
|
case *ast.NumberNode:
|
|
node.Key = resolveKey(node.Key)
|
|
out = append(out, node)
|
|
case *ast.GroupNode:
|
|
groupKey := defaultKey
|
|
if node.Key != "" {
|
|
node.Key = resolve(node.Key)
|
|
groupKey = node.Key
|
|
}
|
|
node.Nodes = normalizeNodes(node.Nodes, resolve, groupKey)
|
|
out = append(out, node)
|
|
default:
|
|
out = append(out, n)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// toPointer returns n as a pointer; the parser emits some nodes by value and the
|
|
// in-place key rewrites would be lost on those.
|
|
func toPointer(n ast.Node) ast.Node {
|
|
rv := reflect.ValueOf(n)
|
|
if rv.Kind() == reflect.Ptr {
|
|
return n
|
|
}
|
|
ptr := reflect.New(rv.Type())
|
|
ptr.Elem().Set(rv)
|
|
if pn, ok := ptr.Interface().(ast.Node); ok {
|
|
return pn
|
|
}
|
|
return n
|
|
}
|
|
|
|
// resourceType maps the type categories to the stored resource type value;
|
|
// unknown values pass through and become dead term queries.
|
|
func resourceType(value string) string {
|
|
switch strings.ToLower(value) {
|
|
case "file":
|
|
return strconv.FormatUint(uint64(provider.ResourceType_RESOURCE_TYPE_FILE), 10)
|
|
case "folder":
|
|
return strconv.FormatUint(uint64(provider.ResourceType_RESOURCE_TYPE_CONTAINER), 10)
|
|
default:
|
|
return value
|
|
}
|
|
}
|