From 4d5a5dde4b9fb00f1edcf2ccafe6194c7bd079ab Mon Sep 17 00:00:00 2001 From: fschade Date: Wed, 30 Jul 2025 19:48:26 +0200 Subject: [PATCH] enhancement(search): implement non bool query compilation --- services/search/pkg/opensearch/kql.go | 44 ++++++++++++++++------ services/search/pkg/opensearch/kql_test.go | 24 ++++++------ 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/services/search/pkg/opensearch/kql.go b/services/search/pkg/opensearch/kql.go index acd9a0ff90..1b87028615 100644 --- a/services/search/pkg/opensearch/kql.go +++ b/services/search/pkg/opensearch/kql.go @@ -19,6 +19,7 @@ func (k *KQL) Compile(tree *ast.Ast) (Builder, error) { if err != nil { return nil, err } + return q, nil } @@ -62,12 +63,27 @@ func (k *KQL) getOperatorValueAt(nodes []ast.Node, i int) string { return "" } +func (k *KQL) getBuilder(node ast.Node) (Builder, error) { + var builder Builder + switch node := node.(type) { + case *ast.StringNode: + builder = NewTermQuery[string](k.getFieldName(node.Key)).Value(node.Value) + case *ast.GroupNode: + group, err := k.compile(node.Nodes) + if err != nil { + return nil, fmt.Errorf("failed to build group: %w", err) + } + builder = group + } + + return builder, nil +} + func (k *KQL) compile(nodes []ast.Node) (Builder, error) { boolQuery := NewBoolQuery() - add := boolQuery.Must - for i, node := range nodes { + for i, node := range nodes { prevOp := k.getOperatorValueAt(nodes, i-1) nextOp := k.getOperatorValueAt(nodes, i+1) @@ -78,15 +94,21 @@ func (k *KQL) compile(nodes []ast.Node) (Builder, error) { add = boolQuery.Must } - switch node := node.(type) { - case *ast.StringNode: - add(NewTermQuery[string](k.getFieldName(node.Key)).Value(node.Value)) - case *ast.GroupNode: - group, err := k.compile(node.Nodes) - if err != nil { - return nil, fmt.Errorf("failed to build group: %w", err) - } - add(group) + if _, ok := node.(*ast.OperatorNode); ok { + // operatorNodes are not builders, so we skip them + continue + } + + builder, err := k.getBuilder(node) + if err != nil { + return nil, fmt.Errorf("failed to get builder for node %T: %w", node, err) + } + + switch { + case len(nodes) == 1: + return builder, nil + default: + add(builder) } } diff --git a/services/search/pkg/opensearch/kql_test.go b/services/search/pkg/opensearch/kql_test.go index 874dba765b..4081287136 100644 --- a/services/search/pkg/opensearch/kql_test.go +++ b/services/search/pkg/opensearch/kql_test.go @@ -19,10 +19,7 @@ func TestKQL_Compile(t *testing.T) { &ast.StringNode{Value: "moby di*"}, }, }, - want: opensearch.NewBoolQuery(). - Must( - opensearch.NewTermQuery[string]("Name").Value("moby di*"), - ), + want: opensearch.NewTermQuery[string]("Name").Value("moby di*"), }, { name: "remaps known field names", @@ -31,12 +28,18 @@ func TestKQL_Compile(t *testing.T) { &ast.StringNode{Key: "mediatype", Value: "application/gzip"}, }, }, - want: opensearch.NewBoolQuery(). - Must( - opensearch.NewTermQuery[string]("MimeType").Value("application/gzip"), - ), + want: opensearch.NewTermQuery[string]("MimeType").Value("application/gzip"), }, // kql to os dsl - type tests + { + name: "remaps known field names", + got: &ast.Ast{ + Nodes: []ast.Node{ + &ast.StringNode{Key: "a", Value: "a"}, + }, + }, + want: opensearch.NewTermQuery[string]("a").Value("a"), + }, // kql to os dsl - structure tests { name: "[*]", @@ -45,10 +48,7 @@ func TestKQL_Compile(t *testing.T) { &ast.StringNode{Key: "name", Value: "moby di*"}, }, }, - want: opensearch.NewBoolQuery(). - Must( - opensearch.NewTermQuery[string]("Name").Value("moby di*"), - ), + want: opensearch.NewTermQuery[string]("Name").Value("moby di*"), }, { name: "[* *]",