github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/ast/pipesearch/searchQuery_test.go (about)

     1  /*
     2  Copyright 2023.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package pipesearch
    18  
    19  import (
    20  	"encoding/json"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/siglens/siglens/pkg/ast"
    25  	"github.com/siglens/siglens/pkg/segment/structs"
    26  	"github.com/siglens/siglens/pkg/segment/utils"
    27  	. "github.com/siglens/siglens/pkg/segment/utils"
    28  	"github.com/stretchr/testify/assert"
    29  )
    30  
    31  func testParseQuery(query string, want *ast.Node) func(t *testing.T) {
    32  	return func(t *testing.T) {
    33  		t.Helper()
    34  		t.Parallel()
    35  		n, err := Parse("", []byte(query))
    36  		if err != nil {
    37  			t.Fatalf("unexpected error: %v", err)
    38  		}
    39  		if !reflect.DeepEqual(want, n.(ast.QueryStruct).SearchFilter) {
    40  			wb, _ := json.MarshalIndent(want, "", " ")
    41  			nb, _ := json.MarshalIndent(n, "", " ")
    42  			t.Fatalf("expected:\n%s\ngot:\n%s", string(wb), string(nb))
    43  		}
    44  	}
    45  }
    46  
    47  func TestAST_simpleEqual(t *testing.T) {
    48  	json_body := []byte(`something="another"`)
    49  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
    50  	assert.Nil(t, err)
    51  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
    52  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
    53  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "something")
    54  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "another")
    55  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
    56  }
    57  
    58  func TestAST_simpleAnd(t *testing.T) {
    59  	json_body := []byte(`name="t1" AND surname="t2"`)
    60  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
    61  	assert.Nil(t, err)
    62  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
    63  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 2)
    64  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
    65  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1")
    66  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
    67  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "surname")
    68  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2")
    69  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
    70  }
    71  
    72  func TestAST_simpleOr(t *testing.T) {
    73  	json_body := []byte(`name="t1" OR surname="t2"`)
    74  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
    75  	assert.Nil(t, err)
    76  	assert.NotNil(t, res.OrFilterCondition.FilterCriteria)
    77  	assert.Len(t, res.OrFilterCondition.FilterCriteria, 2)
    78  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
    79  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1")
    80  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
    81  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "surname")
    82  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2")
    83  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
    84  }
    85  
    86  func TestAST_AND_Or(t *testing.T) {
    87  	json_body := []byte(`name="t1" OR name="t2" AND age=100`)
    88  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
    89  	assert.Nil(t, err)
    90  	assert.NotNil(t, res.OrFilterCondition.FilterCriteria)
    91  	assert.Len(t, res.OrFilterCondition.FilterCriteria, 1)
    92  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
    93  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1")
    94  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
    95  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
    96  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
    97  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2")
    98  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "age")
    99  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
   100  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "100")
   101  }
   102  
   103  func TestAST_AND_Or_paren(t *testing.T) {
   104  	json_body := []byte(`(name="t1" OR name="t2") AND age=100`)
   105  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   106  	assert.Nil(t, err)
   107  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
   108  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "age")
   109  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "100")
   110  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   111  	assert.Equal(t, res.AndFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
   112  	assert.Equal(t, res.AndFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1")
   113  	assert.Equal(t, res.AndFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   114  	assert.Equal(t, res.AndFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
   115  	assert.Equal(t, res.AndFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2")
   116  	assert.Equal(t, res.AndFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
   117  
   118  }
   119  func TestAST_AND_Or_paren_around_condition(t *testing.T) {
   120  	json_body := []byte(`name="t1" OR (name="t2")`)
   121  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   122  	assert.Nil(t, err)
   123  	assert.NotNil(t, res.OrFilterCondition.FilterCriteria)
   124  	assert.Len(t, res.OrFilterCondition.FilterCriteria, 2)
   125  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
   126  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1")
   127  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   128  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
   129  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2")
   130  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
   131  }
   132  
   133  func TestAST_AND_Or_multiple(t *testing.T) {
   134  	json_body := []byte(`name="t1" OR name="t2" OR age=100 AND surname=t3`)
   135  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   136  	assert.Nil(t, err)
   137  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
   138  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1")
   139  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   140  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
   141  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2")
   142  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   143  
   144  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "age")
   145  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "100")
   146  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   147  
   148  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "surname")
   149  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t3")
   150  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
   151  
   152  }
   153  
   154  func TestAST_freeText_simple(t *testing.T) {
   155  	json_body := []byte(`test`)
   156  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   157  	assert.Nil(t, err)
   158  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
   159  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
   160  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchColumn, "*")
   161  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchOperator, And)
   162  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchWords, [][]byte{[]byte("test")})
   163  	assert.NotEqual(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchType, structs.MATCH_PHRASE)
   164  }
   165  
   166  func TestAST_freeText_simple_matchWords(t *testing.T) {
   167  	json_body := []byte(`"test this ."`)
   168  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   169  	assert.Nil(t, err)
   170  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
   171  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
   172  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchColumn, "*")
   173  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchOperator, And)
   174  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchWords, [][]byte{[]byte("test"), []byte("this"), []byte(".")})
   175  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchType, structs.MATCH_PHRASE)
   176  }
   177  
   178  func TestAST_freeText_simple_wildcard(t *testing.T) {
   179  	json_body := []byte(`test*`)
   180  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   181  	assert.Nil(t, err)
   182  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
   183  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
   184  
   185  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
   186  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "test*")
   187  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   188  
   189  }
   190  
   191  func TestAST_freeText_simpleAnd(t *testing.T) {
   192  	json_body := []byte(`another AND test`)
   193  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   194  	assert.Nil(t, err)
   195  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
   196  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 2)
   197  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchColumn, "*")
   198  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchOperator, And)
   199  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchWords, [][]byte{[]byte("another")})
   200  	assert.NotEqual(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchType, structs.MATCH_PHRASE)
   201  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].MatchFilter.MatchColumn, "*")
   202  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].MatchFilter.MatchOperator, And)
   203  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].MatchFilter.MatchWords, [][]byte{[]byte("test")})
   204  	assert.NotEqual(t, res.AndFilterCondition.FilterCriteria[1].MatchFilter.MatchType, structs.MATCH_PHRASE)
   205  }
   206  
   207  func TestAST_freeText_simpleAnd_wildcard(t *testing.T) {
   208  	json_body := []byte(`another* AND test*`)
   209  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   210  	assert.Nil(t, err)
   211  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
   212  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 2)
   213  
   214  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 2)
   215  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
   216  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "another*")
   217  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   218  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
   219  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "test*")
   220  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
   221  }
   222  
   223  func TestAST_freeText_complexOrAnd(t *testing.T) {
   224  	json_body := []byte(`"t2" OR ("t1" AND t3)`)
   225  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   226  	assert.Nil(t, err)
   227  	assert.NotNil(t, res.OrFilterCondition.FilterCriteria)
   228  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].MatchFilter.MatchColumn, "*")
   229  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].MatchFilter.MatchOperator, And)
   230  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].MatchFilter.MatchPhrase, []byte("t2"))
   231  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].MatchFilter.MatchType, structs.MATCH_PHRASE)
   232  
   233  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].MatchFilter.MatchColumn, "*")
   234  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].MatchFilter.MatchOperator, And)
   235  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].MatchFilter.MatchPhrase, []byte("t1"))
   236  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].MatchFilter.MatchType, structs.MATCH_PHRASE)
   237  
   238  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].MatchFilter.MatchColumn, "*")
   239  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].MatchFilter.MatchOperator, And)
   240  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].MatchFilter.MatchWords, [][]byte{[]byte("t3")})
   241  	assert.NotEqual(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].MatchFilter.MatchType, structs.MATCH_PHRASE)
   242  }
   243  
   244  func TestAST_freeText_complexOrAnd_wildcard(t *testing.T) {
   245  	json_body := []byte(`t2* OR (t1* AND t3*)`)
   246  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   247  	assert.Nil(t, err)
   248  	assert.NotNil(t, res.OrFilterCondition.FilterCriteria)
   249  	assert.Len(t, res.OrFilterCondition.FilterCriteria, 1)
   250  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
   251  	assert.Equal(t, res.OrFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2*")
   252  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   253  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
   254  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1*")
   255  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   256  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
   257  	assert.Equal(t, res.OrFilterCondition.NestedNodes[0].AndFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t3*")
   258  
   259  }
   260  
   261  func TestAST_freeText_complexAndOr(t *testing.T) {
   262  	json_body := []byte(`"t2" AND ("t1" OR t3)`)
   263  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   264  	assert.Nil(t, err)
   265  
   266  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
   267  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
   268  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchColumn, "*")
   269  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchOperator, And)
   270  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchPhrase, []byte("t2"))
   271  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].MatchFilter.MatchType, structs.MATCH_PHRASE)
   272  	assert.Equal(t, res.AndFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[0].MatchFilter.MatchColumn, "*")
   273  	assert.Equal(t, res.AndFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[0].MatchFilter.MatchPhrase, []byte("t1"))
   274  	assert.Equal(t, res.AndFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[1].MatchFilter.MatchColumn, "*")
   275  	assert.Equal(t, res.AndFilterCondition.NestedNodes[0].OrFilterCondition.FilterCriteria[1].MatchFilter.MatchWords, [][]byte{[]byte("t3")})
   276  }
   277  
   278  func TestAST_columnValue_complexString(t *testing.T) {
   279  	json_body := []byte(`click_id = "627af0a5-aeb4-4471-889f-6e850958d98e"`)
   280  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   281  	assert.Nil(t, err)
   282  
   283  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
   284  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
   285  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "click_id")
   286  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   287  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "627af0a5-aeb4-4471-889f-6e850958d98e")
   288  }
   289  
   290  func TestAST_columnValue_multiWordValue(t *testing.T) {
   291  	json_body := []byte(`utm_campaign = "Town apply record."`)
   292  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
   293  	assert.Nil(t, err)
   294  
   295  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
   296  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
   297  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "utm_campaign")
   298  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
   299  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "Town apply record.")
   300  }
   301  
   302  func TestSimpleEqual(t *testing.T) {
   303  	t.Run("simple minimal condition", testParseQuery(`something="another"`, &ast.Node{
   304  		NodeType: ast.NodeTerminal,
   305  		Comparison: ast.Comparison{
   306  			Op:     "=",
   307  			Field:  "something",
   308  			Values: "\"another\"",
   309  		},
   310  		Left:  nil,
   311  		Right: nil,
   312  	}))
   313  
   314  	t.Run("multi part field name", testParseQuery(`name.something = another`, &ast.Node{
   315  		NodeType: ast.NodeTerminal,
   316  		Comparison: ast.Comparison{
   317  			Op:     "=",
   318  			Field:  "name.something",
   319  			Values: "another",
   320  		},
   321  		Left:  nil,
   322  		Right: nil,
   323  	}))
   324  
   325  	t.Run("simple AND clause", testParseQuery(`name="t1" AND surname="t2"`, &ast.Node{
   326  		NodeType: ast.NodeAnd,
   327  		Left: &ast.Node{
   328  			NodeType: ast.NodeTerminal,
   329  			Comparison: ast.Comparison{
   330  				Op:     "=",
   331  				Field:  "name",
   332  				Values: "\"t1\"",
   333  			},
   334  		},
   335  		Right: &ast.Node{
   336  			NodeType: ast.NodeTerminal,
   337  			Comparison: ast.Comparison{
   338  				Op:     "=",
   339  				Field:  "surname",
   340  				Values: "\"t2\"",
   341  			},
   342  		},
   343  	}))
   344  
   345  	t.Run("simple AND clause with parenthesis", testParseQuery(`(name="t1" AND surname="t2")`, &ast.Node{
   346  		NodeType: ast.NodeAnd,
   347  		Left: &ast.Node{
   348  			NodeType: ast.NodeTerminal,
   349  			Comparison: ast.Comparison{
   350  				Op:     "=",
   351  				Field:  "name",
   352  				Values: "\"t1\"",
   353  			},
   354  		},
   355  		Right: &ast.Node{
   356  			NodeType: ast.NodeTerminal,
   357  			Comparison: ast.Comparison{
   358  				Op:     "=",
   359  				Field:  "surname",
   360  				Values: "\"t2\"",
   361  			},
   362  		},
   363  	}))
   364  
   365  	t.Run("simple OR clause", testParseQuery(`name="t1" OR surname="t2"`, &ast.Node{
   366  		NodeType: ast.NodeOr,
   367  		Left: &ast.Node{
   368  			NodeType: ast.NodeTerminal,
   369  			Comparison: ast.Comparison{
   370  				Op:     "=",
   371  				Field:  "name",
   372  				Values: "\"t1\"",
   373  			},
   374  		},
   375  		Right: &ast.Node{
   376  			NodeType: ast.NodeTerminal,
   377  			Comparison: ast.Comparison{
   378  				Op:     "=",
   379  				Field:  "surname",
   380  				Values: "\"t2\"",
   381  			},
   382  		},
   383  	}))
   384  
   385  	t.Run("simple OR clause with parenthesis", testParseQuery(`(name="t1" OR surname="t2")`, &ast.Node{
   386  		NodeType: ast.NodeOr,
   387  		Left: &ast.Node{
   388  			NodeType: ast.NodeTerminal,
   389  			Comparison: ast.Comparison{
   390  				Op:     "=",
   391  				Field:  "name",
   392  				Values: "\"t1\"",
   393  			},
   394  		},
   395  		Right: &ast.Node{
   396  			NodeType: ast.NodeTerminal,
   397  			Comparison: ast.Comparison{
   398  				Op:     "=",
   399  				Field:  "surname",
   400  				Values: "\"t2\"",
   401  			},
   402  		},
   403  	}))
   404  
   405  	t.Run("simple OR clause with parenthesis around condition", testParseQuery(`name="t1" OR (name="t2")`, &ast.Node{
   406  		NodeType: ast.NodeOr,
   407  		Left: &ast.Node{
   408  			NodeType: ast.NodeTerminal,
   409  			Comparison: ast.Comparison{
   410  				Op:     "=",
   411  				Field:  "name",
   412  				Values: "\"t1\"",
   413  			},
   414  		},
   415  		Right: &ast.Node{
   416  			NodeType: ast.NodeTerminal,
   417  			Comparison: ast.Comparison{
   418  				Op:     "=",
   419  				Field:  "name",
   420  				Values: "\"t2\"",
   421  			},
   422  		},
   423  	}))
   424  
   425  	t.Run("OR / AND clauses", testParseQuery(`name="t1" OR name="t2" AND age=100`, &ast.Node{
   426  		NodeType: ast.NodeOr,
   427  		Left: &ast.Node{
   428  			NodeType: ast.NodeTerminal,
   429  			Comparison: ast.Comparison{
   430  				Op:     "=",
   431  				Field:  "name",
   432  				Values: "\"t1\"",
   433  			},
   434  		},
   435  		Right: &ast.Node{
   436  			NodeType: ast.NodeAnd,
   437  			Left: &ast.Node{
   438  				NodeType: ast.NodeTerminal,
   439  				Comparison: ast.Comparison{
   440  					Op:     "=",
   441  					Field:  "name",
   442  					Values: "\"t2\"",
   443  				},
   444  			},
   445  			Right: &ast.Node{
   446  				NodeType: ast.NodeTerminal,
   447  				Comparison: ast.Comparison{
   448  					Op:     "=",
   449  					Field:  "age",
   450  					Values: json.Number("100"),
   451  				},
   452  			},
   453  		},
   454  	}))
   455  
   456  	t.Run("OR / AND clauses with paren precedence", testParseQuery(`(name="t1" AND age=100) OR name="t2"`, &ast.Node{
   457  		NodeType: ast.NodeOr,
   458  		Left: &ast.Node{
   459  			NodeType: ast.NodeAnd,
   460  			Left: &ast.Node{
   461  				NodeType: ast.NodeTerminal,
   462  				Comparison: ast.Comparison{
   463  					Op:     "=",
   464  					Field:  "name",
   465  					Values: "\"t1\"",
   466  				},
   467  			},
   468  			Right: &ast.Node{
   469  				NodeType: ast.NodeTerminal,
   470  				Comparison: ast.Comparison{
   471  					Op:     "=",
   472  					Field:  "age",
   473  					Values: json.Number("100"),
   474  				},
   475  			},
   476  		},
   477  		Right: &ast.Node{
   478  			NodeType: ast.NodeTerminal,
   479  			Comparison: ast.Comparison{
   480  				Op:     "=",
   481  				Field:  "name",
   482  				Values: "\"t2\"",
   483  			},
   484  		},
   485  	}))
   486  
   487  	t.Run("OR / AND clauses with paren precedence variation", testParseQuery(`name="t2" OR (name="t1" AND age=100) `, &ast.Node{
   488  		NodeType: ast.NodeOr,
   489  		Left: &ast.Node{
   490  			NodeType: ast.NodeTerminal,
   491  			Comparison: ast.Comparison{
   492  				Op:     "=",
   493  				Field:  "name",
   494  				Values: "\"t2\"",
   495  			},
   496  		},
   497  		Right: &ast.Node{
   498  			NodeType: ast.NodeAnd,
   499  			Left: &ast.Node{
   500  				NodeType: ast.NodeTerminal,
   501  				Comparison: ast.Comparison{
   502  					Op:     "=",
   503  					Field:  "name",
   504  					Values: "\"t1\"",
   505  				},
   506  			},
   507  			Right: &ast.Node{
   508  				NodeType: ast.NodeTerminal,
   509  				Comparison: ast.Comparison{
   510  					Op:     "=",
   511  					Field:  "age",
   512  					Values: json.Number("100"),
   513  				},
   514  			},
   515  		},
   516  	}))
   517  
   518  	t.Run("OR / AND clauses", testParseQuery(`name="t1" OR name="t2" OR age=100`, &ast.Node{
   519  		NodeType: ast.NodeOr,
   520  		Left: &ast.Node{
   521  			NodeType: ast.NodeTerminal,
   522  			Comparison: ast.Comparison{
   523  				Op:     "=",
   524  				Field:  "name",
   525  				Values: "\"t1\"",
   526  			},
   527  		},
   528  		Right: &ast.Node{
   529  			NodeType: ast.NodeOr,
   530  			Left: &ast.Node{
   531  				NodeType: ast.NodeTerminal,
   532  				Comparison: ast.Comparison{
   533  					Op:     "=",
   534  					Field:  "name",
   535  					Values: "\"t2\"",
   536  				},
   537  			},
   538  			Right: &ast.Node{
   539  				NodeType: ast.NodeTerminal,
   540  				Comparison: ast.Comparison{
   541  					Op:     "=",
   542  					Field:  "age",
   543  					Values: json.Number("100"),
   544  				},
   545  			},
   546  		},
   547  	}))
   548  
   549  	t.Run("OR / AND clauses", testParseQuery(`name="t1" OR name="t2" OR age=100 AND surname=t3`, &ast.Node{
   550  		NodeType: ast.NodeOr,
   551  
   552  		Left: &ast.Node{
   553  			NodeType: ast.NodeTerminal,
   554  			Comparison: ast.Comparison{
   555  				Op:     "=",
   556  				Field:  "name",
   557  				Values: "\"t1\"",
   558  			},
   559  		},
   560  		Right: &ast.Node{
   561  			NodeType: ast.NodeOr,
   562  			Left: &ast.Node{
   563  				NodeType: ast.NodeTerminal,
   564  				Comparison: ast.Comparison{
   565  					Op:     "=",
   566  					Field:  "name",
   567  					Values: "\"t2\"",
   568  				},
   569  			},
   570  			Right: &ast.Node{
   571  				NodeType: ast.NodeAnd,
   572  				Left: &ast.Node{
   573  					NodeType: ast.NodeTerminal,
   574  					Comparison: ast.Comparison{
   575  						Op:     "=",
   576  						Field:  "age",
   577  						Values: json.Number("100"),
   578  					},
   579  				},
   580  				Right: &ast.Node{
   581  					NodeType: ast.NodeTerminal,
   582  					Comparison: ast.Comparison{
   583  						Op:     "=",
   584  						Field:  "surname",
   585  						Values: "t3",
   586  					},
   587  				},
   588  			},
   589  		},
   590  	}))
   591  
   592  	t.Run("multiple OR / AND clauses", testParseQuery(`name="t1" OR name="t2" OR age=100 AND surname=t3`, &ast.Node{
   593  		NodeType: ast.NodeOr,
   594  
   595  		Left: &ast.Node{
   596  			NodeType: ast.NodeTerminal,
   597  			Comparison: ast.Comparison{
   598  				Op:     "=",
   599  				Field:  "name",
   600  				Values: "\"t1\"",
   601  			},
   602  		},
   603  		Right: &ast.Node{
   604  			NodeType: ast.NodeOr,
   605  			Left: &ast.Node{
   606  				NodeType: ast.NodeTerminal,
   607  				Comparison: ast.Comparison{
   608  					Op:     "=",
   609  					Field:  "name",
   610  					Values: "\"t2\"",
   611  				},
   612  			},
   613  			Right: &ast.Node{
   614  				NodeType: ast.NodeAnd,
   615  				Left: &ast.Node{
   616  					NodeType: ast.NodeTerminal,
   617  					Comparison: ast.Comparison{
   618  						Op:     "=",
   619  						Field:  "age",
   620  						Values: json.Number("100"),
   621  					},
   622  				},
   623  				Right: &ast.Node{
   624  					NodeType: ast.NodeTerminal,
   625  					Comparison: ast.Comparison{
   626  						Op:     "=",
   627  						Field:  "surname",
   628  						Values: "t3",
   629  					},
   630  				},
   631  			},
   632  		},
   633  	}))
   634  
   635  	t.Run(" multiple AND clauses", testParseQuery(`name="t1" AND name="t2" AND age=100 AND surname=t3`, &ast.Node{
   636  		NodeType: ast.NodeAnd,
   637  
   638  		Left: &ast.Node{
   639  			NodeType: ast.NodeTerminal,
   640  			Comparison: ast.Comparison{
   641  				Op:     "=",
   642  				Field:  "name",
   643  				Values: "\"t1\"",
   644  			},
   645  		},
   646  		Right: &ast.Node{
   647  			NodeType: ast.NodeAnd,
   648  			Left: &ast.Node{
   649  				NodeType: ast.NodeTerminal,
   650  				Comparison: ast.Comparison{
   651  					Op:     "=",
   652  					Field:  "name",
   653  					Values: "\"t2\"",
   654  				},
   655  			},
   656  			Right: &ast.Node{
   657  				NodeType: ast.NodeAnd,
   658  				Left: &ast.Node{
   659  					NodeType: ast.NodeTerminal,
   660  					Comparison: ast.Comparison{
   661  						Op:     "=",
   662  						Field:  "age",
   663  						Values: json.Number("100"),
   664  					},
   665  				},
   666  				Right: &ast.Node{
   667  					NodeType: ast.NodeTerminal,
   668  					Comparison: ast.Comparison{
   669  						Op:     "=",
   670  						Field:  "surname",
   671  						Values: "t3",
   672  					},
   673  				},
   674  			},
   675  		},
   676  	}))
   677  
   678  	t.Run("float value", testParseQuery(`avg=1.4`, &ast.Node{
   679  		NodeType: ast.NodeTerminal,
   680  		Comparison: ast.Comparison{
   681  			Op:     "=",
   682  			Field:  "avg",
   683  			Values: json.Number("1.4"),
   684  		},
   685  		Left:  nil,
   686  		Right: nil,
   687  	}))
   688  
   689  	t.Run("negative int value", testParseQuery(`total=-132`, &ast.Node{
   690  		NodeType: ast.NodeTerminal,
   691  		Comparison: ast.Comparison{
   692  			Op:     "=",
   693  			Field:  "total",
   694  			Values: json.Number("-132"),
   695  		},
   696  		Left:  nil,
   697  		Right: nil,
   698  	}))
   699  
   700  	t.Run("comparator = ", testParseQuery(`answer=42`, &ast.Node{
   701  		NodeType: ast.NodeTerminal,
   702  		Comparison: ast.Comparison{
   703  			Op:     "=",
   704  			Field:  "answer",
   705  			Values: json.Number("42"),
   706  		},
   707  		Left:  nil,
   708  		Right: nil,
   709  	}))
   710  
   711  	t.Run("comparator >", testParseQuery(`answer>42`, &ast.Node{
   712  		NodeType: ast.NodeTerminal,
   713  		Comparison: ast.Comparison{
   714  			Op:     ">",
   715  			Field:  "answer",
   716  			Values: json.Number("42"),
   717  		},
   718  		Left:  nil,
   719  		Right: nil,
   720  	}))
   721  
   722  	t.Run("comparator >=", testParseQuery(`answer>=42`, &ast.Node{
   723  		NodeType: ast.NodeTerminal,
   724  		Comparison: ast.Comparison{
   725  			Op:     ">=",
   726  			Field:  "answer",
   727  			Values: json.Number("42"),
   728  		},
   729  		Left:  nil,
   730  		Right: nil,
   731  	}))
   732  
   733  	t.Run("comparator <", testParseQuery(`answer<42`, &ast.Node{
   734  		NodeType: ast.NodeTerminal,
   735  		Comparison: ast.Comparison{
   736  			Op:     "<",
   737  			Field:  "answer",
   738  			Values: json.Number("42"),
   739  		},
   740  		Left:  nil,
   741  		Right: nil,
   742  	}))
   743  
   744  	t.Run("comparator <", testParseQuery(`answer<=42`, &ast.Node{
   745  		NodeType: ast.NodeTerminal,
   746  		Comparison: ast.Comparison{
   747  			Op:     "<=",
   748  			Field:  "answer",
   749  			Values: json.Number("42"),
   750  		},
   751  		Left:  nil,
   752  		Right: nil,
   753  	}))
   754  
   755  	t.Run("comparator <", testParseQuery(`answer!=42`, &ast.Node{
   756  		NodeType: ast.NodeTerminal,
   757  		Comparison: ast.Comparison{
   758  			Op:     "!=",
   759  			Field:  "answer",
   760  			Values: json.Number("42"),
   761  		},
   762  		Left:  nil,
   763  		Right: nil,
   764  	}))
   765  
   766  	t.Run("allow dash in field name", testParseQuery(`na-me= "t1-t2"`, &ast.Node{
   767  		NodeType: ast.NodeTerminal,
   768  		Comparison: ast.Comparison{
   769  			Op:     "=",
   770  			Field:  "na-me",
   771  			Values: "\"t1-t2\"",
   772  		},
   773  		Left:  nil,
   774  		Right: nil,
   775  	}))
   776  
   777  	t.Run("allow dash and slash in field name", testParseQuery(`na-/me= "t1/t2"`, &ast.Node{
   778  		NodeType: ast.NodeTerminal,
   779  		Comparison: ast.Comparison{
   780  			Op:     "=",
   781  			Field:  "na-/me",
   782  			Values: "\"t1/t2\"",
   783  		},
   784  		Left:  nil,
   785  		Right: nil,
   786  	}))
   787  
   788  	t.Run("free text search", testParseQuery(`"another"`, &ast.Node{
   789  		NodeType: ast.NodeTerminal,
   790  		Comparison: ast.Comparison{
   791  			Op:     "=",
   792  			Field:  "*",
   793  			Values: "\"another\"",
   794  		},
   795  		Left:  nil,
   796  		Right: nil,
   797  	}))
   798  
   799  	t.Run("search with *", testParseQuery(`*="another"`, &ast.Node{
   800  		NodeType: ast.NodeTerminal,
   801  		Comparison: ast.Comparison{
   802  			Op:     "=",
   803  			Field:  "*",
   804  			Values: "\"another\"",
   805  		},
   806  		Left:  nil,
   807  		Right: nil,
   808  	}))
   809  
   810  	t.Run("free text search AND", testParseQuery(`another AND test`, &ast.Node{
   811  		NodeType: ast.NodeAnd,
   812  		Left: &ast.Node{
   813  			NodeType: ast.NodeTerminal,
   814  			Comparison: ast.Comparison{
   815  				Op:     "=",
   816  				Field:  "*",
   817  				Values: "another",
   818  			},
   819  		},
   820  		Right: &ast.Node{
   821  			NodeType: ast.NodeTerminal,
   822  			Comparison: ast.Comparison{
   823  				Op:     "=",
   824  				Field:  "*",
   825  				Values: "test",
   826  			},
   827  		},
   828  	}))
   829  
   830  	t.Run("free text search OR", testParseQuery(`another OR test`, &ast.Node{
   831  		NodeType: ast.NodeOr,
   832  		Left: &ast.Node{
   833  			NodeType: ast.NodeTerminal,
   834  			Comparison: ast.Comparison{
   835  				Op:     "=",
   836  				Field:  "*",
   837  				Values: "another",
   838  			},
   839  		},
   840  		Right: &ast.Node{
   841  			NodeType: ast.NodeTerminal,
   842  			Comparison: ast.Comparison{
   843  				Op:     "=",
   844  				Field:  "*",
   845  				Values: "test",
   846  			},
   847  		},
   848  	}))
   849  
   850  	t.Run("free text search OR / AND clauses with paren precedence variation", testParseQuery(`"t2" OR ("t1" AND t3) `, &ast.Node{
   851  		NodeType: ast.NodeOr,
   852  		Left: &ast.Node{
   853  			NodeType: ast.NodeTerminal,
   854  			Comparison: ast.Comparison{
   855  				Op:     "=",
   856  				Field:  "*",
   857  				Values: "\"t2\"",
   858  			},
   859  		},
   860  		Right: &ast.Node{
   861  			NodeType: ast.NodeAnd,
   862  			Left: &ast.Node{
   863  				NodeType: ast.NodeTerminal,
   864  				Comparison: ast.Comparison{
   865  					Op:     "=",
   866  					Field:  "*",
   867  					Values: "\"t1\"",
   868  				},
   869  			},
   870  			Right: &ast.Node{
   871  				NodeType: ast.NodeTerminal,
   872  				Comparison: ast.Comparison{
   873  					Op:     "=",
   874  					Field:  "*",
   875  					Values: "t3",
   876  				},
   877  			},
   878  		},
   879  	}))
   880  
   881  	t.Run("free text search OR / AND clauses with paren precedence variation", testParseQuery(`"t2" AND ("t1" OR t3)  `, &ast.Node{
   882  		NodeType: ast.NodeAnd,
   883  		Left: &ast.Node{
   884  			NodeType: ast.NodeTerminal,
   885  			Comparison: ast.Comparison{
   886  				Op:     "=",
   887  				Field:  "*",
   888  				Values: "\"t2\"",
   889  			},
   890  		},
   891  		Right: &ast.Node{
   892  			NodeType: ast.NodeOr,
   893  			Left: &ast.Node{
   894  				NodeType: ast.NodeTerminal,
   895  				Comparison: ast.Comparison{
   896  					Op:     "=",
   897  					Field:  "*",
   898  					Values: "\"t1\"",
   899  				},
   900  			},
   901  			Right: &ast.Node{
   902  				NodeType: ast.NodeTerminal,
   903  				Comparison: ast.Comparison{
   904  					Op:     "=",
   905  					Field:  "*",
   906  					Values: "t3",
   907  				},
   908  			},
   909  		},
   910  	}))
   911  
   912  	t.Run("free text search - OR / AND clauses with paren precedence", testParseQuery(`("t1" AND t2) OR name="t3"`, &ast.Node{
   913  		NodeType: ast.NodeOr,
   914  		Left: &ast.Node{
   915  			NodeType: ast.NodeAnd,
   916  			Left: &ast.Node{
   917  				NodeType: ast.NodeTerminal,
   918  				Comparison: ast.Comparison{
   919  					Op:     "=",
   920  					Field:  "*",
   921  					Values: "\"t1\"",
   922  				},
   923  			},
   924  			Right: &ast.Node{
   925  				NodeType: ast.NodeTerminal,
   926  				Comparison: ast.Comparison{
   927  					Op:     "=",
   928  					Field:  "*",
   929  					Values: "t2",
   930  				},
   931  			},
   932  		},
   933  		Right: &ast.Node{
   934  			NodeType: ast.NodeTerminal,
   935  			Comparison: ast.Comparison{
   936  				Op:     "=",
   937  				Field:  "name",
   938  				Values: "\"t3\"",
   939  			},
   940  		},
   941  	}))
   942  
   943  	t.Run("wildcard - simple minimal condition", testParseQuery(`something="another*"`, &ast.Node{
   944  		NodeType: ast.NodeTerminal,
   945  		Comparison: ast.Comparison{
   946  			Op:     "=",
   947  			Field:  "something",
   948  			Values: "\"another*\"",
   949  		},
   950  		Left:  nil,
   951  		Right: nil,
   952  	}))
   953  
   954  	t.Run("wildcard - simple minimal condition", testParseQuery(`"another*"`, &ast.Node{
   955  		NodeType: ast.NodeTerminal,
   956  		Comparison: ast.Comparison{
   957  			Op:     "=",
   958  			Field:  "*",
   959  			Values: "\"another*\"",
   960  		},
   961  		Left:  nil,
   962  		Right: nil,
   963  	}))
   964  
   965  	t.Run("wildcard - simple minimal condition-no quotes", testParseQuery(`another*`, &ast.Node{
   966  		NodeType: ast.NodeTerminal,
   967  		Comparison: ast.Comparison{
   968  			Op:     "=",
   969  			Field:  "*",
   970  			Values: "another*",
   971  		},
   972  		Left:  nil,
   973  		Right: nil,
   974  	}))
   975  
   976  	t.Run("wildcard - simple minimal condition-no quotes", testParseQuery(`another* AND test*`, &ast.Node{
   977  		NodeType: ast.NodeAnd,
   978  		Left: &ast.Node{
   979  			NodeType: ast.NodeTerminal,
   980  			Comparison: ast.Comparison{
   981  				Op:     "=",
   982  				Field:  "*",
   983  				Values: "another*",
   984  			},
   985  		},
   986  		Right: &ast.Node{
   987  			NodeType: ast.NodeTerminal,
   988  			Comparison: ast.Comparison{
   989  				Op:     "=",
   990  				Field:  "*",
   991  				Values: "test*",
   992  			},
   993  		},
   994  	}))
   995  
   996  	t.Run("wildcard - simple minimal condition-no quotes", testParseQuery(`another* OR test*`, &ast.Node{
   997  		NodeType: ast.NodeOr,
   998  		Left: &ast.Node{
   999  			NodeType: ast.NodeTerminal,
  1000  			Comparison: ast.Comparison{
  1001  				Op:     "=",
  1002  				Field:  "*",
  1003  				Values: "another*",
  1004  			},
  1005  		},
  1006  		Right: &ast.Node{
  1007  			NodeType: ast.NodeTerminal,
  1008  			Comparison: ast.Comparison{
  1009  				Op:     "=",
  1010  				Field:  "*",
  1011  				Values: "test*",
  1012  			},
  1013  		},
  1014  	}))
  1015  
  1016  	t.Run("column complex value condition", testParseQuery(`something="phrase-with-special-characters"`, &ast.Node{
  1017  		NodeType: ast.NodeTerminal,
  1018  		Comparison: ast.Comparison{
  1019  			Op:     "=",
  1020  			Field:  "something",
  1021  			Values: "\"phrase-with-special-characters\"",
  1022  		},
  1023  		Left:  nil,
  1024  		Right: nil,
  1025  	}))
  1026  
  1027  	t.Run("column multi word condition", testParseQuery(`something="phrase with multiple words"`, &ast.Node{
  1028  		NodeType: ast.NodeTerminal,
  1029  		Comparison: ast.Comparison{
  1030  			Op:     "=",
  1031  			Field:  "something",
  1032  			Values: "\"phrase with multiple words\"",
  1033  		},
  1034  		Left:  nil,
  1035  		Right: nil,
  1036  	}))
  1037  
  1038  	t.Run("special characters", testParseQuery(`something=AppleWebKit/532.47.1KHTML,likeGecko`, &ast.Node{
  1039  		NodeType: ast.NodeTerminal,
  1040  		Comparison: ast.Comparison{
  1041  			Op:     "=",
  1042  			Field:  "something",
  1043  			Values: "AppleWebKit/532.47.1KHTML,likeGecko",
  1044  		},
  1045  		Left:  nil,
  1046  		Right: nil,
  1047  	}))
  1048  
  1049  	t.Run("special characters free text", testParseQuery(`https://peterson.info/`, &ast.Node{
  1050  		NodeType: ast.NodeTerminal,
  1051  		Comparison: ast.Comparison{
  1052  			Op:     "=",
  1053  			Field:  "*",
  1054  			Values: "https://peterson.info/",
  1055  		},
  1056  		Left:  nil,
  1057  		Right: nil,
  1058  	}))
  1059  }
  1060  
  1061  func TestAST_simpleAnd_CommandsAgg(t *testing.T) {
  1062  	json_body := []byte(`name="t1" AND surname="t2" | columns name`)
  1063  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1064  	assert.Nil(t, err)
  1065  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1066  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 2)
  1067  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
  1068  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1")
  1069  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1070  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "surname")
  1071  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2")
  1072  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
  1073  	assert.NotNil(t, aggNode.OutputTransforms)
  1074  	assert.Len(t, aggNode.OutputTransforms.OutputColumns.IncludeColumns, 1)
  1075  	assert.Equal(t, aggNode.OutputTransforms.OutputColumns.IncludeColumns[0], "name")
  1076  }
  1077  
  1078  func TestAST_blankSearchFilter_CommandsAgg(t *testing.T) {
  1079  	json_body := []byte(`| columns name`)
  1080  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1081  	assert.Nil(t, err)
  1082  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1083  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
  1084  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
  1085  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "*")
  1086  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1087  	assert.NotNil(t, aggNode.OutputTransforms)
  1088  	assert.Len(t, aggNode.OutputTransforms.OutputColumns.IncludeColumns, 1)
  1089  	assert.Equal(t, aggNode.OutputTransforms.OutputColumns.IncludeColumns[0], "name")
  1090  }
  1091  
  1092  func TestAST_blankSearchFilter_ColumnAgg_List(t *testing.T) {
  1093  	json_body := []byte(`| columns name,test`)
  1094  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1095  	assert.Nil(t, err)
  1096  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1097  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
  1098  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
  1099  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "*")
  1100  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1101  	assert.NotNil(t, aggNode)
  1102  	assert.NotNil(t, aggNode.OutputTransforms)
  1103  	assert.Len(t, aggNode.OutputTransforms.OutputColumns.IncludeColumns, 2)
  1104  	assert.Equal(t, aggNode.OutputTransforms.OutputColumns.IncludeColumns[0], "name")
  1105  	assert.Equal(t, aggNode.OutputTransforms.OutputColumns.IncludeColumns[1], "test")
  1106  }
  1107  
  1108  func TestAST_simpleAnd_SegLevelStats(t *testing.T) {
  1109  	json_body := []byte(`name="t1" AND surname="t2" | min(latency)`)
  1110  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1111  	assert.Nil(t, err)
  1112  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1113  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 2)
  1114  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
  1115  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1")
  1116  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1117  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "surname")
  1118  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2")
  1119  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
  1120  	assert.NotNil(t, aggNode)
  1121  	assert.NotNil(t, aggNode.MeasureOperations)
  1122  	assert.Equal(t, aggNode.MeasureOperations[0].MeasureCol, "latency")
  1123  	assert.Equal(t, aggNode.MeasureOperations[0].MeasureFunc, utils.Min)
  1124  }
  1125  
  1126  func TestAST_blankSearchFilter_SegLevelStats(t *testing.T) {
  1127  	json_body := []byte(`| max(cnt)`)
  1128  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1129  	assert.Nil(t, err)
  1130  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1131  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
  1132  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
  1133  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "*")
  1134  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1135  	assert.NotNil(t, aggNode)
  1136  	assert.NotNil(t, aggNode.MeasureOperations)
  1137  	assert.Equal(t, aggNode.MeasureOperations[0].MeasureCol, "cnt")
  1138  	assert.Equal(t, aggNode.MeasureOperations[0].MeasureFunc, utils.Max)
  1139  }
  1140  
  1141  func TestAST_blankSearchFilter_ColumnAgg_ExcludeList(t *testing.T) {
  1142  	json_body := []byte(`| columns - name,test`)
  1143  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1144  	assert.Nil(t, err)
  1145  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1146  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
  1147  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
  1148  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "*")
  1149  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1150  	assert.NotNil(t, aggNode)
  1151  	assert.NotNil(t, aggNode.OutputTransforms)
  1152  	assert.Len(t, aggNode.OutputTransforms.OutputColumns.ExcludeColumns, 2)
  1153  	assert.Equal(t, aggNode.OutputTransforms.OutputColumns.ExcludeColumns[0], "name")
  1154  	assert.Equal(t, aggNode.OutputTransforms.OutputColumns.ExcludeColumns[1], "test")
  1155  }
  1156  
  1157  func TestAST_simpleAnd_ColumnAgg_Rename(t *testing.T) {
  1158  	json_body := []byte(`name="t1" AND surname="t2" | columns newname = name`)
  1159  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1160  	assert.Nil(t, err)
  1161  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1162  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 2)
  1163  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
  1164  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1")
  1165  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1166  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "surname")
  1167  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2")
  1168  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
  1169  	assert.NotNil(t, aggNode.OutputTransforms)
  1170  	assert.Len(t, aggNode.OutputTransforms.OutputColumns.RenameColumns, 1)
  1171  	assert.Equal(t, aggNode.OutputTransforms.OutputColumns.RenameColumns["name"], "newname")
  1172  }
  1173  
  1174  func TestAST_simpleAnd_LetAgg_Single(t *testing.T) {
  1175  	json_body := []byte(`name="t1" AND surname="t2" | let isError=(status >= 399)`)
  1176  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1177  	assert.Nil(t, err)
  1178  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1179  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 2)
  1180  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
  1181  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1")
  1182  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1183  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "surname")
  1184  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2")
  1185  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
  1186  	assert.NotNil(t, aggNode.OutputTransforms)
  1187  	assert.NotNil(t, aggNode.OutputTransforms.LetColumns)
  1188  	assert.Equal(t, aggNode.OutputTransforms.LetColumns.NewColName, "isError")
  1189  	assert.NotNil(t, aggNode.OutputTransforms.LetColumns.SingleColRequest)
  1190  	assert.Equal(t, aggNode.OutputTransforms.LetColumns.SingleColRequest.CName, "status")
  1191  	assert.Equal(t, aggNode.OutputTransforms.LetColumns.SingleColRequest.Oper, utils.LogicalAndArithmeticOperator(10))
  1192  	assert.Equal(t, aggNode.OutputTransforms.LetColumns.SingleColRequest.Value.UnsignedVal, uint64(399))
  1193  
  1194  }
  1195  
  1196  func TestAST_simpleAnd_seglevelStats_commaSeparated(t *testing.T) {
  1197  	json_body := []byte(`name="t1" AND surname="t2" | min(latency),max(latency)`)
  1198  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1199  	assert.Nil(t, err)
  1200  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1201  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 2)
  1202  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "name")
  1203  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t1")
  1204  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1205  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "surname")
  1206  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "t2")
  1207  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[1].ExpressionFilter.FilterOperator, Equals)
  1208  	assert.NotNil(t, aggNode.MeasureOperations)
  1209  	assert.Equal(t, aggNode.MeasureOperations[0].MeasureCol, "latency")
  1210  	assert.Equal(t, aggNode.MeasureOperations[0].MeasureFunc, utils.Min)
  1211  	assert.Equal(t, aggNode.MeasureOperations[1].MeasureCol, "latency")
  1212  	assert.Equal(t, aggNode.MeasureOperations[1].MeasureFunc, utils.Max)
  1213  }
  1214  
  1215  func TestAST_GroupByseglevelStats_commaSeparated(t *testing.T) {
  1216  	json_body := []byte(` min(latency),max(latency) groupby region`)
  1217  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1218  	assert.Nil(t, err)
  1219  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1220  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
  1221  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
  1222  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "*")
  1223  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1224  	assert.NotNil(t, aggNode.GroupByRequest)
  1225  	assert.NotNil(t, aggNode.GroupByRequest.MeasureOperations)
  1226  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[0].MeasureCol, "latency")
  1227  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[0].MeasureFunc, utils.Min)
  1228  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[1].MeasureCol, "latency")
  1229  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[1].MeasureFunc, utils.Max)
  1230  	assert.NotNil(t, aggNode.GroupByRequest.GroupByColumns)
  1231  	assert.Equal(t, aggNode.GroupByRequest.GroupByColumns[0], "region")
  1232  }
  1233  
  1234  func TestAST_GroupByseglevelStats_commaSeparated_multipleGroups(t *testing.T) {
  1235  	json_body := []byte(` min(latency),max(latency) groupby region,os_name`)
  1236  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1237  	assert.Nil(t, err)
  1238  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1239  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
  1240  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
  1241  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "*")
  1242  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1243  	assert.NotNil(t, aggNode.GroupByRequest)
  1244  	assert.NotNil(t, aggNode.GroupByRequest.MeasureOperations)
  1245  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[0].MeasureCol, "latency")
  1246  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[0].MeasureFunc, utils.Min)
  1247  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[1].MeasureCol, "latency")
  1248  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[1].MeasureFunc, utils.Max)
  1249  	assert.NotNil(t, aggNode.GroupByRequest.GroupByColumns)
  1250  	assert.Equal(t, aggNode.GroupByRequest.GroupByColumns[0], "region")
  1251  	assert.Equal(t, aggNode.GroupByRequest.GroupByColumns[1], "os_name")
  1252  }
  1253  
  1254  func TestAST_GroupByseglevelStats_commaSeparated_multipleGroups_withPipe(t *testing.T) {
  1255  	json_body := []byte(`| min(latency),max(latency) groupby region,os_name`)
  1256  	res, aggNode, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1257  	assert.Nil(t, err)
  1258  	assert.NotNil(t, res.AndFilterCondition.FilterCriteria)
  1259  	assert.Len(t, res.AndFilterCondition.FilterCriteria, 1)
  1260  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.LeftInput.Expression.LeftInput.ColumnName, "*")
  1261  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.RightInput.Expression.LeftInput.ColumnValue.StringVal, "*")
  1262  	assert.Equal(t, res.AndFilterCondition.FilterCriteria[0].ExpressionFilter.FilterOperator, Equals)
  1263  	assert.NotNil(t, aggNode.GroupByRequest)
  1264  	assert.NotNil(t, aggNode.GroupByRequest.MeasureOperations)
  1265  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[0].MeasureCol, "latency")
  1266  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[0].MeasureFunc, utils.Min)
  1267  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[1].MeasureCol, "latency")
  1268  	assert.Equal(t, aggNode.GroupByRequest.MeasureOperations[1].MeasureFunc, utils.Max)
  1269  	assert.NotNil(t, aggNode.GroupByRequest.GroupByColumns)
  1270  	assert.Equal(t, aggNode.GroupByRequest.GroupByColumns[0], "region")
  1271  	assert.Equal(t, aggNode.GroupByRequest.GroupByColumns[1], "os_name")
  1272  }
  1273  
  1274  func TestAST_invalidSearch_SegLevelStats(t *testing.T) {
  1275  	json_body := []byte(`| max(cnt).`)
  1276  	res, _, err := parsePipeSearch(string(json_body), "Pipe QL", 1)
  1277  	assert.NotNil(t, err)
  1278  	assert.Nil(t, res)
  1279  }