mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-09-13 14:18:38 -04:00
both engines now agree on names, titles, tags, paths, types, sizes, dates, hidden flags, facet values and wildcards. quotes only delimit phrases and the equals operator matches the whole field value, following the kql spec. the index name carries a generation so a changed mapping starts on a fresh index, MIGRATION.md says how to fill it.
241 lines
3.9 KiB
Go
241 lines
3.9 KiB
Go
package kql
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/opencloud-eu/opencloud/pkg/ast"
|
|
)
|
|
|
|
func base(text []byte, pos position) (*ast.Base, error) {
|
|
source, err := toString(text)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ast.Base{
|
|
Loc: &ast.Location{
|
|
Start: ast.Position{
|
|
Line: pos.line,
|
|
Column: pos.col,
|
|
},
|
|
End: ast.Position{
|
|
Line: pos.line,
|
|
Column: pos.col + len(text),
|
|
},
|
|
Source: &source,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func buildAST(n any, text []byte, pos position) (*ast.Ast, error) {
|
|
b, err := base(text, pos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nodes, err := toNodes[ast.Node](n)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
a := &ast.Ast{
|
|
Base: b,
|
|
Nodes: connectNodes(DefaultConnector{sameKeyOPValue: BoolOR}, nodes...),
|
|
}
|
|
|
|
if err := validateAst(a); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return a, nil
|
|
}
|
|
|
|
func buildStringNode(k, v any, exact bool, text []byte, pos position) (*ast.StringNode, error) {
|
|
b, err := base(text, pos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
key, err := toString(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
value, err := toString(v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ast.StringNode{
|
|
Base: b,
|
|
Key: key,
|
|
Value: value,
|
|
Exact: exact,
|
|
}, nil
|
|
}
|
|
|
|
func buildDateTimeNode(k, o, v any, text []byte, pos position) (*ast.DateTimeNode, error) {
|
|
b, err := base(text, pos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
operator, err := toNode[*ast.OperatorNode](o)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
key, err := toString(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
value, err := toTime(v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ast.DateTimeNode{
|
|
Base: b,
|
|
Key: key,
|
|
Operator: operator,
|
|
Value: value,
|
|
}, nil
|
|
}
|
|
|
|
func buildNumberNode(k, o, v any, text []byte, pos position) (*ast.NumberNode, error) {
|
|
b, err := base(text, pos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
operator, err := toNode[*ast.OperatorNode](o)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
key, err := toString(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
value, err := toFloat(v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ast.NumberNode{
|
|
Base: b,
|
|
Key: key,
|
|
Operator: operator,
|
|
Value: value,
|
|
}, nil
|
|
}
|
|
|
|
func buildNaturalLanguageDateTimeNodes(k, v any, text []byte, pos position) ([]ast.Node, error) {
|
|
b, err := base(text, pos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
key, err := toString(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
from, to, err := toTimeRange(v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return []ast.Node{
|
|
&ast.DateTimeNode{
|
|
Base: b,
|
|
Value: *from,
|
|
Key: key,
|
|
Operator: &ast.OperatorNode{Value: ">="},
|
|
},
|
|
&ast.OperatorNode{Value: BoolAND},
|
|
&ast.DateTimeNode{
|
|
Base: b,
|
|
Value: *to,
|
|
Key: key,
|
|
Operator: &ast.OperatorNode{Value: "<="},
|
|
},
|
|
}, nil
|
|
|
|
}
|
|
|
|
func buildBooleanNode(k, v any, text []byte, pos position) (*ast.BooleanNode, error) {
|
|
b, err := base(text, pos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
key, err := toString(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
value, err := toString(v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ast.BooleanNode{
|
|
Base: b,
|
|
Key: key,
|
|
Value: strings.ToLower(value) == "true",
|
|
}, nil
|
|
}
|
|
|
|
func buildOperatorNode(text []byte, pos position) (*ast.OperatorNode, error) {
|
|
b, err := base(text, pos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
value, err := toString(text)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
switch value {
|
|
case "+":
|
|
value = BoolAND
|
|
case "-":
|
|
value = BoolNOT
|
|
}
|
|
|
|
return &ast.OperatorNode{
|
|
Base: b,
|
|
Value: value,
|
|
}, nil
|
|
}
|
|
|
|
func buildGroupNode(k, n any, text []byte, pos position) (*ast.GroupNode, error) {
|
|
b, err := base(text, pos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
key, _ := toString(k)
|
|
|
|
nodes, err := toNodes[ast.Node](n)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
gn := &ast.GroupNode{
|
|
Base: b,
|
|
Key: key,
|
|
Nodes: connectNodes(DefaultConnector{sameKeyOPValue: BoolOR}, nodes...),
|
|
}
|
|
|
|
if err := validateGroupNode(gn); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return gn, nil
|
|
}
|