@@ -102,19 +102,21 @@ func TestConvertAST_Success(t *testing.T) {
102102%6 = OR %4 %5
103103%7 = MATCH_STR builtin.message "metric.go"
104104%8 = MATCH_STR builtin.message "foo"
105- %9 = AND %7 %8
106- %10 = NOT_MATCH_RE builtin.message "(a|b|c)"
107- %11 = AND %9 %10
108- %12 = MAKETABLE [selector=%3, predicates=[%6, %11], shard=0_of_1]
109- %13 = GTE builtin.timestamp 1970-01-01T01:00:00Z
110- %14 = SELECT %12 [predicate=%13 ]
111- %15 = LT builtin.timestamp 1970-01-01T02 :00:00Z
105+ %9 = MATCH_STR builtin.message "bar"
106+ %10 = OR %8 %9
107+ %11 = AND %7 %10
108+ %12 = NOT_MATCH_RE builtin.message "(a|b|c)"
109+ %13 = AND %11 %12
110+ %14 = MAKETABLE [selector=%3, predicates=[%6, %13], shard=0_of_1 ]
111+ %15 = GTE builtin.timestamp 1970-01-01T01 :00:00Z
112112%16 = SELECT %14 [predicate=%15]
113- %17 = SELECT %16 [predicate=%6]
114- %18 = SELECT %17 [predicate=%11]
115- %19 = TOPK %18 [sort_by=builtin.timestamp, k=1000, asc=false, nulls_first=false]
116- %20 = LOGQL_COMPAT %19
117- RETURN %20
113+ %17 = LT builtin.timestamp 1970-01-01T02:00:00Z
114+ %18 = SELECT %16 [predicate=%17]
115+ %19 = SELECT %18 [predicate=%6]
116+ %20 = SELECT %19 [predicate=%13]
117+ %21 = TOPK %20 [sort_by=builtin.timestamp, k=1000, asc=false, nulls_first=false]
118+ %22 = LOGQL_COMPAT %21
119+ RETURN %22
118120`
119121
120122 require .Equal (t , expected , logicalPlan .String ())
@@ -125,6 +127,84 @@ RETURN %20
125127 t .Logf ("\n %s\n " , sb .String ())
126128}
127129
130+ func TestConvertAST_LineFilterOr (t * testing.T ) {
131+ tests := []struct {
132+ name string
133+ query string
134+ contains []string
135+ }{
136+ {
137+ name : "simple or" ,
138+ query : `{app="loki"} |= "foo" or "bar"` ,
139+ contains : []string {
140+ `MATCH_STR builtin.message "foo"` ,
141+ `MATCH_STR builtin.message "bar"` ,
142+ "OR %" ,
143+ },
144+ },
145+ {
146+ name : "or with regex" ,
147+ query : `{app="loki"} |~ "(?i)abc" or "(?i)def"` ,
148+ contains : []string {
149+ `MATCH_RE builtin.message "(?i)abc"` ,
150+ `MATCH_RE builtin.message "(?i)def"` ,
151+ "OR %" ,
152+ },
153+ },
154+ {
155+ name : "three-way or" ,
156+ query : `{app="loki"} |= "a" or "b" or "c"` ,
157+ contains : []string {
158+ `MATCH_STR builtin.message "a"` ,
159+ `MATCH_STR builtin.message "b"` ,
160+ `MATCH_STR builtin.message "c"` ,
161+ "OR %" ,
162+ },
163+ },
164+ {
165+ name : "or preceded by and" ,
166+ query : `{app="loki"} |= "first" |= "foo" or "bar"` ,
167+ contains : []string {
168+ `MATCH_STR builtin.message "first"` ,
169+ `MATCH_STR builtin.message "foo"` ,
170+ `MATCH_STR builtin.message "bar"` ,
171+ "OR %" ,
172+ "AND %" ,
173+ },
174+ },
175+ {
176+ name : "negative filter or becomes and" ,
177+ query : `{app="loki"} != "foo" or "bar"` ,
178+ contains : []string {
179+ `NOT_MATCH_STR builtin.message "foo"` ,
180+ `NOT_MATCH_STR builtin.message "bar"` ,
181+ "AND %" ,
182+ },
183+ },
184+ }
185+
186+ for _ , tc := range tests {
187+ t .Run (tc .name , func (t * testing.T ) {
188+ q := & query {
189+ statement : tc .query ,
190+ start : 3600 ,
191+ end : 7200 ,
192+ direction : logproto .BACKWARD ,
193+ limit : 1000 ,
194+ }
195+ plan , err := BuildPlan (context .Background (), q )
196+ require .NoError (t , err )
197+
198+ planStr := plan .String ()
199+ t .Logf ("\n %s\n " , planStr )
200+
201+ for _ , substr := range tc .contains {
202+ require .Contains (t , planStr , substr , "plan should contain %q" , substr )
203+ }
204+ })
205+ }
206+ }
207+
128208func TestConvertAST_MetricQuery_Success (t * testing.T ) {
129209 t .Run ("simple metric query" , func (t * testing.T ) {
130210 q := & query {
0 commit comments